fastmcp 4.11.0 → 4.12.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.
package/README.md CHANGED
@@ -33,6 +33,7 @@ A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable
33
33
  - [Configurable ping behavior](#configurable-ping-behavior)
34
34
  - [Health-check endpoint](#health-check-endpoint)
35
35
  - [Roots](#roots-management)
36
+ - [In-memory transport](#unit-testing-with-an-in-memory-transport) for unit testing without binding a port
36
37
  - CLI for [testing](#test-with-mcp-cli) and [debugging](#inspect-with-mcp-inspector)
37
38
 
38
39
  ## When to use FastMCP over the official SDK?
@@ -2525,6 +2526,51 @@ session.on("error", (event) => {
2525
2526
 
2526
2527
  ## Running Your Server
2527
2528
 
2529
+ ### Unit testing with an in-memory transport
2530
+
2531
+ `server.connect(transport)` attaches the server to a transport you construct yourself, instead of letting `start()` create one. Paired with the SDK's `InMemoryTransport`, this lets you drive a server in-process — no port to bind, no subprocess to spawn — which is usually what you want for testing a `stdio` server:
2532
+
2533
+ ```ts
2534
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2535
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
2536
+
2537
+ async function createTestClient(server: FastMCP) {
2538
+ const [clientTransport, serverTransport] =
2539
+ InMemoryTransport.createLinkedPair();
2540
+
2541
+ const client = new Client({ name: "test-client", version: "0.0.0" });
2542
+
2543
+ const [session] = await Promise.all([
2544
+ server.connect(serverTransport),
2545
+ client.connect(clientTransport),
2546
+ ]);
2547
+
2548
+ return { client, session };
2549
+ }
2550
+
2551
+ test("adds two numbers", async () => {
2552
+ const { client } = await createTestClient(server);
2553
+
2554
+ expect(
2555
+ await client.callTool({ arguments: { a: 2, b: 3 }, name: "add" }),
2556
+ ).toEqual({
2557
+ content: [{ text: "5", type: "text" }],
2558
+ });
2559
+
2560
+ await client.close();
2561
+ });
2562
+ ```
2563
+
2564
+ The session is built from the tools, resources and prompts registered on the instance, exactly as `start()` builds it, so your tests exercise the same wiring the real server uses — including `canAccess` filtering and the `connect`/`disconnect` events.
2565
+
2566
+ Pass session auth as the second argument, equivalent to what your `authenticate` function would return:
2567
+
2568
+ ```ts
2569
+ await server.connect(serverTransport, { id: 7, role: "admin" });
2570
+ ```
2571
+
2572
+ `connect` returns the [`FastMCPSession`](#fastmcpsession), so you can assert on `session.clientCapabilities`, `session.roots`, and the rest. The transport's lifecycle belongs to you: `stop()` does not close transports passed to `connect`, so close the client (and the session, if you need `disconnect` to fire) when the test finishes.
2573
+
2528
2574
  ### Test with `mcp-cli`
2529
2575
 
2530
2576
  The fastest way to test and debug your server is with `fastmcp dev`:
package/dist/FastMCP.cjs CHANGED
@@ -8,7 +8,9 @@
8
8
 
9
9
 
10
10
 
11
- var _chunkISO2WPB5cjs = require('./chunk-ISO2WPB5.cjs');
11
+
12
+
13
+ var _chunkPOXZCEYEcjs = require('./chunk-POXZCEYE.cjs');
12
14
 
13
15
 
14
16
 
@@ -43,5 +45,7 @@ var _chunkDZYT6QAHcjs = require('./chunk-DZYT6QAH.cjs');
43
45
 
44
46
 
45
47
 
46
- exports.AuthProvider = _chunkDZYT6QAHcjs.AuthProvider; exports.AzureProvider = _chunkDZYT6QAHcjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkISO2WPB5cjs.DiscoveryDocumentCache; exports.FastMCP = _chunkISO2WPB5cjs.FastMCP; exports.FastMCPSession = _chunkISO2WPB5cjs.FastMCPSession; exports.GitHubProvider = _chunkDZYT6QAHcjs.GitHubProvider; exports.GoogleProvider = _chunkDZYT6QAHcjs.GoogleProvider; exports.OAuthProvider = _chunkDZYT6QAHcjs.OAuthProvider; exports.ServerState = _chunkISO2WPB5cjs.ServerState; exports.UnexpectedStateError = _chunkISO2WPB5cjs.UnexpectedStateError; exports.UserError = _chunkISO2WPB5cjs.UserError; exports.audioContent = _chunkISO2WPB5cjs.audioContent; exports.getAuthSession = _chunkDZYT6QAHcjs.getAuthSession; exports.imageContent = _chunkISO2WPB5cjs.imageContent; exports.jsonSchemaAdapter = _chunkISO2WPB5cjs.jsonSchemaAdapter; exports.requireAll = _chunkDZYT6QAHcjs.requireAll; exports.requireAny = _chunkDZYT6QAHcjs.requireAny; exports.requireAuth = _chunkDZYT6QAHcjs.requireAuth; exports.requireRole = _chunkDZYT6QAHcjs.requireRole; exports.requireScopes = _chunkDZYT6QAHcjs.requireScopes;
48
+
49
+
50
+ exports.AuthProvider = _chunkDZYT6QAHcjs.AuthProvider; exports.AzureProvider = _chunkDZYT6QAHcjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkPOXZCEYEcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkPOXZCEYEcjs.FastMCP; exports.FastMCPError = _chunkPOXZCEYEcjs.FastMCPError; exports.FastMCPSession = _chunkPOXZCEYEcjs.FastMCPSession; exports.GitHubProvider = _chunkDZYT6QAHcjs.GitHubProvider; exports.GoogleProvider = _chunkDZYT6QAHcjs.GoogleProvider; exports.OAuthProvider = _chunkDZYT6QAHcjs.OAuthProvider; exports.ServerState = _chunkPOXZCEYEcjs.ServerState; exports.SessionError = _chunkPOXZCEYEcjs.SessionError; exports.UnexpectedStateError = _chunkPOXZCEYEcjs.UnexpectedStateError; exports.UserError = _chunkPOXZCEYEcjs.UserError; exports.audioContent = _chunkPOXZCEYEcjs.audioContent; exports.getAuthSession = _chunkDZYT6QAHcjs.getAuthSession; exports.imageContent = _chunkPOXZCEYEcjs.imageContent; exports.jsonSchemaAdapter = _chunkPOXZCEYEcjs.jsonSchemaAdapter; exports.requireAll = _chunkDZYT6QAHcjs.requireAll; exports.requireAny = _chunkDZYT6QAHcjs.requireAny; exports.requireAuth = _chunkDZYT6QAHcjs.requireAuth; exports.requireRole = _chunkDZYT6QAHcjs.requireRole; exports.requireScopes = _chunkDZYT6QAHcjs.requireScopes;
47
51
  //# sourceMappingURL=FastMCP.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/FastMCP.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,inCAAC","file":"/home/runner/work/fastmcp/fastmcp/dist/FastMCP.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/FastMCP.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,+tCAAC","file":"/home/runner/work/fastmcp/fastmcp/dist/FastMCP.cjs"}
@@ -242,6 +242,19 @@ type ToolParameters = StandardSchemaV1;
242
242
  declare abstract class FastMCPError extends Error {
243
243
  constructor(message?: string);
244
244
  }
245
+ /**
246
+ * An error raised when a session encounters a problem (e.g. connection
247
+ * failures, protocol violations). Consumers can use this class to
248
+ * distinguish fastmcp session errors from unrelated runtime errors:
249
+ *
250
+ * ```ts
251
+ * server.on("error", ({ error }) => {
252
+ * if (error instanceof SessionError) { ... }
253
+ * });
254
+ * ```
255
+ */
256
+ declare class SessionError extends FastMCPError {
257
+ }
245
258
  declare class UnexpectedStateError extends FastMCPError {
246
259
  extras?: Extras;
247
260
  constructor(message: string, extras?: Extras);
@@ -914,6 +927,34 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
914
927
  * Adds tools to the server.
915
928
  */
916
929
  addTools<Params extends ToolParameters>(tools: Tool<T, Params>[]): void;
930
+ /**
931
+ * Connects the server to a transport you constructed yourself, instead of
932
+ * letting {@link FastMCP.start} create one.
933
+ *
934
+ * The session is built from the tools, resources and prompts registered on
935
+ * this instance — exactly as `start()` does — so tests exercise the same
936
+ * wiring the real server uses. The main use case is driving a server
937
+ * in-process over `InMemoryTransport` without binding a port:
938
+ *
939
+ * ```ts
940
+ * const [clientTransport, serverTransport] =
941
+ * InMemoryTransport.createLinkedPair();
942
+ *
943
+ * await Promise.all([
944
+ * server.connect(serverTransport),
945
+ * client.connect(clientTransport),
946
+ * ]);
947
+ * ```
948
+ *
949
+ * The transport's lifecycle belongs to the caller: `stop()` does not close
950
+ * transports passed here. Close the returned session (or the transport) when
951
+ * you are done with it.
952
+ *
953
+ * @param transport - An already-constructed MCP server transport.
954
+ * @param auth - Session auth, equivalent to what `authenticate` would return.
955
+ * @returns The session bound to the transport.
956
+ */
957
+ connect(transport: Transport, auth?: T): Promise<FastMCPSession<T>>;
917
958
  /**
918
959
  * Embeds a resource by URI, making it easy to include resources in tool responses.
919
960
  *
@@ -1011,4 +1052,4 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
1011
1052
  stop(): Promise<void>;
1012
1053
  }
1013
1054
 
1014
- export { type AudioContent, AuthProvider, type Content, type ContentResult, type Context, DiscoveryDocumentCache, FastMCP, type FastMCPEvents, type FastMCPRequest, type FastMCPResponse, FastMCPSession, type FastMCPSessionAuth, type FastMCPSessionEvents, type HTTPMethod, type ImageContent, type InputPrompt, type InputPromptArgument, type JsonSchemaObject, type JsonSchemaStandardSchema, type LoadContext, type Logger, type LoggingLevel, OAuthSession, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type RouteHandler, type RouteOptions, type SSEServer, type SerializableValue, type ServerOptions, ServerState, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent, jsonSchemaAdapter };
1055
+ export { type AudioContent, AuthProvider, type Content, type ContentResult, type Context, DiscoveryDocumentCache, FastMCP, FastMCPError, type FastMCPEvents, type FastMCPRequest, type FastMCPResponse, FastMCPSession, type FastMCPSessionAuth, type FastMCPSessionEvents, type HTTPMethod, type ImageContent, type InputPrompt, type InputPromptArgument, type JsonSchemaObject, type JsonSchemaStandardSchema, type LoadContext, type Logger, type LoggingLevel, OAuthSession, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type RouteHandler, type RouteOptions, type SSEServer, type SerializableValue, type ServerOptions, ServerState, SessionError, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent, jsonSchemaAdapter };
package/dist/FastMCP.d.ts CHANGED
@@ -242,6 +242,19 @@ type ToolParameters = StandardSchemaV1;
242
242
  declare abstract class FastMCPError extends Error {
243
243
  constructor(message?: string);
244
244
  }
245
+ /**
246
+ * An error raised when a session encounters a problem (e.g. connection
247
+ * failures, protocol violations). Consumers can use this class to
248
+ * distinguish fastmcp session errors from unrelated runtime errors:
249
+ *
250
+ * ```ts
251
+ * server.on("error", ({ error }) => {
252
+ * if (error instanceof SessionError) { ... }
253
+ * });
254
+ * ```
255
+ */
256
+ declare class SessionError extends FastMCPError {
257
+ }
245
258
  declare class UnexpectedStateError extends FastMCPError {
246
259
  extras?: Extras;
247
260
  constructor(message: string, extras?: Extras);
@@ -914,6 +927,34 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
914
927
  * Adds tools to the server.
915
928
  */
916
929
  addTools<Params extends ToolParameters>(tools: Tool<T, Params>[]): void;
930
+ /**
931
+ * Connects the server to a transport you constructed yourself, instead of
932
+ * letting {@link FastMCP.start} create one.
933
+ *
934
+ * The session is built from the tools, resources and prompts registered on
935
+ * this instance — exactly as `start()` does — so tests exercise the same
936
+ * wiring the real server uses. The main use case is driving a server
937
+ * in-process over `InMemoryTransport` without binding a port:
938
+ *
939
+ * ```ts
940
+ * const [clientTransport, serverTransport] =
941
+ * InMemoryTransport.createLinkedPair();
942
+ *
943
+ * await Promise.all([
944
+ * server.connect(serverTransport),
945
+ * client.connect(clientTransport),
946
+ * ]);
947
+ * ```
948
+ *
949
+ * The transport's lifecycle belongs to the caller: `stop()` does not close
950
+ * transports passed here. Close the returned session (or the transport) when
951
+ * you are done with it.
952
+ *
953
+ * @param transport - An already-constructed MCP server transport.
954
+ * @param auth - Session auth, equivalent to what `authenticate` would return.
955
+ * @returns The session bound to the transport.
956
+ */
957
+ connect(transport: Transport, auth?: T): Promise<FastMCPSession<T>>;
917
958
  /**
918
959
  * Embeds a resource by URI, making it easy to include resources in tool responses.
919
960
  *
@@ -1011,4 +1052,4 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
1011
1052
  stop(): Promise<void>;
1012
1053
  }
1013
1054
 
1014
- export { type AudioContent, AuthProvider, type Content, type ContentResult, type Context, DiscoveryDocumentCache, FastMCP, type FastMCPEvents, type FastMCPRequest, type FastMCPResponse, FastMCPSession, type FastMCPSessionAuth, type FastMCPSessionEvents, type HTTPMethod, type ImageContent, type InputPrompt, type InputPromptArgument, type JsonSchemaObject, type JsonSchemaStandardSchema, type LoadContext, type Logger, type LoggingLevel, OAuthSession, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type RouteHandler, type RouteOptions, type SSEServer, type SerializableValue, type ServerOptions, ServerState, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent, jsonSchemaAdapter };
1055
+ export { type AudioContent, AuthProvider, type Content, type ContentResult, type Context, DiscoveryDocumentCache, FastMCP, FastMCPError, type FastMCPEvents, type FastMCPRequest, type FastMCPResponse, FastMCPSession, type FastMCPSessionAuth, type FastMCPSessionEvents, type HTTPMethod, type ImageContent, type InputPrompt, type InputPromptArgument, type JsonSchemaObject, type JsonSchemaStandardSchema, type LoadContext, type Logger, type LoggingLevel, OAuthSession, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type RouteHandler, type RouteOptions, type SSEServer, type SerializableValue, type ServerOptions, ServerState, SessionError, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent, jsonSchemaAdapter };
package/dist/FastMCP.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  DiscoveryDocumentCache,
3
3
  FastMCP,
4
+ FastMCPError,
4
5
  FastMCPSession,
5
6
  ServerState,
7
+ SessionError,
6
8
  UnexpectedStateError,
7
9
  UserError,
8
10
  audioContent,
9
11
  imageContent,
10
12
  jsonSchemaAdapter
11
- } from "./chunk-JOZJUFKE.js";
13
+ } from "./chunk-5BQXF2VT.js";
12
14
  import {
13
15
  AuthProvider,
14
16
  AzureProvider,
@@ -27,11 +29,13 @@ export {
27
29
  AzureProvider,
28
30
  DiscoveryDocumentCache,
29
31
  FastMCP,
32
+ FastMCPError,
30
33
  FastMCPSession,
31
34
  GitHubProvider,
32
35
  GoogleProvider,
33
36
  OAuthProvider,
34
37
  ServerState,
38
+ SessionError,
35
39
  UnexpectedStateError,
36
40
  UserError,
37
41
  audioContent,
@@ -294,6 +294,8 @@ var FastMCPError = class extends Error {
294
294
  this.name = new.target.name;
295
295
  }
296
296
  };
297
+ var SessionError = class extends FastMCPError {
298
+ };
297
299
  var UnexpectedStateError = class extends FastMCPError {
298
300
  extras;
299
301
  constructor(message, extras) {
@@ -1559,6 +1561,53 @@ var FastMCP = class extends FastMCPEventEmitter {
1559
1561
  this.#toolsListChanged(this.#tools);
1560
1562
  }
1561
1563
  }
1564
+ /**
1565
+ * Connects the server to a transport you constructed yourself, instead of
1566
+ * letting {@link FastMCP.start} create one.
1567
+ *
1568
+ * The session is built from the tools, resources and prompts registered on
1569
+ * this instance — exactly as `start()` does — so tests exercise the same
1570
+ * wiring the real server uses. The main use case is driving a server
1571
+ * in-process over `InMemoryTransport` without binding a port:
1572
+ *
1573
+ * ```ts
1574
+ * const [clientTransport, serverTransport] =
1575
+ * InMemoryTransport.createLinkedPair();
1576
+ *
1577
+ * await Promise.all([
1578
+ * server.connect(serverTransport),
1579
+ * client.connect(clientTransport),
1580
+ * ]);
1581
+ * ```
1582
+ *
1583
+ * The transport's lifecycle belongs to the caller: `stop()` does not close
1584
+ * transports passed here. Close the returned session (or the transport) when
1585
+ * you are done with it.
1586
+ *
1587
+ * @param transport - An already-constructed MCP server transport.
1588
+ * @param auth - Session auth, equivalent to what `authenticate` would return.
1589
+ * @returns The session bound to the transport.
1590
+ */
1591
+ async connect(transport, auth) {
1592
+ const session = this.#createSession(auth);
1593
+ await session.connect(transport);
1594
+ this.#sessions.push(session);
1595
+ session.once("error", () => {
1596
+ this.#removeSession(session);
1597
+ });
1598
+ const originalOnClose = transport.onclose;
1599
+ transport.onclose = () => {
1600
+ this.#removeSession(session);
1601
+ if (originalOnClose) {
1602
+ originalOnClose();
1603
+ }
1604
+ };
1605
+ this.emit("connect", {
1606
+ session
1607
+ });
1608
+ this.#serverState = "running" /* Running */;
1609
+ return session;
1610
+ }
1562
1611
  /**
1563
1612
  * Embeds a resource by URI, making it easy to include resources in tool responses.
1564
1613
  *
@@ -2439,10 +2488,12 @@ export {
2439
2488
  jsonSchemaAdapter,
2440
2489
  imageContent,
2441
2490
  audioContent,
2491
+ FastMCPError,
2492
+ SessionError,
2442
2493
  UnexpectedStateError,
2443
2494
  UserError,
2444
2495
  ServerState,
2445
2496
  FastMCPSession,
2446
2497
  FastMCP
2447
2498
  };
2448
- //# sourceMappingURL=chunk-JOZJUFKE.js.map
2499
+ //# sourceMappingURL=chunk-5BQXF2VT.js.map