Express MCP Handler

by jhgaylor

Integrations

  • Provides integration with Express, allowing developers to easily add Model Context Protocol (MCP) capabilities to Express applications with both stateful session management and stateless request handling options.

express-mcp-handler

A middleware for integrating Model Context Protocol (MCP) with Express applications, enabling seamless communication between LLMs and tools.

What is Model Context Protocol (MCP)?

Model Context Protocol (MCP) is an open protocol for integrating large language models (LLMs) with external data sources and tools. It enables AI assistants to access real-time data, execute operations, and interact with various services through a standardized interface.

Features

  • Stateful Handler: Can handle one off requests or maintain long-lived sessions with session IDs and Server-Sent Events (SSE).
  • Stateless Handler: Handles each request in complete isolation for simple, one-off interactions.
  • SSE Handler: Handles Model Context Protocol (MCP) over Server-Sent Events (SSE) with dedicated GET and POST endpoints.
  • Type-Safe API: Built with TypeScript for reliable integration.
  • Flexible Configuration: Customizable error handling, session management, and lifecycle hooks.
  • Express Integration: Plugs directly into Express routes with middleware pattern.

Installation

Install via npm:

npm install express-mcp-handler

Or yarn:

yarn add express-mcp-handler

Or pnpm:

pnpm add express-mcp-handler

Peer Dependencies

This package requires the following peer dependencies:

  • express >= 4.0.0
  • @modelcontextprotocol/sdk >= 1.10.2
  • zod >= 3.0.0

Install them if you haven't already:

npm install express @modelcontextprotocol/sdk zod

Quick Start

Here's a basic example to get you started:

import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { statelessHandler } from 'express-mcp-handler'; const app = express(); app.use(express.json()); // Create a factory function that returns a new McpServer instance for each request const serverFactory = () => new McpServer({ name: 'my-mcp-server', version: '1.0.0', }); // Mount the stateless handler app.post('/mcp', statelessHandler(serverFactory)); app.listen(3000, () => { console.log('Express MCP server running on port 3000'); });

Usage

Express-mcp-handler provides three handler types to suit different use cases:

Stateful Mode

Use statefulHandler to establish reusable sessions between client and server, ideal for maintaining context across multiple interactions:

import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { statefulHandler } from 'express-mcp-handler'; import { randomUUID } from 'node:crypto'; const app = express(); app.use(express.json()); // Create an MCP server instance const server = new McpServer({ name: 'my-server', version: '1.0.0', }); // Configure handler options const handlerOptions = { sessionIdGenerator: randomUUID, // Function to generate unique session IDs onSessionInitialized: (sessionId: string) => { console.log(`Session initialized: ${sessionId}`); // You could store session metadata or initialize resources here }, onSessionClosed: (sessionId: string) => { console.log(`Session closed: ${sessionId}`); // Perform cleanup logic here }, onError: (error: Error, sessionId?: string) => { console.error(`Error in session ${sessionId}:`, error); // Handle errors for monitoring or logging } }; // Mount the handlers for different HTTP methods app.post('/mcp', statefulHandler(server, handlerOptions)); app.get('/mcp', statefulHandler(server, handlerOptions)); app.delete('/mcp', statefulHandler(server, handlerOptions)); app.listen(3000, () => { console.log('Express MCP server running on port 3000'); });

The stateful handler:

  • Initializes a new session on the first request (with no mcp-session-id header)
  • Returns a mcp-session-id header that clients must include in subsequent requests
  • Manages Server-Sent Events (SSE) to push messages from the server to the client
  • Automatically cleans up sessions when closed

Stateless Mode

Use statelessHandler for one-off request handling with no session management, perfect for serverless environments or simple requests:

import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { statelessHandler } from 'express-mcp-handler'; const app = express(); app.use(express.json()); // Function that creates a fresh McpServer for each request const serverFactory = () => new McpServer({ name: 'stateless-mcp-server', version: '1.0.0', }); // Configure with custom error handling const options = { onError: (error: Error) => { console.error('MCP error:', error); // Add custom error reporting logic here } }; app.post('/mcp', statelessHandler(serverFactory, options)); app.listen(3000, () => { console.log('Express Stateless MCP server running on port 3000'); });

