Skip to content

feat: add --corsAddAllowedHeader CLI flag#64

Merged
punkpeye merged 1 commit into
punkpeye:mainfrom
DmitriyAlergant:feat/cors-cli-flags
May 12, 2026
Merged

feat: add --corsAddAllowedHeader CLI flag#64
punkpeye merged 1 commit into
punkpeye:mainfrom
DmitriyAlergant:feat/cors-cli-flags

Conversation

@DmitriyAlergant
Copy link
Copy Markdown

@DmitriyAlergant DmitriyAlergant commented Apr 29, 2026

Summary

Adds a single --corsAddAllowedHeader CLI flag that appends header names to Access-Control-Allow-Headers (defaults preserved). Repeatable.

Motivation

When mcp-proxy is started with --apiKey, the proxy expects the secret in the X-API-Key header.

Browser-based apps (e.g. chat UIs) that support frontend-fetched streamable HTTP MCPs issue a CORS preflight for that header, and because X-API-Key is not in the default Access-Control-Allow-Headers list, the preflight is rejected. The --apiKey gate is therefore unreachable from a browser-hosted client.

The library already exposes a programmatic cors.allowedHeaders option that solves this, but it requires users to abandon the npx mcp-proxy ... one-liner and write a small Node wrapper. The README's "Common Use Cases" section explicitly calls this out as a known browser CORS friction point.

What this changes

  • New CLI flag --corsAddAllowedHeader <name> (yargs array: true, repeatable). Internally builds cors: { allowedHeaders: [...defaults, ...added] } and passes it to startHTTPServer.
  • Defaults are preserved by hard-coding the default list in the CLI; a comment notes the source of truth in src/startHTTPServer.ts.
  • Behavior is opt-in

Example

```bash
npx mcp-proxy --port 8080 --apiKey secret \
--corsAddAllowedHeader X-API-Key \
-- npx -y @modelcontextprotocol/server-filesystem /srv
```

Test plan

  • `pnpm test` (vitest + tsc + eslint + jsr dry-run) — 87 passing, no new failures. Existing CORS tests in `startHTTPServer.test.ts` already cover the `allowedHeaders: string[]` code path used here, so no new test file was added.
  • `pnpm build` — clean.
  • Manual: `OPTIONS http://127.0.0.1:8080/mcp\` with `Access-Control-Request-Headers: x-api-key, content-type` returns `Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-Id, X-API-Key`, and an end-to-end browser MCP client (`proxyMode=frontend`) successfully authenticates with `--apiKey`.

Notes

Perhaps we should also make this a default (always accept X-API-Key when --apiKey is given), but not sure the maintainer's opinion on the security implications.

Lets the CLI append header names to Access-Control-Allow-Headers without
forcing users to drop down to the programmatic API. Defaults are preserved.

The motivating case is `--apiKey` behind a browser: the proxy expects the
secret in `X-API-Key`, but that header is not in the default
Access-Control-Allow-Headers list, so the browser preflight rejects it and
the request never reaches the proxy. With `--corsAddAllowedHeader X-API-Key`
the preflight succeeds and the apiKey gate works as advertised.

  npx mcp-proxy --port 8080 --apiKey secret \
    --corsAddAllowedHeader X-API-Key \
    -- node server.js

For broader CORS overrides (origin allowlist, wildcard headers, disabling
CORS) the programmatic `cors` option remains the right surface — this flag
is intentionally narrow.
@punkpeye punkpeye merged commit 204769e into punkpeye:main May 12, 2026
1 check passed
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 6.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@DmitriyAlergant
Copy link
Copy Markdown
Author

@punkpeye thanks for merging. By any chance don't you think this should be a default (accept CORS header) when --apiKey is used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants