Transport for TMCP using HTTP
npm install @tmcp/transport-httpAn HTTP transport implementation for TMCP (TypeScript Model Context Protocol) servers. This package provides HTTP Streaming based communication for MCP servers over HTTP, enabling web-based clients to interact with your MCP server through standard HTTP requests.
``bash`
pnpm add @tmcp/transport-http tmcp
`javascript
import { McpServer } from 'tmcp';
import { HttpTransport } from '@tmcp/transport-http';
// Create your MCP server
const server = new McpServer(
{
name: 'my-http-server',
version: '1.0.0',
description: 'My HTTP MCP server',
},
{
adapter: new YourSchemaAdapter(),
capabilities: {
tools: { listChanged: true },
prompts: { listChanged: true },
resources: { listChanged: true },
},
},
);
// Add your tools, prompts, and resources
server.tool(
{
name: 'example_tool',
description: 'An example tool',
},
async () => {
return {
content: [{ type: 'text', text: 'Hello from HTTP!' }],
};
},
);
// Create the HTTP transport (defaults to '/mcp' path)
const transport = new HttpTransport(server);
// Use with your preferred HTTP server
// Example with Node.js built-in server + @remix-run/
import * as http from 'node:http';
import { createRequestListener } from '@remix-run/node-fetch-server';
let httpServer = http.createServer(createRequestListener((request)=>{
const response = await transport.respond(request);
if(response){
return response;
}
return new Response(null, { status: 404 });
}));
httpServer.listen(3000, () => {
console.log('MCP HTTP server listening on port 3000');
});
`
`javascriptsession-${Date.now()}-${Math.random().toString(36).substr(2, 9)}
const transport = new HttpTransport(server, {
// Custom MCP endpoint path (default: '/mcp', use null to respond on every path)
path: '/api/mcp',
// Custom session ID generation
getSessionId: () => {
return ;
},
});
> [!NOTE]
> When the transport runs in development mode and you omit the path option, a warning is emitted. Future releases will treat an undefined path as "respond on every path", so set the property explicitly (for example path: '/mcp' or path: null) to lock in the behavior you want today.`
You can pass custom context data to your MCP server for each request. This is useful for authentication, user information, database connections, etc.
`javascript
// Define your custom context type
interface MyContext {
userId: string;
permissions: string[];
database: DatabaseConnection;
}
// Create server with custom context
const server = new McpServer(serverInfo, options).withContext
server.tool(
{
name: 'get-user-profile',
description: 'Get the current user profile',
},
async () => {
// Access custom context in your handler
const { userId, database } = server.ctx.custom!;
const profile = await database.users.findById(userId);
return {
content: [
{ type: 'text', text: User profile: ${JSON.stringify(profile)} }
],
};
},
);
// Create transport (it will be typed to accept your custom context)
const transport = new HttpTransport(server);
// then in the handler
const response = await transport.respond(req, {
userId,
permissions,
database: req.locals.db,
});
`
The HTTP transport supports custom session managers for different deployment scenarios:
#### In-Memory Sessions (Default)
`javascript
import {
InMemoryStreamSessionManager,
InMemoryInfoSessionManager,
} from '@tmcp/session-manager';
const transport = new HttpTransport(server, {
sessionManager: {
streams: new InMemoryStreamSessionManager(),
info: new InMemoryInfoSessionManager(),
},
});
`
#### Redis Sessions (Multi-Server/Serverless)
For deployments across multiple servers or serverless environments where sessions need to be shared:
`javascript
import {
RedisStreamSessionManager,
RedisInfoSessionManager,
} from '@tmcp/session-manager-redis';
const transport = new HttpTransport(server, {
sessionManager: {
streams: new RedisStreamSessionManager('redis://localhost:6379'),
info: new RedisInfoSessionManager('redis://localhost:6379'),
},
});
`
When to use Redis sessions:
- Multi-server deployments: When your application runs on multiple servers and clients might connect to different instances
- Serverless deployments: When your transport is deployed on serverless platforms where instances are ephemeral (attention, serverless environment generally kills SSE request after a not-so-long amount of time, this means notification from the server will not reach the client after the shutdown)
- Load balancing: When using load balancers that might route requests to different server instances
- 🌐 HTTP/SSE Communication: Uses Server-Sent Events for real-time bidirectional communication
- 🔄 Session Management: Maintains client sessions with automatic session ID generation
- 📡 Streaming Responses: Supports streaming responses through SSE
- 🛤️ Configurable Path: Customizable MCP endpoint path with automatic filtering (set path to null to respond everywhere)server.ctx.sessionInfo
- 🔧 Framework Agnostic: Works with any HTTP server framework (Fastify, Bun, Deno, etc.)
- ⚡ Real-time Updates: Server can push notifications and updates to connected clients
- 🛡️ Error Handling: Graceful error handling for malformed requests
- 🔀 Multiple HTTP Methods: Supports GET (notifications), POST (messages), and DELETE (disconnect)
- 🧠 Session Metadata: Automatically persists client capabilities, info, and log levels and exposes them via
#### Constructor
`typescript`
new HttpTransport(server: McpServer, options?: HttpTransportOptions)
Creates a new HTTP transport instance.
Parameters:
- server - A TMCP server instance to handle incoming requestsoptions
- - Optional configuration for the transport
Options:
`typescript`
interface HttpTransportOptions {
getSessionId: () => string; // Custom session ID generator
path?: string | null; // MCP endpoint path (default: '/mcp', null responds on every path)
oauth?: OAuth; // an oauth provider generated from @tmcp/auth
sessionManager?: {
streams?: StreamSessionManager;
info?: InfoSessionManager;
}; // Provide custom managers; defaults to in-memory implementations
disableSse?: boolean; // Disable SSE stream endpoint (GET returns 405)
}
If you omit sessionManager the transport creates InMemoryStreamSessionManager and InMemoryInfoSessionManager instances for you. You can override either field independently (for example, Redis streams with in-memory metadata during development).
If your deployment doesn't support long-lived SSE connections (e.g., some serverless environments), you can disable the GET endpoint:
`javascript`
const transport = new HttpTransport(server, {
disableSse: true,
});
When disableSse is true, GET requests to the MCP endpoint will return a 405 Method Not Allowed response. Clients can still communicate via POST requests, but won't receive server-initiated notifications.
#### Methods
##### respond(request: Request, customContext?: T): Promise
Processes an HTTP request and returns a Response with Server-Sent Events, or null if the request path doesn't match the configured MCP path.
Parameters:
- request - A Web API Request object containing the JSON-RPC messagecustomContext
- - Optional custom context data to pass to the MCP server for this request
Returns:
- A Response object with SSE stream for ongoing communication, or null if the request path doesn't match the MCP endpoint
HTTP Methods:
- POST: Processes MCP messages and returns short-lived event stream responses
- GET: Establishes long-lived connections for server notifications
- DELETE: Disconnects sessions and cleans up resources
The transport supports three HTTP methods:
#### POST - Message Processing
Clients send JSON-RPC messages via HTTP POST requests:
`http
POST /mcp HTTP/1.1
Content-Type: application/json
mcp-session-id: optional-session-id
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
`
Response: Short-lived event stream that closes after sending the response:
`http
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
mcp-session-id: generated-or-provided-session-id
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}
`
#### GET - Notification Stream
Establishes long-lived connections for server notifications:
`http`
GET /mcp HTTP/1.1
mcp-session-id: optional-session-id
Response: Long-lived event stream for server notifications:
`http
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
mcp-session-id: generated-or-provided-session-id
data: {"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
`
#### DELETE - Session Disconnect
Disconnects a session and cleans up resources:
`http`
DELETE /mcp HTTP/1.1
mcp-session-id: session-to-disconnect
Response:
`http`
HTTP/1.1 204 No Content
mcp-session-id: session-to-disconnect
- Session ID Header: mcp-session-id
- Automatic Generation: If no session ID is provided, one is generated automatically
- Session Persistence: Sessions persist across multiple requests until the client disconnects
- Server Notifications: Server can send notifications to all active sessions
`javascript
import { McpServer } from 'tmcp';
import { HttpTransport } from '@tmcp/transport-http';
const server = new McpServer(/ ... /);
const transport = new HttpTransport(server);
Bun.serve({
port: 3000,
async fetch(req) {
const response = await transport.respond(req);
if (response === null) {
return new Response('Not Found', { status: 404 });
}
return response;
},
});
`
`javascript
import { McpServer } from 'tmcp';
import { HttpTransport } from '@tmcp/transport-http';
const server = new McpServer(/ ... /);
const transport = new HttpTransport(server);
Deno.serve({ port: 3000 }, async (req) => {
const response = await transport.respond(req);
if (response === null) {
return new Response('Not Found', { status: 404 });
}
return response;
});
`
If you want the same experience across Deno, Bun, and Node.js, you can use srvx.
`js
import { McpServer } from 'tmcp';
import { HttpTransport } from '@tmcp/transport-http';
import { serve } from 'srvx';
const server = new McpServer(/ ... /);
const transport = new HttpTransport(server);
serve({
async fetch(req) {
const response = await transport.respond(req);
if (response === null) {
return new Response('Not Found', { status: 404 });
}
return response;
},
});
`
The transport includes comprehensive error handling:
- Malformed JSON: Invalid JSON requests return appropriate error responses
- Session Management: Automatic cleanup of disconnected sessions
- Server Errors: Server processing errors are propagated to clients
`bashInstall dependencies
pnpm install
Requirements
- Node.js 16+ (for native ES modules and Web API support)
- A TMCP server instance
- An HTTP server framework or runtime
- A schema adapter (Zod, Valibot, etc.)
Related Packages
tmcp - Core TMCP server implementation
- @tmcp/transport-stdio - Standard I/O transport
- @tmcp/adapter-zod - Zod schema adapter
- @tmcp/adapter-valibot - Valibot schema adapterAcknowledgments
Huge thanks to Sean O'Bannon that provided us with the
@tmcp` scope on npm.MIT