A clean template for building Model Context Protocol (MCP) servers that integrate with Express applications via HTTP Streamable transport.
This template provides an MCP server handler module that can be integrated into an Express application. It handles HTTP streamable MCP requests with Server-Sent Events (SSE) transport.
Important: This is not a standalone server - it's a handler module that you integrate into your Express application at a specific endpoint.
- 🚀 MCP Protocol Implementation - Full support for tools, prompts, resources, and sampling
- 📝 TypeScript - Type-safe development with full TypeScript support
- 🔧 Example Implementations - Sample tool, prompt, and resource handlers
- 🏗️ Clean Architecture - Well-organized code structure for easy extension
- 🔌 HTTP Streamable Transport - SSE-based communication for MCP clients
- 🔒 Authentication Ready - Designed to work with your authentication middleware
npm install @systemprompt/mcp-server-template
import express from 'express';
import { createMCPHandler } from '@systemprompt/mcp-server-template';
const app = express();
// Create the MCP handler
const mcpHandler = createMCPHandler();
// Add your authentication middleware
const authMiddleware = (req, res, next) => {
// Your authentication logic here
// Verify tokens, API keys, etc.
if (!isAuthenticated(req)) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
};
// Mount the MCP handler at your desired endpoint
app.all('/mcp', authMiddleware, mcpHandler);
app.listen(3000, () => {
console.log('Server with MCP endpoint running on port 3000');
});
import express from 'express';
import { createMCPHandler as createTemplateHandler } from '@systemprompt/mcp-server-template';
import { createMCPHandler as createCustomHandler } from './my-custom-mcp';
const app = express();
// Mount different MCP servers at different endpoints
app.all('/mcp/template', authMiddleware, createTemplateHandler());
app.all('/mcp/custom', authMiddleware, createCustomHandler());
src/
├── index.ts # Module exports
├── server/
│ ├── mcp.ts # MCP handler factory
│ └── config.ts # Server configuration
├── handlers/
│ ├── tool-handlers.ts # Tool request handlers
│ ├── prompt-handlers.ts # Prompt handlers
│ ├── resource-handlers.ts# Resource handlers
│ ├── sampling.ts # Sampling handler
│ └── tools/ # Individual tool implementations
├── constants/
│ ├── tools.ts # Tool definitions
│ ├── prompts.ts # Prompt definitions
│ └── resources.ts # Resource definitions
└── utils/
└── logger.ts # Logging utility
Edit src/constants/tools.ts
:
export const MY_TOOL: Tool = {
name: 'my_tool',
description: 'Description of what my tool does',
inputSchema: {
type: 'object',
properties: {
param1: { type: 'string', description: 'Parameter description' },
param2: { type: 'number', description: 'Another parameter' },
},
required: ['param1'],
},
};
export const TOOLS: Tool[] = [
MY_TOOL,
// ... other tools
];
Create src/handlers/tools/my-tool.ts
:
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
export interface MyToolArgs {
param1: string;
param2?: number;
}
export async function handleMyTool(args: MyToolArgs): Promise<CallToolResult> {
// Your tool implementation
const result = await performOperation(args.param1, args.param2);
return {
content: [
{
type: 'text',
text: `Result: ${result}`,
},
],
};
}
Define resources in src/constants/resources.ts
:
export const RESOURCES: Resource[] = [
{
uri: "myapp://config",
name: "My App Configuration",
description: "Current configuration settings",
mimeType: "application/json",
},
];
Add prompts in src/constants/prompts.ts
:
export const PROMPTS: Prompt[] = [
{
name: 'analyze_data',
description: 'Analyze data and provide insights',
arguments: [
{
name: 'data_type',
description: 'Type of data to analyze',
required: true,
},
],
},
];
The MCP handler expects authenticated requests. You must implement authentication in your Express middleware before requests reach the MCP handler.
Example authentication patterns:
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token || !isValidToken(token)) {
return res.status(401).json({ error: 'Invalid token' });
}
req.user = getUserFromToken(token);
next();
};
const authMiddleware = (req, res, next) => {
const apiKey = req.headers['x-api-key'];
if (!apiKey || !isValidApiKey(apiKey)) {
return res.status(401).json({ error: 'Invalid API key' });
}
next();
};
The template includes comprehensive E2E tests. To run tests against your MCP server:
- Start your Express server with the MCP handler mounted
- Set up test environment:
cd e2e-test npm install
- Configure test endpoint:
echo "MCP_BASE_URL=http://localhost:3000" > .env echo "MCP_ACCESS_TOKEN=your-test-token" >> .env
- Run tests:
npm test
Environment variables in .env
:
SERVER_NAME=my-mcp-server
SERVER_VERSION=1.0.0
LOG_LEVEL=info
To use your MCP server with Claude Desktop or other MCP clients:
{
"mcpServers": {
"my-server": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer your-token-here"
}
}
}
}
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
For questions and support, please open an issue on GitHub.