Origin Validation
DNS rebinding protection, on by default.
A local MCP server is reachable from any web page the user visits: the page cannot read cross-origin responses, but it can send requests, and DNS rebinding can make localhost look same-origin. Checking Origin is the cheap defense, so it is enabled by default.
The default policy is:
- A request with an
Originheader is denied unless the origin is allowlisted →403. - A request without an
Originheader is allowed (allowMissing: true) — that is how non-browser clients and CLIs call you.
defineMcpHandler({
name: "my-server",
version: "1.0.0",
origin: {
allow: ["https://app.example.com", "http://localhost:3000"],
allowMissing: true, // default
},
tools: [/* ... */],
});Allowlist entries are normalized (and rejected at startup if malformed), so https://app.example.com/ and https://APP.example.com match the same origin. Origin: null — from sandboxed iframes and some file:// contexts — is treated as the literal origin "null", so you must allowlist it explicitly to accept it.
#Custom Validation
For wildcards or a dynamic allowlist:
defineMcpHandler({
name: "my-server",
version: "1.0.0",
origin: {
validate: (origin, event) => origin.endsWith(".example.com"),
},
tools: [/* ... */],
});validate runs only when allow did not already match. Match on the end of the host with a leading dot, as above — origin.includes("example.com") would accept https://example.com.attacker.net.
#Requiring an Origin
Set allowMissing: false when every legitimate client is a browser. Requests without the header are then 403 too:
origin: { allow: ["https://app.example.com"], allowMissing: false }#Disabling
defineMcpHandler({
name: "my-server",
version: "1.0.0",
origin: false,
tools: [/* ... */],
});Warning
Only disable origin checks when something in front of you already does them, or when the endpoint is unreachable from a browser. For a server bound to 127.0.0.1, this check is the main thing standing between a visited web page and your tools.
Origin validation applies to every HTTP method the endpoint serves — POST, GET, and DELETE — and runs before auth, body limits, and parsing.