Skip to content

Commit 7048e23

Browse files
committed
docs: add cors docs page
1 parent 8d0420c commit 7048e23

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed

docs/source/_sidebar.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ items:
2828
href: "./deploy"
2929
- label: "Health Checks"
3030
href: "./health-checks"
31+
- label: "CORS Support"
32+
href: "./cors"
3133
- label: "Authorization"
3234
href: "./auth"
3335
- label: "Best Practices"

docs/source/cors.mdx

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
---
2+
title: Configuring CORS
3+
---
4+
5+
# Configuring CORS
6+
7+
Control browser access to your MCP server
8+
9+
---
10+
11+
**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](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
12+
13+
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:
14+
15+
- Add the origins of those web applications to the server's list of allowed `origins`.
16+
- Use this option if there is a known, finite list of web applications that consume your MCP server.
17+
- Add a regex that matches the origins of those web applications to the server's list of allowed `match_origins`.
18+
- 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.
19+
- Enable the `allow_any_origin` option.
20+
- Use this option if your MCP server is a public API with arbitrarily many web app consumers.
21+
- 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).
22+
- 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`.
23+
24+
The following snippet includes an example of each option (use either `allow_any_origin`, or `origins` and/or `match_origins`):
25+
26+
```yaml title="mcp.yaml"
27+
transport:
28+
type: streamable_http
29+
port: 5000
30+
31+
cors:
32+
# Enable CORS support
33+
enabled: true
34+
35+
# Set to true to allow any origin
36+
# (Defaults to false)
37+
allow_any_origin: true
38+
39+
# List of accepted origins
40+
# (Ignored if allow_any_origin is true)
41+
#
42+
# An origin is a combination of scheme, hostname and port.
43+
# It does not have any path section, so no trailing slash.
44+
origins:
45+
- https://www.your-app.example.com
46+
- https://studio.apollographql.com # Keep this so GraphOS Studio can run queries against your server
47+
48+
# List of origin patterns (regex matching)
49+
match_origins:
50+
- "^https://([a-z0-9]+[.])*api[.]example[.]com$" # any host that uses https and ends with .api.example.com
51+
```
52+
53+
You can also disable CORS entirely by setting `enabled` to `false` or omitting the `cors` section:
54+
55+
```yaml title="mcp.yaml"
56+
cors:
57+
enabled: false
58+
```
59+
60+
If your MCP server serves exclusively _non_-browser-based clients, you probably don't need to enable CORS configuration.
61+
62+
## Passing credentials
63+
64+
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.
65+
66+
You can enable credentials with CORS by setting the Access-Control-Allow-Credentials HTTP header to `true`.
67+
68+
To allow browsers to pass credentials to the server, set `allow_credentials` to `true`, like so:
69+
70+
```yaml title="mcp.yaml"
71+
cors:
72+
enabled: true
73+
origins:
74+
- https://www.your-app.example.com
75+
- https://studio.apollographql.com
76+
allow_credentials: true
77+
```
78+
79+
**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.
80+
81+
## All `cors` options
82+
83+
The following snippet shows all CORS configuration defaults for Apollo MCP Server:
84+
85+
```yaml title="mcp.yaml"
86+
#
87+
# CORS (Cross Origin Resource Sharing)
88+
#
89+
cors:
90+
# Enable CORS support
91+
enabled: false
92+
93+
# Set to true to allow any origin
94+
allow_any_origin: false
95+
96+
# List of accepted origins
97+
# (Ignored if allow_any_origin is set to true)
98+
#
99+
# An origin is a combination of scheme, hostname and port.
100+
# It does not have any path section, so no trailing slash.
101+
origins: []
102+
103+
# List of origin patterns (regex matching)
104+
# Useful for matching dynamic ports or subdomains
105+
match_origins: []
106+
107+
# Set to true to add the `Access-Control-Allow-Credentials` header
108+
allow_credentials: false
109+
110+
# Allowed request methods
111+
allow_methods:
112+
- GET
113+
- POST
114+
115+
# The headers to allow.
116+
# These are the default headers required for MCP protocol
117+
allow_headers:
118+
- accept
119+
- content-type
120+
- mcp-protocol-version
121+
- mcp-session-id
122+
123+
# Which response headers are available to scripts running in the
124+
# browser in response to a cross-origin request.
125+
# The mcp-session-id header should be exposed for MCP session management.
126+
expose_headers:
127+
- mcp-session-id
128+
129+
# Adds the Access-Control-Max-Age header
130+
# Maximum age (in seconds) for preflight cache
131+
max_age: 7200 # 2 hours
132+
```
133+
134+
## Origin matching
135+
136+
Apollo MCP Server supports two types of origin matching:
137+
138+
### Exact origins
139+
140+
Use the `origins` array for exact origin matches:
141+
142+
```yaml
143+
cors:
144+
enabled: true
145+
origins:
146+
- http://localhost:3000
147+
- https://myapp.example.com
148+
- https://studio.apollographql.com
149+
```
150+
151+
### Pattern matching
152+
153+
Use the `match_origins` array for regex pattern matching:
154+
155+
```yaml
156+
cors:
157+
enabled: true
158+
match_origins:
159+
- "^https://localhost:[0-9]+$" # Any localhost HTTPS port
160+
- "^http://localhost:[0-9]+$" # Any localhost HTTP port
161+
- "^https://.*\\.example\\.com$" # Any subdomain of example.com
162+
```
163+
164+
## Common configurations
165+
166+
### Development setup
167+
168+
For local development with hot reloading and various ports:
169+
170+
```yaml title="mcp.yaml"
171+
cors:
172+
enabled: true
173+
match_origins:
174+
- "^http://localhost:[0-9]+$"
175+
allow_credentials: true
176+
```
177+
178+
### Production setup
179+
180+
For production with specific known origins:
181+
182+
```yaml title="mcp.yaml"
183+
cors:
184+
enabled: true
185+
origins:
186+
- https://myapp.example.com
187+
- https://studio.apollographql.com
188+
allow_credentials: true
189+
max_age: 86400 # 24 hours
190+
```
191+
192+
### Public API setup
193+
194+
For public APIs that don't require credentials:
195+
196+
```yaml title="mcp.yaml"
197+
cors:
198+
enabled: true
199+
allow_any_origin: true
200+
allow_credentials: false # Cannot use credentials with any origin
201+
```
202+
203+
## Browser integration example
204+
205+
Here's a simple example of connecting to Apollo MCP Server from a browser:
206+
207+
```javascript
208+
async function connectToMCP() {
209+
const response = await fetch("http://127.0.0.1:5000/mcp", {
210+
method: "POST",
211+
headers: {
212+
Accept: "application/json, text/event-stream",
213+
"Content-Type": "application/json",
214+
"MCP-Protocol-Version": "2025-06-18",
215+
},
216+
body: JSON.stringify({
217+
jsonrpc: "2.0",
218+
method: "initialize",
219+
params: {
220+
protocolVersion: "2025-06-18",
221+
capabilities: {},
222+
clientInfo: { name: "Browser Client", version: "1.0" },
223+
},
224+
id: 1,
225+
}),
226+
});
227+
228+
// Extract session ID from response headers (automatically exposed)
229+
const sessionId = response.headers.get("mcp-session-id");
230+
231+
// Handle SSE format response (starts with "data: ")
232+
const responseText = await response.text();
233+
const jsonData = responseText.startsWith("data: ")
234+
? responseText.slice(6) // Remove "data: " prefix
235+
: responseText;
236+
237+
const result = JSON.parse(jsonData);
238+
console.log("Connected:", result);
239+
console.log("Session ID:", sessionId);
240+
}
241+
242+
connectToMCP();
243+
```

0 commit comments

Comments
 (0)