fastmcp 3.30.1 → 3.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,8 @@ A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable
19
19
  - [Logging](#logging)
20
20
  - [Error handling](#errors)
21
21
  - [HTTP Streaming](#http-streaming) (with SSE compatibility)
22
+ - [Custom HTTP routes](#custom-http-routes) for REST APIs, webhooks, and admin interfaces
23
+ - [Edge Runtime Support](#edge-runtime-support) for Cloudflare Workers, Deno Deploy, and more
22
24
  - [Stateless mode](#stateless-mode) for serverless deployments
23
25
  - CORS (enabled by default)
24
26
  - [Progress notifications](#progress)
@@ -182,6 +184,210 @@ const transport = new SSEClientTransport(new URL(`http://localhost:8080/sse`));
182
184
  await client.connect(transport);
183
185
  ```
184
186
 
187
+ #### Custom HTTP Routes
188
+
189
+ FastMCP allows you to add custom HTTP routes alongside MCP endpoints, enabling you to build comprehensive HTTP services that include REST APIs, webhooks, admin interfaces, and more - all within the same server process.
190
+
191
+ ```ts
192
+ // Add REST API endpoints
193
+ server.addRoute("GET", "/api/users", async (req, res) => {
194
+ res.json({ users: [] });
195
+ });
196
+
197
+ // Handle path parameters
198
+ server.addRoute("GET", "/api/users/:id", async (req, res) => {
199
+ res.json({
200
+ userId: req.params.id,
201
+ query: req.query, // Access query parameters
202
+ });
203
+ });
204
+
205
+ // Handle POST requests with body parsing
206
+ server.addRoute("POST", "/api/users", async (req, res) => {
207
+ const body = await req.json();
208
+ res.status(201).json({ created: body });
209
+ });
210
+
211
+ // Serve HTML content
212
+ server.addRoute("GET", "/admin", async (req, res) => {
213
+ res.send("<html><body><h1>Admin Panel</h1></body></html>");
214
+ });
215
+
216
+ // Handle webhooks
217
+ server.addRoute("POST", "/webhook/github", async (req, res) => {
218
+ const payload = await req.json();
219
+ const event = req.headers["x-github-event"];
220
+
221
+ // Process webhook...
222
+ res.json({ received: true });
223
+ });
224
+ ```
225
+
226
+ Custom routes support:
227
+
228
+ - All HTTP methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
229
+ - Path parameters (`:param`) and wildcards (`*`)
230
+ - Query string parsing
231
+ - JSON and text body parsing
232
+ - Custom status codes and headers
233
+ - Authentication via the same `authenticate` function as MCP
234
+ - **Public routes** that bypass authentication
235
+
236
+ Routes are matched in the order they are registered, allowing you to define specific routes before catch-all patterns.
237
+
238
+ ##### Public Routes
239
+
240
+ By default, custom routes require authentication (if configured). You can make routes public by adding the `{ public: true }` option:
241
+
242
+ ```ts
243
+ // Public route - no authentication required
244
+ server.addRoute(
245
+ "GET",
246
+ "/.well-known/openid-configuration",
247
+ async (req, res) => {
248
+ res.json({
249
+ issuer: "https://example.com",
250
+ authorization_endpoint: "https://example.com/auth",
251
+ token_endpoint: "https://example.com/token",
252
+ });
253
+ },
254
+ { public: true },
255
+ );
256
+
257
+ // Private route - requires authentication
258
+ server.addRoute("GET", "/api/users", async (req, res) => {
259
+ // req.auth contains authenticated user data
260
+ res.json({ users: [] });
261
+ });
262
+
263
+ // Public static files
264
+ server.addRoute(
265
+ "GET",
266
+ "/public/*",
267
+ async (req, res) => {
268
+ // Serve static files without authentication
269
+ res.send(`File: ${req.url}`);
270
+ },
271
+ { public: true },
272
+ );
273
+ ```
274
+
275
+ Public routes are perfect for:
276
+
277
+ - OAuth discovery endpoints (`.well-known/*`)
278
+ - Health checks and status pages
279
+ - Static assets and documentation
280
+ - Webhook endpoints from external services
281
+ - Public APIs that don't require user authentication
282
+
283
+ See the [custom-routes example](src/examples/custom-routes.ts) for a complete demonstration.
284
+
285
+ #### Edge Runtime Support
286
+
287
+ FastMCP supports edge runtimes like Cloudflare Workers, enabling deployment of MCP servers to the edge with minimal latency worldwide.
288
+
289
+ ##### Choosing Between FastMCP and EdgeFastMCP
290
+
291
+ | Use Case | Class | Import |
292
+ | ------------------------------- | ------------- | -------------------------------------------- |
293
+ | Node.js, Express, Bun | `FastMCP` | `import { FastMCP } from "fastmcp"` |
294
+ | Cloudflare Workers, Deno Deploy | `EdgeFastMCP` | `import { EdgeFastMCP } from "fastmcp/edge"` |
295
+
296
+ | Feature | FastMCP | EdgeFastMCP |
297
+ | -------------------- | ------------------------------ | -------------------------------------- |
298
+ | Runtime | Node.js | Edge (V8 isolates) |
299
+ | Start method | `server.start({ port })` | `export default server` |
300
+ | Transport | stdio, httpStream, SSE | HTTP Streamable only |
301
+ | Sessions | Stateful or stateless | Stateless only |
302
+ | File system | Yes | No |
303
+ | OAuth/Authentication | Built-in `authenticate` option | Use Hono middleware (built-in planned) |
304
+ | Custom routes | `server.getApp()` | `server.getApp()` |
305
+
306
+ > **Note:** Built-in authentication for EdgeFastMCP is planned for a future release. Both FastMCP and EdgeFastMCP use Hono internally, so there's no technical barrier—EdgeFastMCP was simply written before OAuth was added to FastMCP. PRs are welcome to add an `authenticate` option that accepts web `Request` instead of Node.js `http.IncomingMessage`.
307
+ >
308
+ > In the meantime, use Hono middleware:
309
+ >
310
+ > ```ts
311
+ > const app = server.getApp();
312
+ > app.use("/api/*", async (c, next) => {
313
+ > if (c.req.header("authorization") !== "Bearer secret") {
314
+ > return c.json({ error: "Unauthorized" }, 401);
315
+ > }
316
+ > await next();
317
+ > });
318
+ > ```
319
+
320
+ ##### Cloudflare Workers
321
+
322
+ To deploy FastMCP to Cloudflare Workers, use the `EdgeFastMCP` class from the `/edge` subpath:
323
+
324
+ ```ts
325
+ import { EdgeFastMCP } from "fastmcp/edge";
326
+ import { z } from "zod";
327
+
328
+ const server = new EdgeFastMCP({
329
+ name: "My Edge Server",
330
+ version: "1.0.0",
331
+ description: "MCP server running on Cloudflare Workers",
332
+ });
333
+
334
+ // Add tools, resources, prompts as usual
335
+ server.addTool({
336
+ name: "greet",
337
+ description: "Greet someone",
338
+ parameters: z.object({
339
+ name: z.string(),
340
+ }),
341
+ execute: async ({ name }) => {
342
+ return `Hello, ${name}! Served from the edge.`;
343
+ },
344
+ });
345
+
346
+ // Export the server as the default (required for Cloudflare Workers)
347
+ export default server;
348
+ ```
349
+
350
+ ##### Edge Runtime Differences
351
+
352
+ When running on edge runtimes:
353
+
354
+ - **Stateless by default**: Each request is handled independently
355
+ - **No filesystem access**: Use fetch APIs for external data
356
+ - **V8 Isolates**: Fast cold starts and efficient resource usage
357
+ - **Global deployment**: Automatic distribution to edge locations
358
+
359
+ ##### Custom Routes on Edge
360
+
361
+ You can access the underlying Hono app to add custom HTTP routes:
362
+
363
+ ```ts
364
+ const app = server.getApp();
365
+
366
+ // Add a landing page
367
+ app.get("/", (c) => c.html("<h1>Welcome to my MCP server</h1>"));
368
+
369
+ // Add REST API endpoints
370
+ app.get("/api/status", (c) => c.json({ status: "ok" }));
371
+ ```
372
+
373
+ ##### Deployment
374
+
375
+ Configure your `wrangler.toml`:
376
+
377
+ ```toml
378
+ name = "my-mcp-server"
379
+ main = "src/index.ts"
380
+ compatibility_date = "2024-01-01"
381
+ ```
382
+
383
+ Deploy with:
384
+
385
+ ```bash
386
+ wrangler deploy
387
+ ```
388
+
389
+ See the [edge-cloudflare-worker example](src/examples/edge-cloudflare-worker.ts) for a complete demonstration.
390
+
185
391
  #### Stateless Mode
186
392
 
187
393
  FastMCP supports stateless operation for HTTP streaming, where each request is handled independently without maintaining persistent sessions. This is ideal for serverless environments, load-balanced deployments, or when session state isn't required.