Debug CORS: send the real preflight, get Chrome's exact error and the headers that fix it.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Use when the user hits a CORS error ("blocked by CORS policy", "No 'Access-Control-Allow-Origin' header", "preflight", "Failed to fetch" from a frontend) or is about to call a public API from browser code (React, Next.js, Vue, a browser extension page) and asks whether it will work (signals: "CORS", "works in Postman but not in the browser", "preflight 401/404", "Access-Control-Allow-Headers", "withCredentials", "credentials include"). Sends the browser's own preflight (OPTIONS with Origin, Access-Control-Request-Method and -Headers) to the live API and, for GET and HEAD, the request itself with the Origin header, then applies the Fetch standard CORS rules as Chrome implements them. Returns verdict (allowed, blocked, preflight_passed, incomplete, same_origin, unreachable), the exact Chrome console error, which step fails (preflight or response) and why, whether a preflight is needed and why, the CORS headers the server sent, warnings (missing Vary: Origin, a server that echoes any origin with credentials, unreadable response headers, Authorization covered only by *), the exact response headers that fix it, and curl commands to reproduce. Example: {"url":"https://api.example.com/v1/items","origin":"http://localhost:3000","method":"POST","headers":["Content-Type: application/json","Authorization"],"credentials":true}. Limits: public http/https APIs on ports 80 and 443 only (localhost, private and staging servers go through border_check_cors_headers with pasted curl output); never sends POST, PUT, PATCH or DELETE (those get the preflight checked only) and never sends header values for Authorization or keys; a server can answer differently to a real browser session.
The API address the page calls, for example "https://api.example.com/v1/items".
The origin of the page that makes the request: scheme, host and port, for example "https://app.example.com" or "http://localhost:5173". A full page URL is reduced to its origin.
HTTP method the page uses (default GET), for example "POST", "PUT", "PATCH" or "DELETE".
Request headers the page sets in fetch() or axios, as "Name" or "Name: value". Values matter only for Content-Type, Accept, Accept-Language, Content-Language and Range; give names alone for Authorization and API keys. Example: ["Content-Type: application/json","Authorization"].
true when the request sends cookies: fetch credentials: "include", XHR or axios withCredentials: true. Default false.
Response headers the page code reads with response.headers.get(), for example ["X-Total-Count","ETag"]. Checked against Access-Control-Expose-Headers.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http border https://border.clawhard.com/mcp
Use when the user hits a CORS error ("blocked by CORS policy", "No 'Access-Control-Allow-Origin' header", "preflight", "Failed to fetch" from a frontend) or is about to call a public API from browser code (React, Next.js, Vue, a browser extension page) and asks whether it will work (signals: "CORS", "works in Postman but not in the browser", "preflight 401/404", "Access-Control-Allow-Headers", "withCredentials", "credentials include"). Sends the browser's own preflight (OPTIONS with Origin, Access-Control-Request-Method and -Headers) to the live API and, for GET and HEAD, the request itself with the Origin header, then applies the Fetch standard CORS rules as Chrome implements them. Returns verdict (allowed, blocked, preflight_passed, incomplete, same_origin, unreachable), the exact Chrome console error, which step fails (preflight or response) and why, whether a preflight is needed and why, the CORS headers the server sent, warnings (missing Vary: Origin, a server that echoes any origin with credentials, unreadable response headers, Authorization covered only by *), the exact response headers that fix it, and curl commands to reproduce. Example: {"url":"https://api.example.com/v1/items","origin":"http://localhost:3000","method":"POST","headers":["Content-Type: application/json","Authorization"],"credentials":true}. Limits: public http/https APIs on ports 80 and 443 only (localhost, private and staging servers go through border_check_cors_headers with pasted curl output); never sends POST, PUT, PATCH or DELETE (those get the preflight checked only) and never sends header values for Authorization or keys; a server can answer differently to a real browser session.
| Argument | Type | Description |
|---|---|---|
| url* | string | The API address the page calls, for example "https://api.example.com/v1/items". |
| method | string | HTTP method the page uses (default GET), for example "POST", "PUT", "PATCH" or "DELETE". |
| origin* | string | The origin of the page that makes the request: scheme, host and port, for example "https://app.example.com" or "http://localhost:5173". A full page URL is reduced to its origin. |
| headers | array | Request headers the page sets in fetch() or axios, as "Name" or "Name: value". Values matter only for Content-Type, Accept, Accept-Language, Content-Language and Range; give names alone for Authorization and API keys. Example: ["Content-Type: application/json","Authorization"]. |
| credentials | boolean | true when the request sends cookies: fetch credentials: "include", XHR or axios withCredentials: true. Default false. |
| read_headers | array | Response headers the page code reads with response.headers.get(), for example ["X-Total-Count","ETag"]. Checked against Access-Control-Expose-Headers. |
{
"type": "object",
"required": [
"url",
"origin"
],
"properties": {
"url": {
"type": "string",
"maxLength": 2000,
"minLength": 4,
"description": "The API address the page calls, for example \"https://api.example.com/v1/items\"."
},
"method": {
"type": "string",
"maxLength": 20,
"minLength": 3,
"description": "HTTP method the page uses (default GET), for example \"POST\", \"PUT\", \"PATCH\" or \"DELETE\"."
},
"origin": {
"type": "string",
"maxLength": 300,
"minLength": 4,
"description": "The origin of the page that makes the request: scheme, host and port, for example \"https://app.example.com\" or \"http://localhost:5173\". A full page URL is reduced to its origin."
},
"headers": {
"type": "array",
"items": {
"type": "string",
"maxLength": 300,
"minLength": 1
},
"maxItems": 30,
"description": "Request headers the page sets in fetch() or axios, as \"Name\" or \"Name: value\". Values matter only for Content-Type, Accept, Accept-Language, Content-Language and Range; give names alone for Authorization and API keys. Example: [\"Content-Type: application/json\",\"Authorization\"]."
},
"credentials": {
"type": "boolean",
"description": "true when the request sends cookies: fetch credentials: \"include\", XHR or axios withCredentials: true. Default false."
},
"read_headers": {
"type": "array",
"items": {
"type": "string",
"maxLength": 100,
"minLength": 1
},
"maxItems": 30,
"description": "Response headers the page code reads with response.headers.get(), for example [\"X-Total-Count\",\"ETag\"]. Checked against Access-Control-Expose-Headers."
}
}
}Use when a CORS problem involves a server Border cannot reach (localhost, a dev or staging server, a private network, a custom port) or a POST, PUT, PATCH or DELETE whose real response needs checking, and the raw response headers are available from curl -i or the browser DevTools Network tab (signals: "here is the OPTIONS response", "my local API returns these headers", "CORS works on localhost but not in production", "preflight response is"). Parses the pasted OPTIONS response and/or the actual response (status line plus headers; curl -i, curl -v, curl -iL with redirects, and DevTools copies are all read) and applies the Fetch standard CORS rules as Chrome implements them, for the given page origin, method, request headers and credentials mode. Returns the same result as border_check_cors: verdict, the exact Chrome console error, the failing step and reason, warnings, the response headers that fix it, and the curl commands to capture any missing response. Nothing is fetched. Example: {"url":"http://localhost:8000/api/login","origin":"http://localhost:5173","method":"POST","headers":["Content-Type: application/json"],"credentials":true,"preflight_response":"HTTP/1.1 200 OK\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: content-type"}. Limits: the verdict is only as complete as the pasted headers; a preflighted request needs both pastes for a full answer.
| Argument | Type | Description |
|---|---|---|
| url* | string | The API address the page calls, for example "https://api.example.com/v1/items". |
| method | string | HTTP method the page uses (default GET), for example "POST", "PUT", "PATCH" or "DELETE". |
| origin* | string | The origin of the page that makes the request: scheme, host and port, for example "https://app.example.com" or "http://localhost:5173". A full page URL is reduced to its origin. |
We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 12, 2026.
| headers | array | Request headers the page sets in fetch() or axios, as "Name" or "Name: value". Values matter only for Content-Type, Accept, Accept-Language, Content-Language and Range; give names alone for Authorization and API keys. Example: ["Content-Type: application/json","Authorization"]. |
| response | string | The raw response to the actual request: status line and headers from curl -i (curl -iL output with redirects is read hop by hop) or DevTools. Bodies are ignored. |
| credentials | boolean | true when the request sends cookies: fetch credentials: "include", XHR or axios withCredentials: true. Default false. |
| read_headers | array | Response headers the page code reads with response.headers.get(), for example ["X-Total-Count","ETag"]. Checked against Access-Control-Expose-Headers. |
| preflight_response | string | The raw OPTIONS (preflight) response: status line and headers, as printed by curl -i -X OPTIONS (see the curl.preflight command in any result) or copied from DevTools. |
{
"type": "object",
"required": [
"url",
"origin"
],
"properties": {
"url": {
"type": "string",
"maxLength": 2000,
"minLength": 4,
"description": "The API address the page calls, for example \"https://api.example.com/v1/items\"."
},
"method": {
"type": "string",
"maxLength": 20,
"minLength": 3,
"description": "HTTP method the page uses (default GET), for example \"POST\", \"PUT\", \"PATCH\" or \"DELETE\"."
},
"origin": {
"type": "string",
"maxLength": 300,
"minLength": 4,
"description": "The origin of the page that makes the request: scheme, host and port, for example \"https://app.example.com\" or \"http://localhost:5173\". A full page URL is reduced to its origin."
},
"headers": {
"type": "array",
"items": {
"type": "string",
"maxLength": 300,
"minLength": 1
},
"maxItems": 30,
"description": "Request headers the page sets in fetch() or axios, as \"Name\" or \"Name: value\". Values matter only for Content-Type, Accept, Accept-Language, Content-Language and Range; give names alone for Authorization and API keys. Example: [\"Content-Type: application/json\",\"Authorization\"]."
},
"response": {
"type": "string",
"maxLength": 20000,
"minLength": 1,
"description": "The raw response to the actual request: status line and headers from curl -i (curl -iL output with redirects is read hop by hop) or DevTools. Bodies are ignored."
},
"credentials": {
"type": "boolean",
"description": "true when the request sends cookies: fetch credentials: \"include\", XHR or axios withCredentials: true. Default false."
},
"read_headers": {
"type": "array",
"items": {
"type": "string",
"maxLength": 100,
"minLength": 1
},
"maxItems": 30,
"description": "Response headers the page code reads with response.headers.get(), for example [\"X-Total-Count\",\"ETag\"]. Checked against Access-Control-Expose-Headers."
},
"preflight_response": {
"type": "string",
"maxLength": 20000,
"minLength": 1,
"description": "The raw OPTIONS (preflight) response: status line and headers, as printed by curl -i -X OPTIONS (see the curl.preflight command in any result) or copied from DevTools."
}
}
}