
# 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 `Origin` header is denied unless the origin is allowlisted → `403`.
- A request **without** an `Origin` header is allowed (`allowMissing: true`) — that is how non-browser clients and CLIs call you.

```ts
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:

```ts
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:

```ts
origin: { allow: ["https://app.example.com"], allowMissing: false }
```

## Disabling

```ts
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.
