fastmcp 4.7.0 → 4.7.1

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.
Files changed (2) hide show
  1. package/README.md +68 -47
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -267,87 +267,108 @@ The `CorsOptions` type is exported from `fastmcp` for convenience.
267
267
  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.
268
268
 
269
269
  ```ts
270
- // Add REST API endpoints
271
- server.addRoute("GET", "/api/users", async (req, res) => {
272
- res.json({ users: [] });
270
+ const app = server.getApp();
271
+
272
+ // Add REST API endpoints with Hono's native API
273
+ app.get("/api/users", async (c) => {
274
+ return c.json({ users: [] });
273
275
  });
274
276
 
275
277
  // Handle path parameters
276
- server.addRoute("GET", "/api/users/:id", async (req, res) => {
277
- res.json({
278
- userId: req.params.id,
279
- query: req.query, // Access query parameters
278
+ app.get("/api/users/:id", async (c) => {
279
+ return c.json({
280
+ userId: c.req.param("id"),
281
+ query: c.req.query(), // Access query parameters
280
282
  });
281
283
  });
282
284
 
283
285
  // Handle POST requests with body parsing
284
- server.addRoute("POST", "/api/users", async (req, res) => {
285
- const body = await req.json();
286
- res.status(201).json({ created: body });
286
+ app.post("/api/users", async (c) => {
287
+ const body = await c.req.json();
288
+ return c.json({ created: body }, 201);
287
289
  });
288
290
 
289
291
  // Serve HTML content
290
- server.addRoute("GET", "/admin", async (req, res) => {
291
- res.send("<html><body><h1>Admin Panel</h1></body></html>");
292
+ app.get("/admin", async (c) => {
293
+ return c.html("<html><body><h1>Admin Panel</h1></body></html>");
292
294
  });
293
295
 
294
296
  // Handle webhooks
295
- server.addRoute("POST", "/webhook/github", async (req, res) => {
296
- const payload = await req.json();
297
- const event = req.headers["x-github-event"];
297
+ app.post("/webhook/github", async (c) => {
298
+ const payload = await c.req.json();
299
+ const event = c.req.header("x-github-event");
298
300
 
299
301
  // Process webhook...
300
- res.json({ received: true });
302
+ return c.json({ received: true });
301
303
  });
302
304
  ```
303
305
 
304
- Custom routes support:
306
+ Custom routes use the underlying [Hono](https://hono.dev/) app returned by `server.getApp()` and support:
305
307
 
306
- - All HTTP methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
308
+ - Hono's HTTP methods: `get`, `post`, `put`, `delete`, `patch`, `options`, and more
307
309
  - Path parameters (`:param`) and wildcards (`*`)
308
310
  - Query string parsing
309
- - JSON and text body parsing
311
+ - JSON, text, form, and other body helpers from `c.req`
310
312
  - Custom status codes and headers
311
- - Authentication via the same `authenticate` function as MCP
312
- - **Public routes** that bypass authentication
313
+ - Middleware and route groups through Hono
313
314
 
314
315
  Routes are matched in the order they are registered, allowing you to define specific routes before catch-all patterns.
315
316
 
316
- ##### Public Routes
317
+ ##### Public and Protected Routes
317
318
 
318
- By default, custom routes require authentication (if configured). You can make routes public by adding the `{ public: true }` option:
319
+ Custom Hono routes are public unless you add your own route middleware or authentication checks. For protected custom routes, put your auth logic in a reusable helper and call it from both FastMCP's `authenticate` option and your Hono route handlers:
319
320
 
320
321
  ```ts
322
+ import type { IncomingMessage } from "node:http";
323
+ import type { Context } from "hono";
324
+ import { FastMCP } from "fastmcp";
325
+
326
+ async function authenticateRequest(request: IncomingMessage) {
327
+ const apiKey = request.headers["x-api-key"];
328
+ return apiKey === "123" ? { userId: "123" } : undefined;
329
+ }
330
+
331
+ const server = new FastMCP({
332
+ name: "My Server",
333
+ version: "1.0.0",
334
+ authenticate: authenticateRequest,
335
+ });
336
+
337
+ const app = server.getApp();
338
+
339
+ async function requireAuth(c: Context) {
340
+ const auth = await authenticateRequest(c.env.incoming);
341
+
342
+ if (!auth) {
343
+ return c.json({ error: "Authentication required" }, 401);
344
+ }
345
+
346
+ return auth;
347
+ }
348
+
321
349
  // Public route - no authentication required
322
- server.addRoute(
323
- "GET",
324
- "/.well-known/openid-configuration",
325
- async (req, res) => {
326
- res.json({
327
- issuer: "https://example.com",
328
- authorization_endpoint: "https://example.com/auth",
329
- token_endpoint: "https://example.com/token",
330
- });
331
- },
332
- { public: true },
333
- );
350
+ app.get("/.well-known/openid-configuration", async (c) => {
351
+ return c.json({
352
+ issuer: "https://example.com",
353
+ authorization_endpoint: "https://example.com/auth",
354
+ token_endpoint: "https://example.com/token",
355
+ });
356
+ });
334
357
 
335
358
  // Private route - requires authentication
336
- server.addRoute("GET", "/api/users", async (req, res) => {
337
- // req.auth contains authenticated user data
338
- res.json({ users: [] });
359
+ app.get("/api/users", async (c) => {
360
+ const auth = await requireAuth(c);
361
+ if (auth instanceof Response) {
362
+ return auth;
363
+ }
364
+
365
+ return c.json({ users: [] });
339
366
  });
340
367
 
341
368
  // Public static files
342
- server.addRoute(
343
- "GET",
344
- "/public/*",
345
- async (req, res) => {
346
- // Serve static files without authentication
347
- res.send(`File: ${req.url}`);
348
- },
349
- { public: true },
350
- );
369
+ app.get("/public/*", async (c) => {
370
+ return c.text(`File: ${c.req.path}`);
371
+ });
351
372
  ```
352
373
 
353
374
  Public routes are perfect for:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastmcp",
3
- "version": "4.7.0",
3
+ "version": "4.7.1",
4
4
  "main": "dist/FastMCP.js",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -55,7 +55,7 @@
55
55
  "zod-to-json-schema": "^3.25.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "jose": "^5.0.0"
58
+ "jose": "^5.0.0 || ^6.0.0"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "jose": {