Configuring CORS for Apollo MCP Server


Why it matters

When your clients include browsers (for example, Single Page Apps or other browser‑based frontends), you need Cross‑Origin Resource Sharing (CORS) properly configured, otherwise browsers will block requests. Misconfigurations (too permissive or too restrictive) can lead to bugs or security issues. By default, Apollo MCP Server has CORS disabled.

This page shows how to enable and configure CORS for Apollo 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.

Enabling CORS

To enable CORS, add a cors section to your Apollo MCP Server YAML config file:

YAML
mcp.yaml
1cors:
2  enabled: true

If enabled is not set to true, all other CORS options are ignored.

Configuring allowed origins

You must specify which browser origins are allowed to access your MCP Server.

Allow any origin

YAML
mcp.yaml
1cors:
2  enabled: true
3  allow_any_origin: true

If you set allow_any_origin to true (the default is false), Apollo MCP Server will respond with Access-Control-Allow-Origin: * in all CORS responses. This means that any website can initiate browser connections.

note
Clients will not be able to authenticate with your MCP Server if you set allow_any_origin to true.

Origins

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

Set origins to a list of URLs to restrict access to specific servers. Use this option if you have a known list of web applications accessing your MCP server. An origin is a combination of protocol, hostname, and port. Origins do not include a path, so do not include a trailing slash.

Match Origins

YAML
mcp.yaml
1cors:
2  enabled: true
3  match_origins:
4    - "^http://localhost:\d+$" # Any localhost url from any port
5    - "^https://([a-z0-9]+[.])*.api.example.com$" # Any host that uses https and is either api.example.com or a subdomain of it

The match_origins configuration option allows you to use a regular expression to set endpoints that can interact with your Apollo MCP Server. While match_origins can be used with origins, it is always evaluated after origins.

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

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();
Feedback

Edit on GitHub

Ask Community