@tmcp/transport-http
v0.8.3
Published
Transport for TMCP using HTTP
Readme
@tmcp/transport-http
An 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.
Installation
pnpm add @tmcp/transport-http tmcpUsage
Basic Setup
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');
});With Custom Configuration
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 `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
},
});
> [!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.With Custom Context
You can pass custom context data to your MCP server for each request. This is useful for authentication, user information, database connections, etc.
// 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<MyContext>();
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,
});Session Management
The HTTP transport supports custom session managers for different deployment scenarios:
In-Memory Sessions (Default)
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:
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
Features
- 🌐 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
pathtonullto respond everywhere) - 🔧 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
server.ctx.sessionInfo
API
HttpTransport
Constructor
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:
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
}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).
Methods
respond(request: Request, customContext?: T): Promise<Response | null>
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
Protocol Details
HTTP Methods
The transport supports three HTTP methods:
POST - Message Processing
Clients send JSON-RPC messages via HTTP POST requests:
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/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:
GET /mcp HTTP/1.1
mcp-session-id: optional-session-idResponse: Long-lived event stream for server notifications:
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:
DELETE /mcp HTTP/1.1
mcp-session-id: session-to-disconnectResponse:
HTTP/1.1 204 No Content
mcp-session-id: session-to-disconnectSession Management
- 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
Framework Examples
Bun
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;
},
});Deno
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;
});srvx
If you want the same experience across Deno, Bun, and Node.js, you can use srvx.
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;
},
});Error Handling
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
Development
# Install dependencies
pnpm install
# Generate TypeScript declarations
pnpm generate:types
# Lint the code
pnpm lintRequirements
- 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 adapter
Acknowledgments
Huge thanks to Sean O'Bannon that provided us with the @tmcp scope on npm.
License
MIT
