diff --git a/README.md b/README.md
index 7c69fff5f7..6ca75ede59 100644
--- a/README.md
+++ b/README.md
@@ -106,7 +106,7 @@ Official integrations are maintained by companies building production ready MCP
-
**[Lingo.dev](https://github.com/lingodotdev/lingo.dev/blob/main/mcp.md)** - Make your AI agent speak every language on the planet, using [Lingo.dev](https://lingo.dev) Localization Engine.
-
**[Mailgun](https://github.com/mailgun/mailgun-mcp-server)** - Interact with Mailgun API.
-
**[Make](https://github.com/integromat/make-mcp-server)** - Turn your [Make](https://www.make.com/) scenarios into callable tools for AI assistants.
--
**[MCP Toolbox for Databases](https://github.com/googleapis/genai-toolbox)** - Open source MCP server specializing in easy, fast, and secure tools for Databases.
+-
**[MCP Toolbox for Databases](https://github.com/googleapis/genai-toolbox)** - Open source MCP server specializing in easy, fast, and secure tools for Databases. Supports AlloyDB, BigQuery, Bigtable, Cloud SQL, Dgraph, MySQL, Neo4j, Postgres, Spanner, and more.
-
**[Meilisearch](https://github.com/meilisearch/meilisearch-mcp)** - Interact & query with Meilisearch (Full-text & semantic search API)
-
**[Metoro](https://github.com/metoro-io/metoro-mcp-server)** - Query and interact with kubernetes environments monitored by Metoro
-
**[Milvus](https://github.com/zilliztech/mcp-server-milvus)** - Search, Query and interact with data in your Milvus Vector Database.
diff --git a/package-lock.json b/package-lock.json
index aa8137c3bc..23e61d7022 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5435,7 +5435,7 @@
"version": "0.6.2",
"license": "MIT",
"dependencies": {
- "@modelcontextprotocol/sdk": "^1.9.0",
+ "@modelcontextprotocol/sdk": "^1.10.1",
"express": "^4.21.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.5"
@@ -5450,9 +5450,9 @@
}
},
"src/everything/node_modules/@modelcontextprotocol/sdk": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.9.0.tgz",
- "integrity": "sha512-Jq2EUCQpe0iyO5FGpzVYDNFR6oR53AIrwph9yWl7uSc7IWUMsrmpmSaTGra5hQNunXpM+9oit85p924jWuHzUA==",
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.1.tgz",
+ "integrity": "sha512-xNYdFdkJqEfIaTVP1gPKoEvluACHZsHZegIoICX8DM1o6Qf3G5u2BQJHmgd0n4YgRPqqK/u1ujQvrgAxxSJT9w==",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
diff --git a/src/everything/README.md b/src/everything/README.md
index 236ac59660..4d51de51a3 100644
--- a/src/everything/README.md
+++ b/src/everything/README.md
@@ -126,7 +126,7 @@ The server sends random-leveled log messages every 15 seconds, e.g.:
}
```
-## Usage with Claude Desktop
+## Usage with Claude Desktop (uses [stdio Transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#stdio))
Add to your `claude_desktop_config.json`:
@@ -172,3 +172,19 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
}
}
```
+
+## Run with [HTTP+SSE Transport](https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse) (deprecated as of [2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports))
+
+```shell
+cd src/everything
+npm install
+npm run start:sse
+```
+
+## Run with [Streamable HTTP Transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http)
+
+```shell
+cd src/everything
+npm install
+npm run start:streamableHttp
+```
diff --git a/src/everything/package.json b/src/everything/package.json
index bfcbfae4c9..ffe6b7cd68 100644
--- a/src/everything/package.json
+++ b/src/everything/package.json
@@ -18,10 +18,11 @@
"prepare": "npm run build",
"watch": "tsc --watch",
"start": "node dist/index.js",
- "start:sse": "node dist/sse.js"
+ "start:sse": "node dist/sse.js",
+ "start:streamableHttp": "node dist/streamableHttp.js"
},
"dependencies": {
- "@modelcontextprotocol/sdk": "^1.9.0",
+ "@modelcontextprotocol/sdk": "^1.10.1",
"express": "^4.21.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.5"
diff --git a/src/everything/streamableHttp.ts b/src/everything/streamableHttp.ts
new file mode 100644
index 0000000000..3a87bc8332
--- /dev/null
+++ b/src/everything/streamableHttp.ts
@@ -0,0 +1,172 @@
+import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import { InMemoryEventStore } from '@modelcontextprotocol/sdk/examples/shared/inMemoryEventStore.js';
+import express, { Request, Response } from "express";
+import { createServer } from "./everything.js";
+import { randomUUID } from 'node:crypto';
+
+const app = express();
+
+const { server, cleanup } = createServer();
+
+const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
+
+app.post('/mcp', async (req: Request, res: Response) => {
+ console.log('Received MCP POST request');
+ try {
+ // Check for existing session ID
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
+ let transport: StreamableHTTPServerTransport;
+
+ if (sessionId && transports[sessionId]) {
+ // Reuse existing transport
+ transport = transports[sessionId];
+ } else if (!sessionId) {
+ // New initialization request
+ const eventStore = new InMemoryEventStore();
+ transport = new StreamableHTTPServerTransport({
+ sessionIdGenerator: () => randomUUID(),
+ eventStore, // Enable resumability
+ onsessioninitialized: (sessionId) => {
+ // Store the transport by session ID when session is initialized
+ // This avoids race conditions where requests might come in before the session is stored
+ console.log(`Session initialized with ID: ${sessionId}`);
+ transports[sessionId] = transport;
+ }
+ });
+
+ // Set up onclose handler to clean up transport when closed
+ transport.onclose = () => {
+ const sid = transport.sessionId;
+ if (sid && transports[sid]) {
+ console.log(`Transport closed for session ${sid}, removing from transports map`);
+ delete transports[sid];
+ }
+ };
+
+ // Connect the transport to the MCP server BEFORE handling the request
+ // so responses can flow back through the same transport
+ await server.connect(transport);
+
+ await transport.handleRequest(req, res);
+ return; // Already handled
+ } else {
+ // Invalid request - no session ID or not initialization request
+ res.status(400).json({
+ jsonrpc: '2.0',
+ error: {
+ code: -32000,
+ message: 'Bad Request: No valid session ID provided',
+ },
+ id: req?.body?.id,
+ });
+ return;
+ }
+
+ // Handle the request with existing transport - no need to reconnect
+ // The existing transport is already connected to the server
+ await transport.handleRequest(req, res);
+ } catch (error) {
+ console.error('Error handling MCP request:', error);
+ if (!res.headersSent) {
+ res.status(500).json({
+ jsonrpc: '2.0',
+ error: {
+ code: -32603,
+ message: 'Internal server error',
+ },
+ id: req?.body?.id,
+ });
+ return;
+ }
+ }
+});
+
+// Handle GET requests for SSE streams (using built-in support from StreamableHTTP)
+app.get('/mcp', async (req: Request, res: Response) => {
+ console.log('Received MCP GET request');
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
+ if (!sessionId || !transports[sessionId]) {
+ res.status(400).json({
+ jsonrpc: '2.0',
+ error: {
+ code: -32000,
+ message: 'Bad Request: No valid session ID provided',
+ },
+ id: req?.body?.id,
+ });
+ return;
+ }
+
+ // Check for Last-Event-ID header for resumability
+ const lastEventId = req.headers['last-event-id'] as string | undefined;
+ if (lastEventId) {
+ console.log(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
+ } else {
+ console.log(`Establishing new SSE stream for session ${sessionId}`);
+ }
+
+ const transport = transports[sessionId];
+ await transport.handleRequest(req, res);
+});
+
+// Handle DELETE requests for session termination (according to MCP spec)
+app.delete('/mcp', async (req: Request, res: Response) => {
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
+ if (!sessionId || !transports[sessionId]) {
+ res.status(400).json({
+ jsonrpc: '2.0',
+ error: {
+ code: -32000,
+ message: 'Bad Request: No valid session ID provided',
+ },
+ id: req?.body?.id,
+ });
+ return;
+ }
+
+ console.log(`Received session termination request for session ${sessionId}`);
+
+ try {
+ const transport = transports[sessionId];
+ await transport.handleRequest(req, res);
+ } catch (error) {
+ console.error('Error handling session termination:', error);
+ if (!res.headersSent) {
+ res.status(500).json({
+ jsonrpc: '2.0',
+ error: {
+ code: -32603,
+ message: 'Error handling session termination',
+ },
+ id: req?.body?.id,
+ });
+ return;
+ }
+ }
+});
+
+// Start the server
+const PORT = process.env.PORT || 3001;
+app.listen(PORT, () => {
+ console.log(`MCP Streamable HTTP Server listening on port ${PORT}`);
+});
+
+// Handle server shutdown
+process.on('SIGINT', async () => {
+ console.log('Shutting down server...');
+
+ // Close all active transports to properly clean up resources
+ for (const sessionId in transports) {
+ try {
+ console.log(`Closing transport for session ${sessionId}`);
+ await transports[sessionId].close();
+ delete transports[sessionId];
+ } catch (error) {
+ console.error(`Error closing transport for session ${sessionId}:`, error);
+ }
+ }
+ await cleanup();
+ await server.close();
+ console.log('Server shutdown complete');
+ process.exit(0);
+});