Configuring CORS


Configuring CORS

Control browser access to your MCP server

This article describes CORS configuration that's specific to Apollo MCP Server. For a more general introduction to CORS and common considerations, see MDN's CORS documentation.

By default, Apollo MCP Server has CORS disabled. If your MCP server serves tools to browser-based applications, you need to enable CORS and configure one of the following in the cors section of your server's YAML config file:

  • Add the origins of those web applications to the server's list of allowed origins.

    • Use this option if there is a known, finite list of web applications that consume your MCP server.

  • Add a regex that matches the origins of those web applications to the server's list of allowed match_origins.

    • This option comes in handy if you want to match origins against a pattern, see the example below that matches subdomains of a specific namespace.

  • Enable the allow_any_origin option.

    • Use this option if your MCP server is a public API with arbitrarily many web app consumers.

    • With this option enabled, the server sends the wildcard (*) value for the Access-Control-Allow-Origin header. This enables any website to initiate browser connections to it (but they can't provide cookies or other credentials).

  • If clients need to authenticate their requests with cookies, you must use either origins, match_origins, or the combination of both options. When using both options, note that origins is evaluated before match_origins.

The following snippet includes an example of each option (use either allow_any_origin, or origins and/or match_origins):

YAML
mcp.yaml
1transport:
2  type: streamable_http
3  port: 8000
4
5cors:
6  # Enable CORS support
7  enabled: true
8
9  # Set to true to allow any origin
10  # (Defaults to false)
11  allow_any_origin: true
12
13  # List of accepted origins
14  # (Ignored if allow_any_origin is true)
15  #
16  # An origin is a combination of scheme, hostname and port.
17  # It does not have any path section, so no trailing slash.
18  origins:
19    - https://www.your-app.example.com
20
21  # List of origin patterns (regex matching)
22  match_origins:
23    - "^https://([a-z0-9]+[.])*api[.]example[.]com$" # any host that uses https and ends with .api.example.com

You can also disable CORS entirely by setting enabled to false or omitting the cors section:

YAML
mcp.yaml
1cors:
2  enabled: false

If your MCP server serves exclusively non-browser-based clients, you probably don't need to enable CORS configuration.

Passing credentials

If your MCP server requires requests to include a user's credentials (e.g., via cookies), you need to modify your CORS configuration to tell the browser those credentials are allowed.

You can enable credentials with CORS by setting the Access-Control-Allow-Credentials HTTP header to true.

To allow browsers to pass credentials to the server, set allow_credentials to true, like so:

YAML
mcp.yaml
1cors:
2  enabled: true
3  origins:
4    - https://www.your-app.example.com
5  allow_credentials: true

To support credentialed requests, your server's config file must specify individual origins or match_origins. If your server enables allow_any_origin, your browser will refuse to send credentials.

All cors options

The following snippet shows all CORS configuration defaults for Apollo MCP Server:

YAML
mcp.yaml
1#
2# CORS (Cross Origin Resource Sharing)
3#
4cors:
5  # Enable CORS support
6  enabled: false
7
8  # Set to true to allow any origin
9  allow_any_origin: false
10
11  # List of accepted origins
12  # (Ignored if allow_any_origin is set to true)
13  #
14  # An origin is a combination of scheme, hostname and port.
15  # It does not have any path section, so no trailing slash.
16  origins: []
17
18  # List of origin patterns (regex matching)
19  # Useful for matching dynamic ports or subdomains
20  match_origins: []
21
22  # Set to true to add the `Access-Control-Allow-Credentials` header
23  allow_credentials: false
24
25  # Allowed request methods
26  allow_methods:
27    - GET
28    - POST
29
30  # The headers to allow.
31  # These are the default headers required for MCP protocol and trace context
32  allow_headers:
33    - accept
34    - content-type
35    - mcp-protocol-version
36    - mcp-session-id
37    - traceparent # W3C Trace Context
38    - tracestate # W3C Trace Context
39
40  # Which response headers are available to scripts running in the
41  # browser in response to a cross-origin request.
42  # The mcp-session-id header should be exposed for MCP session management.
43  # Trace context headers are exposed for distributed tracing.
44  expose_headers:
45    - mcp-session-id
46    - traceparent # W3C Trace Context
47    - tracestate # W3C Trace Context
48
49  # Adds the Access-Control-Max-Age header
50  # Maximum age (in seconds) for preflight cache
51  max_age: 7200 # 2 hours

Origin matching

Apollo MCP Server supports two types of origin matching:

Exact origins

Use the origins array for exact origin matches:

YAML
1cors:
2  enabled: true
3  origins:
4    - http://localhost:3000
5    - https://myapp.example.com

Pattern matching

Use the match_origins array for regex pattern matching:

YAML
1cors:
2  enabled: true
3  match_origins:
4    - "^https://localhost:[0-9]+$" # Any localhost HTTPS port
5    - "^http://localhost:[0-9]+$" # Any localhost HTTP port
6    - "^https://.*\\.example\\.com$" # Any subdomain of example.com

Common configurations

Development setup

For local development with hot reloading and various ports:

YAML
mcp.yaml
1cors:
2  enabled: true
3  match_origins:
4    - "^http://localhost:[0-9]+$"
5  allow_credentials: true

Production setup

For production with specific known origins:

YAML
mcp.yaml
1cors:
2  enabled: true
3  origins:
4    - https://myapp.example.com
5  allow_credentials: true
6  max_age: 86400 # 24 hours

Public API setup

For public APIs that don't require credentials:

YAML
mcp.yaml
1cors:
2  enabled: true
3  allow_any_origin: true
4  allow_credentials: false # Cannot use credentials with any origin

Browser integration example

Here's a simple example of connecting to Apollo MCP Server from a browser:

JavaScript
1async function connectToMCP() {
2  const response = await fetch("http://127.0.0.1:8000/mcp", {
3    method: "POST",
4    headers: {
5      Accept: "application/json, text/event-stream",
6      "Content-Type": "application/json",
7      "MCP-Protocol-Version": "2025-06-18",
8    },
9    body: JSON.stringify({
10      jsonrpc: "2.0",
11      method: "initialize",
12      params: {
13        protocolVersion: "2025-06-18",
14        capabilities: {},
15        clientInfo: { name: "Browser Client", version: "1.0" },
16      },
17      id: 1,
18    }),
19  });
20
21  // Extract session ID from response headers (automatically exposed)
22  const sessionId = response.headers.get("mcp-session-id");
23
24  // Handle SSE format response (starts with "data: ")
25  const responseText = await response.text();
26  const jsonData = responseText.startsWith("data: ")
27    ? responseText.slice(6) // Remove "data: " prefix
28    : responseText;
29
30  const result = JSON.parse(jsonData);
31  console.log("Connected:", result);
32  console.log("Session ID:", sessionId);
33}
34
35connectToMCP();