Each stateless request:

  • Creates a fresh transport and server instance
  • Ensures complete isolation with no session tracking
  • Is suitable for simple or serverless environments

SSE Mode

Use sseHandlers to handle Model Context Protocol (MCP) over Server-Sent Events (SSE), ideal for real-time streaming responses:

import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { sseHandlers } from 'express-mcp-handler'; const app = express(); app.use(express.json()); // Provide a factory function that returns a fresh McpServer for each SSE connection const serverFactory = () => new McpServer({ name: 'sse-mcp-server', version: '1.0.0', }); // Configure SSE handlers const handlers = sseHandlers(serverFactory, { onError: (error: Error, sessionId?: string) => { console.error(`[SSE][${sessionId || 'unknown'}]`, error); }, onClose: (sessionId: string) => { console.log(`[SSE] transport closed: ${sessionId}`); // Clean up any session resources }, }); // Mount the SSE endpoints app.get('/sse', handlers.getHandler); app.post('/messages', handlers.postHandler); app.listen(3002, () => { console.log('Express MCP SSE server running on port 3002'); });

SSE handlers provide:

  • GET /sse: Establishes the SSE stream and returns a mcp-session-id header
  • POST /messages: Sends MCP messages over the SSE transport using the mcp-session-id query parameter

API Reference

statefulHandler

function statefulHandler( server: McpServer, options: { sessionIdGenerator: () => string; onSessionInitialized?: (sessionId: string) => void; onSessionClosed?: (sessionId: string) => void; onError?: (error: Error, sessionId?: string) => void; onInvalidSession?: (req: express.Request) => void; } ): express.RequestHandler;
ParameterTypeDescription
serverMcpServerInstance of McpServer to handle protocol logic
options.sessionIdGenerator() => stringFunction that returns a unique session ID
options.onSessionInitialized(sessionId: string) => void(optional) Callback invoked with the new session ID
options.onSessionClosed(sessionId: string) => void(optional) Callback invoked when a session is closed
options.onError(error: Error, sessionId?: string) => void(optional) Callback invoked on errors
options.onInvalidSession(req: express.Request) => void(optional) Callback invoked when an invalid session is accessed

statelessHandler

function statelessHandler( serverFactory: () => McpServer, options?: { sessionIdGenerator?: () => string; onClose?: (req: express.Request, res: express.Response) => void; onError?: (error: Error) => void; } ): express.RequestHandler;
ParameterTypeDescription
serverFactory() => McpServerFunction that returns a new server instance for each request
options.sessionIdGenerator() => string(optional) Override transport session ID generation
options.onClose(req: express.Request, res: express.Response) => void(optional) Callback fired when the request/response cycle ends
options.onError(error: Error) => void(optional) Callback fired on errors during handling

sseHandlers

function sseHandlers( serverFactory: ServerFactory, options: SSEHandlerOptions ): { getHandler: express.RequestHandler; postHandler: express.RequestHandler; };
ParameterTypeDescription
serverFactoryServerFactoryFactory function that returns a fresh McpServer for each SSE connection
options.onError(error: Error, sessionId?: string) => void(optional) Callback invoked on errors, receives error and optional sessionId
options.onClose(sessionId: string) => void(optional) Callback invoked when an SSE session is closed, receives sessionId

Error Handling

All handler types support custom error handling through their options:

// Example of custom error handling for stateful handler const handlerOptions = { // ... other options onError: (error: Error, sessionId?: string) => { console.error(`Error in session ${sessionId}:`, error); // Send error to monitoring service Sentry.captureException(error, { extra: { sessionId } }); } };

TypeScript Support

This package is written in TypeScript and provides type definitions for all exports. When using TypeScript, you'll get full IntelliSense and type checking.

