A unified MCP (Model Context Protocol) server with pluggable tools.
MCP Server
A unified MCP (Model Context Protocol) server with pluggable tools. Each tool has an independent endpoint, allowing clients to selectively add specific tools.
Features
- Unified Endpoint with Path Routing: Each tool has its own MCP endpoint (
/mcp/{toolName}) - Loosely Coupled Tools: Tools are independently loaded from
src/tools/directory - Fault Isolation: Individual tool failures don't affect other tools (timeout protection + error handling)
- StreamableHTTP Transport: Modern MCP transport protocol
- Bearer Token Authentication: Secure API access
- Docker Support: Ready for containerized deployment
Project Structure
mcp_server/
├── src/
│ ├── index.ts # Entry point
│ ├── core/
│ │ ├── tool-registry.ts # Tool registry
│ │ ├── tool-loader.ts # Dynamic tool loader
│ │ └── tool-executor.ts # Isolated executor (timeout + error handling)
│ ├── server/
│ │ ├── app.ts # Express + StreamableHTTP
│ │ └── mcp-server.ts # MCP Server instance
│ ├── middleware/
│ │ └── auth.ts # Bearer token authentication
│ ├── tools/ # Loosely coupled tools directory
│ │ ├── calculator/index.ts # Calculator tool (add/subtract/multiply/divide)
│ │ ├── echo/index.ts # Echo tool (echo/reverse/info)
│ │ └── time/index.ts # Time tool (get_current_time/convert_time/format_time)
│ ├── types/mcp.ts # Type definitions
│ └── utils/logger.ts # Terminal logger
├── Dockerfile # Multi-stage build
├── docker-compose.yml
├── package.json
└── tsconfig.json
Quick Start
Local Development
# Install dependencies
npm install
# Create .env file
echo "AUTHORIZATION_KEY=your-secret-key" > .env
# Start development server
npm run dev
Docker Deployment
# Build and run with docker-compose
docker-compose up -d --build
# Or build manually
docker build -t mcp-server .
docker run -e AUTHORIZATION_KEY=your-secret-key -p 3000:3000 mcp-server
API Endpoints
| Endpoint | Method | Description |
| ----------------- | ------ | -------------------------------------------- |
| /mcp/{toolName} | POST | MCP JSON-RPC request for specific tool |
| /mcp/{toolName} | GET | SSE connection (requires session-id) |
| /mcp/{toolName} | DELETE | Close session |
| /health | GET | Health check |
| /tools | GET | List all available tools and their endpoints |
Available Tools
Calculator (/mcp/calculator)
Math expression evaluator supporting various operators and functions.
| Method | Description | Parameters |
| ---------- | ------------------------------ | ---------------------- |
| evaluate | Evaluate a math expression | expression: string |
Supported Operators:
- Arithmetic:
+,-,*,/ - Floor Division:
// - Modulo:
% - Power:
**or^
Supported Constants: pi, e
Supported Functions: sin, cos, tan, sqrt, abs, log, log10, exp, floor, ceil, round, pow, min, max
Examples:
2 + 3 * 4 → 14
(2 + 3) * 4 → 20
2^10 → 1024
sqrt(16) → 4
2 * pi → 6.283...
sin(0) → 0
pow(2, 8) → 256
17 // 5 → 3
17 % 5 → 2
Echo (/mcp/echo)
Echo tool for testing and debugging.
| Method | Description | Parameters |
| --------- | --------------------------- | ----------------- |
| echo | Echo back the input message | message: string |
| reverse | Reverse the input string | text: string |
| info | Get server information | - |
Time (/mcp/time)
Time tool for timezone conversion and formatting.
| Method | Description | Parameters |
| ------------------ | --------------------------------------- | ---------------------------------------------------------------------------- |
| get_current_time | Get current time in a specific timezone | timezone: string (default: "Etc/UTC") |
| convert_time | Convert time between timezones | source_timezone: string, target_timezone: string, time: string (HH:MM) |
| format_time | Convert timestamp to formatted string | timestamp: number (ms), timezone: string |
Client Configuration
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"calculator": {
"url": "http://localhost:3000/mcp/calculator",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer your-secret-key"
}
},
"time": {
"url": "http://localhost:3000/mcp/time",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer your-secret-key"
}
}
}
}
Cursor / VS Code
Create .cursor/mcp.json in project root:
{
"mcpServers": {
"calculator": {
"url": "http://localhost:3000/mcp/calculator",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer your-secret-key"
}
}
}
}
Programmatic Usage (Node.js)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({
name: "my-client",
version: "1.0.0",
});
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:3000/mcp/calculator"),
{
requestInit: {
headers: {
Authorization: "Bearer your-secret-key",
},
},
}
);
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log(tools);
// Call a tool
const result = await client.callTool({
name: "add",
arguments: { a: 10, b: 5 },
});
console.log(result);
Adding New Tools
- Create a new directory under
src/tools/:
src/tools/my-tool/
└── index.ts
- Implement the
MCPToolinterface:
import { z } from "zod";
import { MCPTool, MCPMethodDefinition } from "../../types/mcp.js";
const myTool: MCPTool = {
name: "my-tool",
description: "Description of my tool",
version: "1.0.0",
getMethods(): MCPMethodDefinition[] {
return [
{
name: "my-method",
description: "Description of my method",
inputSchema: {
param1: z.string().describe("Parameter description"),
},
handler: async (params) => {
const { param1 } = params as { param1: string };
return { result: param1 };
},
},
];
},
async initialize() {
// Initialization logic
},
async healthCheck() {
return true;
},
};
export default myTool;
- The tool will be automatically loaded on server startup.
Scripts
npm run dev # Start development server with hot reload
npm run build # Build for production
npm start # Start production server
npm test # Run tests
npm run lint # Check code style
npm run lint:fix # Auto-fix code style issues
License
MIT