Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/everything/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ npm install
npm run start:sse
```

Note: the SSE transport binds to `127.0.0.1` by default and only enables CORS for loopback origins (for Inspector direct connect). To intentionally expose it, set:

```shell
HOST=0.0.0.0 MCP_CORS_ORIGIN_REGEX='^https?://your-allowed-origin(:\\d+)?$' npm run start:sse
```

## Run from source with [Streamable HTTP Transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http)

```shell
Expand All @@ -78,6 +84,12 @@ npm install
npm run start:streamableHttp
```

Note: the Streamable HTTP transport binds to `127.0.0.1` by default and only enables CORS for loopback origins (for Inspector direct connect). To intentionally expose it, set:

```shell
HOST=0.0.0.0 MCP_CORS_ORIGIN_REGEX='^https?://your-allowed-origin(:\\d+)?$' npm run start:streamableHttp
```

## Running as an installed package
### Install
```shell
Expand All @@ -103,4 +115,3 @@ npx @modelcontextprotocol/server-everything sse
```shell
npx @modelcontextprotocol/server-everything streamableHttp
```

38 changes: 38 additions & 0 deletions src/everything/transports/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { CorsOptions } from "cors";

const DEFAULT_LOOPBACK_ORIGIN_REGEX =
/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/;

function getCorsOriginRegex(): RegExp {
const raw = process.env.MCP_CORS_ORIGIN_REGEX;
if (!raw) return DEFAULT_LOOPBACK_ORIGIN_REGEX;

try {
return new RegExp(raw);
} catch (err) {
// Fail fast with a clear message instead of silently allowing all origins.
throw new Error(
`Invalid MCP_CORS_ORIGIN_REGEX=${JSON.stringify(raw)}: ${String(err)}`
);
}
}

export function createCorsOptions(opts: {
methods: string;
exposedHeaders?: string[];
}): CorsOptions {
const originRegex = getCorsOriginRegex();

return {
// Only allow loopback origins by default (Inspector direct connect).
// Override via MCP_CORS_ORIGIN_REGEX if you intentionally need a wider allowlist.
origin: (origin, callback) => {
if (!origin) return callback(null, false);
return callback(null, originRegex.test(origin));
},
methods: opts.methods,
preflightContinue: false,
optionsSuccessStatus: 204,
...(opts.exposedHeaders ? { exposedHeaders: opts.exposedHeaders } : {}),
};
}
25 changes: 15 additions & 10 deletions src/everything/transports/sse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
import { createServer } from "../server/index.js";
import cors from "cors";
import { createCorsOptions } from "./cors.js";

console.error("Starting SSE server...");

// Express app with permissive CORS for testing with Inspector direct connect mode
// Express app with loopback-only CORS by default for Inspector direct connect mode.
// Override via MCP_CORS_ORIGIN_REGEX if you intentionally need a wider allowlist.
const app = express();
app.use(
cors({
origin: "*", // use "*" with caution in production
methods: "GET,POST",
preflightContinue: false,
optionsSuccessStatus: 204,
})
cors(
createCorsOptions({
methods: "GET,POST",
})
)
);

// Map sessionId to transport for each client
Expand Down Expand Up @@ -71,7 +72,11 @@ app.post("/message", async (req, res) => {
});

// Start the express server
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.error(`Server is running on port ${PORT}`);
const PORT = process.env.PORT ? Number(process.env.PORT) : 3001;
if (!Number.isFinite(PORT)) {
throw new Error(`Invalid PORT=${JSON.stringify(process.env.PORT)}`);
}
const HOST = process.env.HOST || "127.0.0.1";
app.listen(PORT, HOST, () => {
console.error(`Server is running on http://${HOST}:${PORT}`);
});
33 changes: 22 additions & 11 deletions src/everything/transports/streamableHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import express, { Request, Response } from "express";
import { createServer } from "../server/index.js";
import { randomUUID } from "node:crypto";
import cors from "cors";
import { createCorsOptions } from "./cors.js";

// Simple in-memory event store for SSE resumability
class InMemoryEventStore implements EventStore {
Expand Down Expand Up @@ -38,16 +39,20 @@ class InMemoryEventStore implements EventStore {

console.log("Starting Streamable HTTP server...");

// Express app with permissive CORS for testing with Inspector direct connect mode
// Express app with loopback-only CORS by default for Inspector direct connect mode.
// Override via MCP_CORS_ORIGIN_REGEX if you intentionally need a wider allowlist.
const app = express();
app.use(
cors({
origin: "*", // use "*" with caution in production
methods: "GET,POST,DELETE",
preflightContinue: false,
optionsSuccessStatus: 204,
exposedHeaders: ["mcp-session-id", "last-event-id", "mcp-protocol-version"],
})
cors(
createCorsOptions({
methods: "GET,POST,DELETE",
exposedHeaders: [
"mcp-session-id",
"last-event-id",
"mcp-protocol-version",
],
})
)
);

// Map sessionId to server transport for each client
Expand Down Expand Up @@ -198,9 +203,15 @@ app.delete("/mcp", async (req: Request, res: Response) => {
});

// Start the server
const PORT = process.env.PORT || 3001;
const server = app.listen(PORT, () => {
console.error(`MCP Streamable HTTP Server listening on port ${PORT}`);
const PORT = process.env.PORT ? Number(process.env.PORT) : 3001;
if (!Number.isFinite(PORT)) {
throw new Error(`Invalid PORT=${JSON.stringify(process.env.PORT)}`);
}
const HOST = process.env.HOST || "127.0.0.1";
const server = app.listen(PORT, HOST, () => {
console.error(
`MCP Streamable HTTP Server listening on http://${HOST}:${PORT}`
);
});

// Handle server errors
Expand Down