Skip to content

Conversation

@AhmedElhadidii
Copy link

@AhmedElhadidii AhmedElhadidii commented Aug 12, 2025

Summary;
-Migrate server transport from SSE to Streamable HTTP.
-Consolidate all MCP traffic to a single /mcp endpoint with StreamableHTTPServerTransport.handleRequest.
-Keep stdio mode unchanged.
-Add Linux-safe guards to avoid xcrun calls on non-macOS.
-Bump MCP SDK to ^1.13.2.

Summary by CodeRabbit

  • New Features

    • HTTP server now supports dual transport modes: StreamableHTTPServerTransport and SSEServerTransport.
    • Added session-based connection management for improved transport reuse and validation.
    • Introduced new SSE endpoints: GET /sse and POST /messages for backward compatibility.
    • Enhanced error handling with structured responses.
  • Chores

    • Updated startup messaging to reflect HTTP server mode and available transports.
    • Refreshed CLI help text.

✏️ Tip: You can customize this high-level summary in your review settings.

@krismuhi
Copy link
Member

thanks for the PR!

we need to make this optional.
with defaults and easy way to switch

can you share your usecase?

@AhmedElhadidii
Copy link
Author

The Use case is that there are some MCP clients that only support the new Http Streamable method.
For example N8N Only allow integrations with Http Streamable

Copilot AI and others added 4 commits August 22, 2025 13:48
Co-authored-by: AhmedElhadidii <89388836+AhmedElhadidii@users.noreply.github.com>
Co-authored-by: AhmedElhadidii <89388836+AhmedElhadidii@users.noreply.github.com>
…-36a8041e48ba

Support both Streamable HTTP and SSE transports for backward compatibility
@AhmedElhadidii AhmedElhadidii changed the title Server: migrate SSE to Streamable HTTP & Bump MCP SDK version Server: Added Streamable HTTP & Bump MCP SDK version Aug 22, 2025
@gmegidish
Copy link
Member

@AhmedElhadidii this PR is lit 🔥 🔥 !

I'll check it thoroughly with n8n and I'll merge.

@gmegidish
Copy link
Member

btw, why was the types.d file needed? these types are exported already in the mcp package itself.

thank you so much for this PR!!!! 🙏

@AhmedElhadidii
Copy link
Author

AhmedElhadidii commented Aug 24, 2025

btw, why was the types.d file needed? these types are exported already in the mcp package itself.

Yes You're absolutely Right!👌

Copy link
Author

@AhmedElhadidii AhmedElhadidii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

gmegidish and others added 2 commits October 21, 2025 15:17
Removed checks for iOS Simulator availability on non-macOS platforms. Device won't be returned in list_available_devices
@coderabbitai
Copy link

coderabbitai bot commented Dec 24, 2025

Walkthrough

Introduces a dual-transport HTTP server supporting StreamableHTTPServerTransport and SSEServerTransport with session-based management. Replaces SSE-only setup with unified /mcp endpoint, adds backward-compatible SSE routes, and refactors server initialization with improved error handling and updated startup messaging.

Changes

Cohort / File(s) Summary
Transport Management
src/index.ts
Added StreamableHTTPServerTransport and SSEServerTransport support with session-based transport storage and reuse; implemented transport cleanup on close
Route Consolidation & Enhancement
src/index.ts
Replaced old /mcp handler with unified app.all("/mcp") for transport initialization and validation; added GET /sse and POST /messages routes for backward-compatible SSE handling
Session & Initialization Logic
src/index.ts
Implemented session ID-based validation, transport initialization detection, and automatic MCP server creation and wiring to transports
Dependencies & Error Handling
src/index.ts
Added isInitializeRequest and randomUUID imports, integrated express.json() middleware; refined JSON-RPC error responses and 500 error handling across paths
Server Configuration & CLI Updates
src/index.ts
Renamed startSseServer to startHttpServer; updated startup logging to display HTTP server mode and supported transports; revised CLI help text

