Merge pull request #713 from modelcontextprotocol/jerome/cors-browser-support
feat: Add CORS configuration for browser-based MCP clients
This commit is contained in:
commit
1bd56ee46d
5 changed files with 54 additions and 14 deletions
35
README.md
35
README.md
|
|
@ -570,20 +570,31 @@ app.listen(3000);
|
|||
```
|
||||
|
||||
> [!TIP]
|
||||
> When using this in a remote environment, make sure to allow the header parameter `mcp-session-id` in CORS. Otherwise, it may result in a `Bad Request: No valid session ID provided` error.
|
||||
>
|
||||
> For example, in Node.js you can configure it like this:
|
||||
>
|
||||
> ```ts
|
||||
> app.use(
|
||||
> cors({
|
||||
> origin: ['https://your-remote-domain.com, https://your-other-remote-domain.com'],
|
||||
> exposedHeaders: ['mcp-session-id'],
|
||||
> allowedHeaders: ['Content-Type', 'mcp-session-id'],
|
||||
> })
|
||||
> );
|
||||
> When using this in a remote environment, make sure to allow the header parameter `mcp-session-id` in CORS. Otherwise, it may result in a `Bad Request: No valid session ID provided` error. Read the following section for examples.
|
||||
> ```
|
||||
|
||||
|
||||
#### CORS Configuration for Browser-Based Clients
|
||||
|
||||
If you'd like your server to be accessible by browser-based MCP clients, you'll need to configure CORS headers. The `Mcp-Session-Id` header must be exposed for browser clients to access it:
|
||||
|
||||
```typescript
|
||||
import cors from 'cors';
|
||||
|
||||
// Add CORS middleware before your MCP routes
|
||||
app.use(cors({
|
||||
origin: '*', // Configure appropriately for production, for example:
|
||||
// origin: ['https://your-remote-domain.com, https://your-other-remote-domain.com'],
|
||||
exposedHeaders: ['Mcp-Session-Id']
|
||||
allowedHeaders: ['Content-Type', 'mcp-session-id'],
|
||||
}));
|
||||
```
|
||||
|
||||
This configuration is necessary because:
|
||||
- The MCP streamable HTTP transport uses the `Mcp-Session-Id` header for session management
|
||||
- Browsers restrict access to response headers unless explicitly exposed via CORS
|
||||
- Without this configuration, browser-based clients won't be able to read the session ID from initialization responses
|
||||
|
||||
#### Without Session Management (Stateless)
|
||||
|
||||
For simpler use cases where session management isn't needed:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { McpServer } from '../../server/mcp.js';
|
|||
import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js';
|
||||
import { z } from 'zod';
|
||||
import { CallToolResult, isInitializeRequest } from '../../types.js';
|
||||
import cors from 'cors';
|
||||
|
||||
|
||||
// Create an MCP server with implementation details
|
||||
|
|
@ -81,6 +82,12 @@ const getServer = () => {
|
|||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Configure CORS to expose Mcp-Session-Id header for browser-based clients
|
||||
app.use(cors({
|
||||
origin: '*', // Allow all origins - adjust as needed for production
|
||||
exposedHeaders: ['Mcp-Session-Id']
|
||||
}));
|
||||
|
||||
// Map to store transports by session ID
|
||||
const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { McpServer } from '../../server/mcp.js';
|
|||
import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js';
|
||||
import { z } from 'zod';
|
||||
import { CallToolResult, GetPromptResult, ReadResourceResult } from '../../types.js';
|
||||
import cors from 'cors';
|
||||
|
||||
const getServer = () => {
|
||||
// Create an MCP server with implementation details
|
||||
|
|
@ -96,6 +97,12 @@ const getServer = () => {
|
|||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Configure CORS to expose Mcp-Session-Id header for browser-based clients
|
||||
app.use(cors({
|
||||
origin: '*', // Allow all origins - adjust as needed for production
|
||||
exposedHeaders: ['Mcp-Session-Id']
|
||||
}));
|
||||
|
||||
app.post('/mcp', async (req: Request, res: Response) => {
|
||||
const server = getServer();
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import { setupAuthServer } from './demoInMemoryOAuthProvider.js';
|
|||
import { OAuthMetadata } from 'src/shared/auth.js';
|
||||
import { checkResourceAllowed } from 'src/shared/auth-utils.js';
|
||||
|
||||
import cors from 'cors';
|
||||
|
||||
// Check for OAuth flag
|
||||
const useOAuth = process.argv.includes('--oauth');
|
||||
const strictOAuth = process.argv.includes('--oauth-strict');
|
||||
|
|
@ -420,12 +422,18 @@ const getServer = () => {
|
|||
return server;
|
||||
};
|
||||
|
||||
const MCP_PORT = 3000;
|
||||
const AUTH_PORT = 3001;
|
||||
const MCP_PORT = process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : 3000;
|
||||
const AUTH_PORT = process.env.MCP_AUTH_PORT ? parseInt(process.env.MCP_AUTH_PORT, 10) : 3001;
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Allow CORS all domains, expose the Mcp-Session-Id header
|
||||
app.use(cors({
|
||||
origin: '*', // Allow all origins
|
||||
exposedHeaders: ["Mcp-Session-Id"]
|
||||
}));
|
||||
|
||||
// Set up OAuth if enabled
|
||||
let authMiddleware = null;
|
||||
if (useOAuth) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { SSEServerTransport } from '../../server/sse.js';
|
|||
import { z } from 'zod';
|
||||
import { CallToolResult, isInitializeRequest } from '../../types.js';
|
||||
import { InMemoryEventStore } from '../shared/inMemoryEventStore.js';
|
||||
import cors from 'cors';
|
||||
|
||||
/**
|
||||
* This example server demonstrates backwards compatibility with both:
|
||||
|
|
@ -71,6 +72,12 @@ const getServer = () => {
|
|||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Configure CORS to expose Mcp-Session-Id header for browser-based clients
|
||||
app.use(cors({
|
||||
origin: '*', // Allow all origins - adjust as needed for production
|
||||
exposedHeaders: ['Mcp-Session-Id']
|
||||
}));
|
||||
|
||||
// Store transports by session ID
|
||||
const transports: Record<string, StreamableHTTPServerTransport | SSEServerTransport> = {};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue