Files
gh-jezweb-claude-skills-ski…/templates/basic-mcp-server.ts
2025-11-30 08:25:43 +08:00

103 lines
2.4 KiB
TypeScript

/**
* Basic MCP Server Template
*
* A minimal Model Context Protocol server with a simple echo tool.
* Deploy to Cloudflare Workers for serverless MCP endpoint.
*
* Setup:
* 1. npm install @modelcontextprotocol/sdk hono zod
* 2. npm install -D @cloudflare/workers-types wrangler typescript
* 3. wrangler deploy
*
* Test locally:
* - wrangler dev
* - npx @modelcontextprotocol/inspector (connect to http://localhost:8787/mcp)
*/
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { Hono } from 'hono';
import { z } from 'zod';
// Define environment type (add your bindings here)
type Env = {
// Example: D1 database
// DB: D1Database;
// KV namespace
// CACHE: KVNamespace;
};
// Initialize MCP server
const server = new McpServer({
name: 'basic-mcp-server',
version: '1.0.0'
});
// Register a simple echo tool
server.registerTool(
'echo',
{
description: 'Echoes back the input text',
inputSchema: z.object({
text: z.string().describe('Text to echo back')
})
},
async ({ text }) => ({
content: [{ type: 'text', text }]
})
);
// Register an addition tool
server.registerTool(
'add',
{
description: 'Adds two numbers together',
inputSchema: z.object({
a: z.number().describe('First number'),
b: z.number().describe('Second number')
})
},
async ({ a, b }) => ({
content: [{
type: 'text',
text: `The sum of ${a} and ${b} is ${a + b}`
}]
})
);
// HTTP endpoint setup with Hono
const app = new Hono<{ Bindings: Env }>();
// Health check endpoint
app.get('/', (c) => {
return c.json({
name: 'basic-mcp-server',
version: '1.0.0',
status: 'running',
mcp_endpoint: '/mcp'
});
});
// MCP endpoint
app.post('/mcp', async (c) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
});
// CRITICAL: Close transport on response end to prevent memory leaks
c.res.raw.on('close', () => transport.close());
await server.connect(transport);
await transport.handleRequest(c.req.raw, c.res.raw, await c.req.json());
return c.body(null);
});
// CRITICAL: Use direct export (not object wrapper)
// ✅ CORRECT:
export default app;
// ❌ WRONG (causes build errors):
// export default { fetch: app.fetch };