import { statefulHandler, StatefulHandlerOptions } from 'express-mcp-handler'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; // Type-safe options const options: StatefulHandlerOptions = { sessionIdGenerator: () => Date.now().toString(), onError: (error, sessionId) => { // TypeScript knows the types of these parameters console.error(`Error in session ${sessionId}:`, error); } }; const server = new McpServer({ name: 'typed-server', version: '1.0.0', }); // Type-safe handler app.post('/mcp', statefulHandler(server, options));

Development

To contribute to this project:

git clone https://github.com/jhgaylor/express-mcp-handler.git cd express-mcp-handler npm install npm run build npm test

Test Coverage

The project has solid test coverage and promises to maintain it.

All changes are verified through our CI/CD pipeline using Jest for testing and Codecov for coverage reporting.

Continuous Integration

This project uses GitHub Actions for continuous integration. Every push to the main branch and pull request will:

  1. Run the lint check
  2. Build the project
  3. Run tests with coverage
  4. Upload coverage reports to Codecov

You can view the current CI status in the badge at the top of this README or on the Actions tab of the GitHub repository.

License

MIT License

Publishing to npm

Log in to npm if you haven't already:

npm login

Publish the package to npm (will run your prepublishOnly build):

npm publish

To bump, tag, and push a new version:

npm version patch # or minor, major git push origin main --tags

Handler Types at a Glance

HandlerScenarioSessionsStreaming
statelessHandlerOne-off or serverless workloadsNoNo
statefulHandlerMulti-turn interactionsYesYes
sseHandlersReal-time SSE streamingYesYes

Troubleshooting

Missing mcp-session-id header
Ensure the client includes the mcp-session-id header returned on the initial request.

Transport connection closed prematurely
Verify network connectivity and ensure the client properly handles SSE events.

Changelog

All notable changes to this project are documented in the CHANGELOG.md.

-
security - not tested
F
license - not found
-
quality - not tested

remote-capable server

The server can be hosted and run remotely because it primarily relies on remote services or has no dependency on the local environment.

A utility that integrates Model Context Protocol (MCP) into Express applications, offering both stateful session management and stateless request handling options.

  1. What is Model Context Protocol (MCP)?
    1. Features
      1. Installation
        1. Peer Dependencies
      2. Quick Start
        1. Usage
          1. Stateful Mode
          2. Stateless Mode
          3. SSE Mode
        2. API Reference
          1. statefulHandler
          2. statelessHandler
          3. sseHandlers
        3. Error Handling
          1. TypeScript Support
            1. Development
              1. Test Coverage
              2. Continuous Integration
            2. License
              1. Publishing to npm
                1. Handler Types at a Glance
                  1. Troubleshooting
                    1. Changelog

                      Related MCP Servers

                      • -
                        security
                        A
                        license
                        -
                        quality
                        MCP Server simplifies the implementation of the Model Context Protocol by providing a user-friendly API to create custom tools and manage server workflows efficiently.
                        Last updated -
                        4
                        3
                        TypeScript
                        MIT License
                      • -
                        security
                        A
                        license
                        -
                        quality
                        MCP Server provides a simpler API to interact with the Model Context Protocol by allowing users to define custom tools and services to streamline workflows and processes.
                        Last updated -
                        13
                        2
                        TypeScript
                        MIT License
                      • A
                        security
                        A
                        license
                        A
                        quality
                        A Model Context Protocol (MCP) server that provides tools for managing todo items, including creation, updating, completion, deletion, searching, and summarizing tasks.
                        Last updated -
                        10
                        4
                        TypeScript
                        MIT License
                      • A
                        security
                        F
                        license
                        A
                        quality
                        A Model Context Protocol (MCP) server that provides a simple sleep/wait tool, useful for adding delays between operations such as waiting between API calls or testing eventually consistent systems.
                        Last updated -
                        1
                        6
                        7
                        JavaScript

                      View all related MCP servers

                      ID: sn20luzb4s