fastmcp 3.19.2 → 3.20.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/.roo/mcp.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "context7": {
4
+ "command": "npx",
5
+ "args": ["-y", "@upstash/context7-mcp"],
6
+ "env": {
7
+ "DEFAULT_MINIMUM_TOKENS": ""
8
+ }
9
+ }
10
+ }
11
+ }
package/README.md CHANGED
@@ -11,6 +11,7 @@ A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable
11
11
  - Simple Tool, Resource, Prompt definition
12
12
  - [Authentication](#authentication)
13
13
  - [Passing headers through context](#passing-headers-through-context)
14
+ - [Session ID and Request ID tracking](#session-id-and-request-id-tracking)
14
15
  - [Sessions](#sessions)
15
16
  - [Image content](#returning-an-image)
16
17
  - [Audio content](#returning-an-audio)
@@ -1529,6 +1530,88 @@ Tool result: {
1529
1530
  }
1530
1531
  ```
1531
1532
 
1533
+ #### Session ID and Request ID Tracking
1534
+
1535
+ FastMCP automatically exposes session and request IDs to tool handlers through the context parameter. This enables per-session state management and request tracking.
1536
+
1537
+ **Session ID** (`context.sessionId`):
1538
+
1539
+ - Available only for HTTP-based transports (HTTP Stream, SSE)
1540
+ - Extracted from the `Mcp-Session-Id` header
1541
+ - Remains constant across multiple requests from the same client
1542
+ - Useful for maintaining per-session state, counters, or user-specific data
1543
+
1544
+ **Request ID** (`context.requestId`):
1545
+
1546
+ - Available for all transports when provided by the client
1547
+ - Unique for each individual request
1548
+ - Useful for request tracing and debugging
1549
+
1550
+ ```ts
1551
+ import { FastMCP } from "fastmcp";
1552
+ import { z } from "zod";
1553
+
1554
+ const server = new FastMCP({
1555
+ name: "Session Counter Server",
1556
+ version: "1.0.0",
1557
+ });
1558
+
1559
+ // Per-session counter storage
1560
+ const sessionCounters = new Map<string, number>();
1561
+
1562
+ server.addTool({
1563
+ name: "increment_counter",
1564
+ description: "Increment a per-session counter",
1565
+ parameters: z.object({}),
1566
+ execute: async (args, context) => {
1567
+ if (!context.sessionId) {
1568
+ return "Session ID not available (requires HTTP transport)";
1569
+ }
1570
+
1571
+ const counter = sessionCounters.get(context.sessionId) || 0;
1572
+ const newCounter = counter + 1;
1573
+ sessionCounters.set(context.sessionId, newCounter);
1574
+
1575
+ return `Counter for session ${context.sessionId}: ${newCounter}`;
1576
+ },
1577
+ });
1578
+
1579
+ server.addTool({
1580
+ name: "show_ids",
1581
+ description: "Display session and request IDs",
1582
+ parameters: z.object({}),
1583
+ execute: async (args, context) => {
1584
+ return `Session ID: ${context.sessionId || "N/A"}
1585
+ Request ID: ${context.requestId || "N/A"}`;
1586
+ },
1587
+ });
1588
+
1589
+ server.start({
1590
+ transportType: "httpStream",
1591
+ httpStream: {
1592
+ port: 8080,
1593
+ },
1594
+ });
1595
+ ```
1596
+
1597
+ **Use Cases:**
1598
+
1599
+ - **Per-session state management**: Maintain counters, caches, or temporary data unique to each client session
1600
+ - **User authentication and authorization**: Track authenticated users across requests
1601
+ - **Session-specific resource management**: Allocate and manage resources per session
1602
+ - **Multi-tenant implementations**: Isolate data and operations by session
1603
+ - **Request tracing**: Track individual requests for debugging and monitoring
1604
+
1605
+ **Example:**
1606
+
1607
+ See [`src/examples/session-id-counter.ts`](src/examples/session-id-counter.ts) for a complete example demonstrating session-based counter management.
1608
+
1609
+ **Notes:**
1610
+
1611
+ - Session IDs are automatically generated by the MCP transport layer
1612
+ - In stateless mode, session IDs are not persisted across requests
1613
+ - For stdio transport, `sessionId` will be `undefined` as there's no HTTP session concept
1614
+
1532
1615
  ### Providing Instructions
1533
1616
 
1534
1617
  You can provide instructions to the server using the `instructions` option:
package/dist/FastMCP.d.ts CHANGED
@@ -62,7 +62,19 @@ type Context<T extends FastMCPSessionAuth> = {
62
62
  warn: (message: string, data?: SerializableValue) => void;
63
63
  };
64
64
  reportProgress: (progress: Progress) => Promise<void>;
65
+ /**
66
+ * Request ID from the current MCP request.
67
+ * Available for all transports when the client provides it.
68
+ */
69
+ requestId?: string;
65
70
  session: T | undefined;
71
+ /**
72
+ * Session ID from the Mcp-Session-Id header.
73
+ * Only available for HTTP-based transports (SSE, HTTP Stream).
74
+ * Can be used to track per-session state, implement session-specific
75
+ * counters, or maintain user-specific data across multiple requests.
76
+ */
77
+ sessionId?: string;
66
78
  streamContent: (content: Content | Content[]) => Promise<void>;
67
79
  };
68
80
  type Extra = unknown;
@@ -549,7 +561,9 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
549
561
  get loggingLevel(): LoggingLevel;
550
562
  get roots(): Root[];
551
563
  get server(): Server;
552
- constructor({ auth, instructions, logger, name, ping, prompts, resources, resourcesTemplates, roots, tools, transportType, utils, version, }: {
564
+ get sessionId(): string | undefined;
565
+ set sessionId(value: string | undefined);
566
+ constructor({ auth, instructions, logger, name, ping, prompts, resources, resourcesTemplates, roots, sessionId, tools, transportType, utils, version, }: {
553
567
  auth?: T;
554
568
  instructions?: string;
555
569
  logger: Logger;
@@ -559,6 +573,7 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
559
573
  resources: Resource<T>[];
560
574
  resourcesTemplates: InputResourceTemplate<T>[];
561
575
  roots?: ServerOptions<T>["roots"];
576
+ sessionId?: string;
562
577
  tools: Tool<T>[];
563
578
  transportType?: "httpStream" | "stdio";
564
579
  utils?: ServerOptions<T>["utils"];
package/dist/FastMCP.js CHANGED
@@ -233,6 +233,12 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
233
233
  get server() {
234
234
  return this.#server;
235
235
  }
236
+ get sessionId() {
237
+ return this.#sessionId;
238
+ }
239
+ set sessionId(value) {
240
+ this.#sessionId = value;
241
+ }
236
242
  #auth;
237
243
  #capabilities = {};
238
244
  #clientCapabilities;
@@ -248,6 +254,11 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
248
254
  #roots = [];
249
255
  #rootsConfig;
250
256
  #server;
257
+ /**
258
+ * Session ID from the Mcp-Session-Id header (HTTP transports only).
259
+ * Used to track per-session state across multiple requests.
260
+ */
261
+ #sessionId;
251
262
  #utils;
252
263
  constructor({
253
264
  auth,
@@ -259,6 +270,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
259
270
  resources,
260
271
  resourcesTemplates,
261
272
  roots,
273
+ sessionId,
262
274
  tools,
263
275
  transportType,
264
276
  utils,
@@ -269,6 +281,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
269
281
  this.#logger = logger;
270
282
  this.#pingConfig = ping;
271
283
  this.#rootsConfig = roots;
284
+ this.#sessionId = sessionId;
272
285
  this.#needsEventLoopFlush = transportType === "httpStream";
273
286
  if (tools.length) {
274
287
  this.#capabilities.tools = {};
@@ -329,6 +342,12 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
329
342
  this.#connectionState = "connecting";
330
343
  try {
331
344
  await this.#server.connect(transport);
345
+ if ("sessionId" in transport) {
346
+ const transportWithSessionId = transport;
347
+ if (typeof transportWithSessionId.sessionId === "string") {
348
+ this.#sessionId = transportWithSessionId.sessionId;
349
+ }
350
+ }
332
351
  let attempt = 0;
333
352
  const maxAttempts = 10;
334
353
  const retryDelay = 100;
@@ -900,7 +919,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
900
919
  },
901
920
  log,
902
921
  reportProgress,
922
+ requestId: typeof request.params?._meta?.requestId === "string" ? request.params._meta.requestId : void 0,
903
923
  session: this.#auth,
924
+ sessionId: this.#sessionId,
904
925
  streamContent
905
926
  });
906
927
  const maybeStringResult = await (tool.timeoutMs ? Promise.race([
@@ -1125,7 +1146,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1125
1146
  `[FastMCP info] Starting server in stateless mode on HTTP Stream at http://${httpConfig.host}:${httpConfig.port}${httpConfig.endpoint}`
1126
1147
  );
1127
1148
  this.#httpStreamServer = await startHTTPServer({
1128
- authenticate: this.#authenticate,
1149
+ ...this.#authenticate ? { authenticate: this.#authenticate } : {},
1129
1150
  createServer: async (request) => {
1130
1151
  let auth;
1131
1152
  if (this.#authenticate) {
@@ -1134,7 +1155,8 @@ var FastMCP = class extends FastMCPEventEmitter {
1134
1155
  throw new Error("Authentication required");
1135
1156
  }
1136
1157
  }
1137
- return this.#createSession(auth);
1158
+ const sessionId = Array.isArray(request.headers["mcp-session-id"]) ? request.headers["mcp-session-id"][0] : request.headers["mcp-session-id"];
1159
+ return this.#createSession(auth, sessionId);
1138
1160
  },
1139
1161
  enableJsonResponse: httpConfig.enableJsonResponse,
1140
1162
  eventStore: httpConfig.eventStore,
@@ -1156,13 +1178,14 @@ var FastMCP = class extends FastMCPEventEmitter {
1156
1178
  });
1157
1179
  } else {
1158
1180
  this.#httpStreamServer = await startHTTPServer({
1159
- authenticate: this.#authenticate,
1181
+ ...this.#authenticate ? { authenticate: this.#authenticate } : {},
1160
1182
  createServer: async (request) => {
1161
1183
  let auth;
1162
1184
  if (this.#authenticate) {
1163
1185
  auth = await this.#authenticate(request);
1164
1186
  }
1165
- return this.#createSession(auth);
1187
+ const sessionId = Array.isArray(request.headers["mcp-session-id"]) ? request.headers["mcp-session-id"][0] : request.headers["mcp-session-id"];
1188
+ return this.#createSession(auth, sessionId);
1166
1189
  },
1167
1190
  enableJsonResponse: httpConfig.enableJsonResponse,
1168
1191
  eventStore: httpConfig.eventStore,
@@ -1213,7 +1236,11 @@ var FastMCP = class extends FastMCPEventEmitter {
1213
1236
  * Creates a new FastMCPSession instance with the current configuration.
1214
1237
  * Used both for regular sessions and stateless requests.
1215
1238
  */
1216
- #createSession(auth) {
1239
+ #createSession(auth, sessionId) {
1240
+ if (auth && typeof auth === "object" && "authenticated" in auth && !auth.authenticated) {
1241
+ const errorMessage = "error" in auth && typeof auth.error === "string" ? auth.error : "Authentication failed";
1242
+ throw new Error(errorMessage);
1243
+ }
1217
1244
  const allowedTools = auth ? this.#tools.filter(
1218
1245
  (tool) => tool.canAccess ? tool.canAccess(auth) : true
1219
1246
  ) : this.#tools;
@@ -1227,6 +1254,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1227
1254
  resources: this.#resources,
1228
1255
  resourcesTemplates: this.#resourcesTemplates,
1229
1256
  roots: this.#options.roots,
1257
+ sessionId,
1230
1258
  tools: allowedTools,
1231
1259
  transportType: "httpStream",
1232
1260
  utils: this.#options.utils,