Track MCP LogoTrack MCP
Track MCP LogoTrack MCP

The world's largest repository of Model Context Protocol servers. Discover, explore, and submit MCP tools.

Product

  • Categories
  • Top MCP
  • New & Updated
  • Submit MCP

Company

  • About

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy

© 2026 TrackMCP. All rights reserved.

Built with ❤️ by Krishna Goyal

    Express Mcp Handler

    Effortlessly integrate the Model Context Protocol (MCP) into Express with lightweight stateful, stateless, and SSE middleware.

    11 stars
    TypeScript
    Updated Sep 24, 2025

    Table of Contents

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

    Table of Contents

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

    Documentation

    express-mcp-handler

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

    npm version

    npm downloads

    License: MIT

    Node.js Version

    TypeScript

    CI

    codecov

    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:

    bash
    npm install express-mcp-handler

    Or yarn:

    bash
    yarn add express-mcp-handler

    Or pnpm:

    bash
    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:

    bash
    npm install express @modelcontextprotocol/sdk zod

    Quick Start

    Here's a basic example to get you started:

    ts
    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:

    ts
    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:

    ts
    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:

    ts
    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

    ts
    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

    ts
    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

    ts
    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:

    ts
    // 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.

    ts
    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:

    bash
    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:

    bash
    npm login

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

    bash
    npm publish

    To bump, tag, and push a new version:

    bash
    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.

    Similar MCP

    Based on tags & features

    • ME

      Metmuseum Mcp

      TypeScript·
      14
    • MC

      Mcp Server Aws Sso

      TypeScript·
      6
    • MC

      Mcp Ipfs

      TypeScript·
      11
    • LI

      Liveblocks Mcp Server

      TypeScript·
      11

    Trending MCP

    Most active this week

    • PL

      Playwright Mcp

      TypeScript·
      22.1k
    • SE

      Serena

      Python·
      14.5k
    • MC

      Mcp Playwright

      TypeScript·
      4.9k
    • MC

      Mcp Server Cloudflare

      TypeScript·
      3.0k
    View All MCP Servers

    Similar MCP

    Based on tags & features

    • ME

      Metmuseum Mcp

      TypeScript·
      14
    • MC

      Mcp Server Aws Sso

      TypeScript·
      6
    • MC

      Mcp Ipfs

      TypeScript·
      11
    • LI

      Liveblocks Mcp Server

      TypeScript·
      11

    Trending MCP

    Most active this week

    • PL

      Playwright Mcp

      TypeScript·
      22.1k
    • SE

      Serena

      Python·
      14.5k
    • MC

      Mcp Playwright

      TypeScript·
      4.9k
    • MC

      Mcp Server Cloudflare

      TypeScript·
      3.0k