Possibly related issues

  • support Streamable HTTP server #98 - Directly addresses the same objective of adding StreamableHTTPServerTransport support and modifying HTTP /mcp endpoint handling for transport connection

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions 'Streamable HTTP' which aligns with the main change (new HTTP-based server flow), but omits the significant addition of session-based transport management and backward compatibility for SSE, making it partially cover the primary changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ef1319 and 3b6859b.

📒 Files selected for processing (1)
  • src/index.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/index.ts (2)
src/server.ts (2)
  • createMcpServer (34-612)
  • getAgentVersion (29-32)
src/logger.ts (1)
  • error (19-21)
🔇 Additional comments (4)
src/index.ts (4)

22-97: Streamable HTTP transport implementation looks solid.

The session management logic correctly validates transport types, creates new sessions only for initialization requests, and properly cleans up on close. The app.all() approach appropriately delegates HTTP method handling (including DELETE for session termination) to the SDK's transport.handleRequest().


122-156: SSE message handling is well-structured.

Good validation chain for session ID and transport type, with appropriate error responses. The type guard on line 136 ensures type safety before calling handlePostMessage.


158-163: Startup logging is clear and helpful.

Good documentation of both available transport endpoints. The logging is consistent with existing patterns in the codebase.


181-195: CLI interface properly updated.

Help text accurately describes the dual-transport capability, and the function invocation correctly uses the renamed startHttpServer.

Comment on lines +102 to 119
app.get("/sse", async (req, res) => {
console.log("Received GET request to /sse (SSE transport)");
try {
const transport = new SSEServerTransport("/messages", res);
transports[transport.sessionId] = transport;

res.on("close", () => {
delete transports[transport.sessionId];
});

const server = createMcpServer();
await server.connect(transport);
} catch (error: any) {
console.error("Error setting up SSE transport:", error);
if (!res.headersSent) {
res.status(500).send("Failed to establish SSE connection");
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential memory leak if server.connect() fails.

The transport is added to the transports map on line 106 before server.connect() is called on line 113. If connect() throws, the entry remains in the map since res.on("close") may not fire for an incompletely established SSE connection.

🔎 Proposed fix: store transport after successful connection
 	app.get("/sse", async (req, res) => {
 		console.log("Received GET request to /sse (SSE transport)");
 		try {
 			const transport = new SSEServerTransport("/messages", res);
-			transports[transport.sessionId] = transport;
 
 			res.on("close", () => {
 				delete transports[transport.sessionId];
 			});
 
 			const server = createMcpServer();
 			await server.connect(transport);
+			transports[transport.sessionId] = transport;
 		} catch (error: any) {
 			console.error("Error setting up SSE transport:", error);
 			if (!res.headersSent) {
 				res.status(500).send("Failed to establish SSE connection");
 			}
 		}
 	});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.get("/sse", async (req, res) => {
console.log("Received GET request to /sse (SSE transport)");
try {
const transport = new SSEServerTransport("/messages", res);
transports[transport.sessionId] = transport;
res.on("close", () => {
delete transports[transport.sessionId];
});
const server = createMcpServer();
await server.connect(transport);
} catch (error: any) {
console.error("Error setting up SSE transport:", error);
if (!res.headersSent) {
res.status(500).send("Failed to establish SSE connection");
}
}
app.get("/sse", async (req, res) => {
console.log("Received GET request to /sse (SSE transport)");
try {
const transport = new SSEServerTransport("/messages", res);
res.on("close", () => {
delete transports[transport.sessionId];
});
const server = createMcpServer();
await server.connect(transport);
transports[transport.sessionId] = transport;
} catch (error: any) {
console.error("Error setting up SSE transport:", error);
if (!res.headersSent) {
res.status(500).send("Failed to establish SSE connection");
}
}
});
🤖 Prompt for AI Agents
In src/index.ts around lines 102 to 119, the SSE transport is inserted into the
transports map before server.connect(), so if connect() throws the transport
remains registered and leaks; instead instantiate the transport but only add it
to transports and attach the res.on("close") cleanup after await
server.connect(transport) succeeds; on connect failure ensure you clean up by
calling any transport.close() / dispose method (or otherwise free resources) and
do not leave the transport in the map, then send the 500 response if headers not
sent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants