worker.ts
Language TypeScript2.1 KB56 lines
import { McpAgent } from "agents/mcp";import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";import { registerTools, SERVER_INFO } from "./server.js";import { configFromEnv } from "./lib/config.js";import { WorkerRateLimiter } from "./rateLimiterDO.js";import type { Env } from "./env.js";// Re-export so wrangler can bind the shared rate-limiter Durable Object class.export { RateLimiterDO } from "./rateLimiterDO.js";/*** Cloudflare Workers entry point: remote MCP over HTTP, so the whole company* can connect to one hosted server instead of each person running stdio.** Built on the Agents SDK `McpAgent`, which is a Durable Object: each client* session is an isolate-backed instance with its own `this.env`. We register the* SAME read-only tool set as the stdio entry, keeping a single source of truth.** Live requests stay gated (PLINTH_ALLOW_LIVE_REQUESTS) until an operator* deliberately turns them on.*/export class PlinthMcp extends McpAgent<Env> {server = new McpServer(SERVER_INFO);async init(): Promise<void> {registerTools(this.server, {config: configFromEnv(this.env),limiter: new WorkerRateLimiter(this.env.RATE_LIMITER),});}}export default {async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {const url = new URL(request.url);// Streamable HTTP transport (current MCP standard). The Durable Object// binding is named PLINTH_MCP in wrangler.jsonc, not the SDK default MCP_OBJECT.if (url.pathname === "/mcp") {return PlinthMcp.serve("/mcp", { binding: "PLINTH_MCP" }).fetch(request, env, ctx);}// SSE transport (legacy clients).if (url.pathname === "/sse" || url.pathname === "/sse/message") {return PlinthMcp.serveSSE("/sse", { binding: "PLINTH_MCP" }).fetch(request, env, ctx);}if (url.pathname === "/health") {return Response.json({ status: "ok", server: SERVER_INFO });}return new Response("Not found", { status: 404 });},};// Unauthenticated: see "Next steps" in the server README before exposing real data.