103 lines
2.4 KiB
TypeScript
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 };
|