@prefecthq/fastmcp-ts 1.1.0 → 1.2.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/dist/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { CreateMessageResult, CreateMessageResultWithTools, ContentBlock, CreateMessageRequestParams, LoggingLevel, ElicitRequestParams, ElicitResult, Tool, Resource, Prompt, ResourceTemplateType, TextResourceContents, BlobResourceContents, GetPromptResult, OAuthClientMetadata as OAuthClientMetadata$1, Root, ModelPreferences, SamplingMessage, ToolChoice } from '@modelcontextprotocol/server';
1
+ import { CallToolResult as CallToolResult$1, OAuthClientProvider, OAuthClientMetadata, OAuthClientInformationContext, StoredOAuthClientInformation, StoredOAuthTokens, OAuthDiscoveryState, ClientAuthMethod, Transport, ClientCapabilities, VersionNegotiationOptions, PriorDiscovery, InputRequiredOptions, ResponseCacheStore, ProtocolEra, Implementation, ServerCapabilities } from '@modelcontextprotocol/client';
2
+ export { ClientCapabilities } from '@modelcontextprotocol/client';
3
+ import { CreateMessageResult, CreateMessageResultWithTools, CreateMessageRequestParams, LoggingLevel, ElicitRequestParams, ElicitResult, Tool, Resource, Prompt, ResourceTemplateType, TextResourceContents, BlobResourceContents, GetPromptResult, OAuthClientMetadata as OAuthClientMetadata$1, Root, ContentBlock, ModelPreferences, SamplingMessage, ToolChoice } from '@modelcontextprotocol/server';
2
4
  export { BlobResourceContents, ContentBlock, CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, ElicitRequestParams, ElicitResult, GetPromptResult, LoggingLevel, ModelPreferences, Prompt, PromptArgument, PromptMessage, Resource, ResourceContents, ResourceTemplateType as ResourceTemplate, Root, SamplingMessage, TextResourceContents, Tool, ToolChoice, ToolResultContent, ToolUseContent } from '@modelcontextprotocol/server';
3
- import { OAuthClientProvider, OAuthClientMetadata, OAuthClientInformationContext, StoredOAuthClientInformation, StoredOAuthTokens, OAuthDiscoveryState, ClientAuthMethod, Transport, VersionNegotiationOptions, ProtocolEra, PriorDiscovery, InputRequiredOptions, ResponseCacheStore, Implementation, ServerCapabilities } from '@modelcontextprotocol/client';
4
5
  import Anthropic from '@anthropic-ai/sdk';
5
6
  import OpenAI from 'openai';
6
7
  import { GoogleGenAI } from '@google/genai';
@@ -9,10 +10,10 @@ import { GoogleGenAI } from '@google/genai';
9
10
  type AnySamplingResult = CreateMessageResult | CreateMessageResultWithTools;
10
11
  /**
11
12
  * The SDK's CallToolResult with a typed generic for structuredContent.
12
- * Use TData to get typed access to structured tool output.
13
+ * The intersection retains its open extension fields while narrowing the two
14
+ * values FastMCP normalizes.
13
15
  */
14
- type CallToolResult<TData = unknown> = {
15
- content: ContentBlock[];
16
+ type CallToolResult<TData = unknown> = CallToolResult$1 & {
16
17
  structuredContent: TData | null;
17
18
  isError: boolean;
18
19
  };
@@ -598,115 +599,6 @@ declare class StdioTransport {
598
599
  }
599
600
  type ClientTransportInput = string | McpServerLike | McpConfig | StdioTransport | Transport;
600
601
 
601
- interface MultiServerOptions {
602
- handlers?: ClientHandlers;
603
- /** file:// URIs to advertise to all servers as accessible roots. */
604
- roots?: string[];
605
- defaultOptions?: ClientDefaultOptions;
606
- /**
607
- * Protocol version negotiation, applied identically to every server in the
608
- * config (protocol revision 2026-07-28 and later). See
609
- * `ClientOptions.versionNegotiation` on the single-server `Client` — same
610
- * semantics, just applied per sub-client here since each connected server
611
- * negotiates its own era independently. Default `{ mode: 'auto' }`: each
612
- * sub-client probes its server once and falls back to legacy when the
613
- * server offers no modern era; `{ mode: 'legacy' }` opts every connection
614
- * out of the probe.
615
- */
616
- versionNegotiation?: VersionNegotiationOptions;
617
- }
618
- declare class MultiServerClient implements IClient {
619
- private _clients;
620
- private _connectPromise;
621
- private _connected;
622
- /** URI (or namespaced template URI) → server name, populated by list calls */
623
- private _uriMap;
624
- private readonly _config;
625
- private readonly _handlers;
626
- private readonly _roots;
627
- private readonly _defaultOptions;
628
- private readonly _versionNegotiation;
629
- private _resourceSubscriptions;
630
- /** Modern-era (2026-07-28) subscriptions/listen streams, one per server that
631
- * currently has active resource subscriptions — see Client's own field of the
632
- * same purpose for the full rationale. Keyed by server name since each
633
- * connected server negotiates its own era independently. */
634
- private _resourceListenSubscriptions;
635
- /** Per-server log level set by setLogLevel() for servers negotiated to modern
636
- * era — see Client's own field of the same purpose for the full rationale.
637
- * Keyed by server name since each connected server negotiates its own era
638
- * independently and may therefore need (or not need) meta-threading. */
639
- private _logLevels;
640
- constructor(config: McpConfig, options?: MultiServerOptions);
641
- connect(): Promise<void>;
642
- private _doConnect;
643
- close(): Promise<void>;
644
- [Symbol.asyncDispose](): Promise<void>;
645
- isConnected(): boolean;
646
- static connect(config: McpConfig, options?: MultiServerOptions): Promise<MultiServerClient>;
647
- /**
648
- * The protocol era negotiated with a specific named server: `'modern'` for
649
- * 2026-07-28, `'legacy'` for 2025-11-25 and earlier, `undefined` if the
650
- * server name is unknown or not yet connected. See
651
- * `MultiServerOptions.versionNegotiation` — the same mode is requested of
652
- * every server, but each negotiates (and may land on) its own era
653
- * independently, so this is necessarily per-server rather than a single
654
- * client-wide value.
655
- */
656
- getProtocolEra(serverName: string): ProtocolEra | undefined;
657
- /** See Client.ping's docs — the same era-routing applies here, per server,
658
- * since each connected server negotiates its own era independently. */
659
- ping(options?: RequestOptions): Promise<boolean>;
660
- listTools(options?: RequestOptions): Promise<Tool[]>;
661
- callTool<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
662
- callToolRaw<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
663
- listResources(options?: RequestOptions): Promise<Resource[]>;
664
- listResourceTemplates(options?: RequestOptions): Promise<ResourceTemplateType[]>;
665
- readResource(uri: string, options?: RequestOptions): Promise<Array<TextResourceContents | BlobResourceContents>>;
666
- listPrompts(options?: RequestOptions): Promise<Prompt[]>;
667
- getPrompt(name: string, args?: Record<string, string>, options?: RequestOptions): Promise<GetPromptResult>;
668
- /** See Client.subscribeResource's docs — the same era-routing applies here,
669
- * per server, since each connected server negotiates its own era. */
670
- subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise<void>;
671
- unsubscribeResource(uri: string, options?: RequestOptions): Promise<void>;
672
- /** Re-opens server-scoped listen stream for its currently-subscribed URIs — see
673
- * Client's own private method of the same purpose for the full rationale. */
674
- private _refreshResourceListenSubscriptionForServer;
675
- complete(ref: {
676
- type: 'ref/prompt';
677
- name: string;
678
- } | {
679
- type: 'ref/resource';
680
- uri: string;
681
- }, argument: {
682
- name: string;
683
- value: string;
684
- }, context?: {
685
- arguments?: Record<string, string>;
686
- }, options?: RequestOptions): Promise<CompletionResult>;
687
- /** See Client.setLogLevel's docs — the same era-routing applies here, per
688
- * server: legacy sends the real `logging/setLevel` RPC; modern records the
689
- * level and threads it into `_meta` on that server's subsequent requests via
690
- * `_metaParamsFor`, since `logging/setLevel` is absent from the modern wire
691
- * registry (SEP-2577). */
692
- setLogLevel(level: LoggingLevel, options?: RequestOptions): Promise<void>;
693
- private _assertConnected;
694
- private _parseNamespacedName;
695
- private _sdkForServer;
696
- private _buildSdkClient;
697
- private _buildCapabilities;
698
- private _registerHandlers;
699
- /** See Client._metaParams's docs — the same purpose, per server name, since
700
- * each connected server may be on a different era and have a different
701
- * recorded log level (or none). */
702
- private _metaParamsFor;
703
- private _toSdkOptions;
704
- }
705
-
706
- declare class ToolCallError extends Error {
707
- readonly content: ContentBlock[];
708
- constructor(message: string, content: ContentBlock[]);
709
- }
710
602
  interface ClientDefaultOptions {
711
603
  /** Global fallback timeout in seconds for all requests. */
712
604
  timeout?: number;
@@ -735,6 +627,11 @@ interface ClientOptions {
735
627
  */
736
628
  auth?: BearerAuth | OAuth | AsyncHeaderAuth | string;
737
629
  handlers?: ClientHandlers;
630
+ /**
631
+ * Additional capabilities to advertise to the server. FastMCP preserves
632
+ * their settings while adding capabilities inferred from handlers and roots.
633
+ */
634
+ capabilities?: ClientCapabilities;
738
635
  /**
739
636
  * Filesystem roots to advertise to the server.
740
637
  * Accepts a static array of strings / Root objects, or an async callback
@@ -815,6 +712,121 @@ interface ClientOptions {
815
712
  */
816
713
  legacySSE?: boolean;
817
714
  }
715
+
716
+ interface MultiServerOptions {
717
+ handlers?: ClientHandlers;
718
+ /**
719
+ * Additional capabilities to advertise to every server. FastMCP combines
720
+ * them with capabilities inferred from handlers and roots.
721
+ */
722
+ capabilities?: ClientCapabilities;
723
+ /** file:// URIs to advertise to all servers as accessible roots. */
724
+ roots?: string[];
725
+ defaultOptions?: ClientDefaultOptions;
726
+ /**
727
+ * Protocol version negotiation, applied identically to every server in the
728
+ * config (protocol revision 2026-07-28 and later). See
729
+ * `ClientOptions.versionNegotiation` on the single-server `Client` — same
730
+ * semantics, just applied per sub-client here since each connected server
731
+ * negotiates its own era independently. Default `{ mode: 'auto' }`: each
732
+ * sub-client probes its server once and falls back to legacy when the
733
+ * server offers no modern era; `{ mode: 'legacy' }` opts every connection
734
+ * out of the probe.
735
+ */
736
+ versionNegotiation?: VersionNegotiationOptions;
737
+ }
738
+ declare class MultiServerClient implements IClient {
739
+ private _clients;
740
+ private _connectPromise;
741
+ private _connected;
742
+ /** URI (or namespaced template URI) → server name, populated by list calls */
743
+ private _uriMap;
744
+ private readonly _config;
745
+ private readonly _handlers;
746
+ private readonly _roots;
747
+ private readonly _capabilities;
748
+ private readonly _defaultOptions;
749
+ private readonly _versionNegotiation;
750
+ private _resourceSubscriptions;
751
+ /** Modern-era (2026-07-28) subscriptions/listen streams, one per server that
752
+ * currently has active resource subscriptions — see Client's own field of the
753
+ * same purpose for the full rationale. Keyed by server name since each
754
+ * connected server negotiates its own era independently. */
755
+ private _resourceListenSubscriptions;
756
+ /** Per-server log level set by setLogLevel() for servers negotiated to modern
757
+ * era — see Client's own field of the same purpose for the full rationale.
758
+ * Keyed by server name since each connected server negotiates its own era
759
+ * independently and may therefore need (or not need) meta-threading. */
760
+ private _logLevels;
761
+ constructor(config: McpConfig, options?: MultiServerOptions);
762
+ connect(): Promise<void>;
763
+ private _doConnect;
764
+ close(): Promise<void>;
765
+ [Symbol.asyncDispose](): Promise<void>;
766
+ isConnected(): boolean;
767
+ static connect(config: McpConfig, options?: MultiServerOptions): Promise<MultiServerClient>;
768
+ /**
769
+ * The protocol era negotiated with a specific named server: `'modern'` for
770
+ * 2026-07-28, `'legacy'` for 2025-11-25 and earlier, `undefined` if the
771
+ * server name is unknown or not yet connected. See
772
+ * `MultiServerOptions.versionNegotiation` — the same mode is requested of
773
+ * every server, but each negotiates (and may land on) its own era
774
+ * independently, so this is necessarily per-server rather than a single
775
+ * client-wide value.
776
+ */
777
+ getProtocolEra(serverName: string): ProtocolEra | undefined;
778
+ /** See Client.ping's docs — the same era-routing applies here, per server,
779
+ * since each connected server negotiates its own era independently. */
780
+ ping(options?: RequestOptions): Promise<boolean>;
781
+ listTools(options?: RequestOptions): Promise<Tool[]>;
782
+ callTool<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
783
+ callToolRaw<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
784
+ listResources(options?: RequestOptions): Promise<Resource[]>;
785
+ listResourceTemplates(options?: RequestOptions): Promise<ResourceTemplateType[]>;
786
+ readResource(uri: string, options?: RequestOptions): Promise<Array<TextResourceContents | BlobResourceContents>>;
787
+ listPrompts(options?: RequestOptions): Promise<Prompt[]>;
788
+ getPrompt(name: string, args?: Record<string, string>, options?: RequestOptions): Promise<GetPromptResult>;
789
+ /** See Client.subscribeResource's docs — the same era-routing applies here,
790
+ * per server, since each connected server negotiates its own era. */
791
+ subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise<void>;
792
+ unsubscribeResource(uri: string, options?: RequestOptions): Promise<void>;
793
+ /** Re-opens server-scoped listen stream for its currently-subscribed URIs — see
794
+ * Client's own private method of the same purpose for the full rationale. */
795
+ private _refreshResourceListenSubscriptionForServer;
796
+ complete(ref: {
797
+ type: 'ref/prompt';
798
+ name: string;
799
+ } | {
800
+ type: 'ref/resource';
801
+ uri: string;
802
+ }, argument: {
803
+ name: string;
804
+ value: string;
805
+ }, context?: {
806
+ arguments?: Record<string, string>;
807
+ }, options?: RequestOptions): Promise<CompletionResult>;
808
+ /** See Client.setLogLevel's docs — the same era-routing applies here, per
809
+ * server: legacy sends the real `logging/setLevel` RPC; modern records the
810
+ * level and threads it into `_meta` on that server's subsequent requests via
811
+ * `_metaParamsFor`, since `logging/setLevel` is absent from the modern wire
812
+ * registry (SEP-2577). */
813
+ setLogLevel(level: LoggingLevel, options?: RequestOptions): Promise<void>;
814
+ private _assertConnected;
815
+ private _parseNamespacedName;
816
+ private _sdkForServer;
817
+ private _buildSdkClient;
818
+ private _registerHandlers;
819
+ /** See Client._metaParams's docs — the same purpose, per server name, since
820
+ * each connected server may be on a different era and have a different
821
+ * recorded log level (or none). */
822
+ private _metaParamsFor;
823
+ private _toSdkOptions;
824
+ }
825
+
826
+ declare class ToolCallError extends Error {
827
+ readonly content: ContentBlock[];
828
+ constructor(message: string, content: ContentBlock[]);
829
+ }
818
830
  declare class Client implements IClient {
819
831
  private _sdkClient;
820
832
  private _refCount;
@@ -842,6 +854,7 @@ declare class Client implements IClient {
842
854
  private readonly _auth;
843
855
  private readonly _handlers;
844
856
  private readonly _roots;
857
+ private readonly _capabilities;
845
858
  private readonly _autoInitialize;
846
859
  private readonly _versionNegotiation;
847
860
  private readonly _prior;
@@ -1085,7 +1098,6 @@ declare class Client implements IClient {
1085
1098
  */
1086
1099
  private _metaParams;
1087
1100
  private _toSdkOptions;
1088
- private _buildCapabilities;
1089
1101
  private _buildListChangedConfig;
1090
1102
  private _registerHandlers;
1091
1103
  /**
package/dist/client.js CHANGED
@@ -916,6 +916,37 @@ async function resolveTransport(input, auth, options) {
916
916
  // src/client/client.ts
917
917
  import { UnauthorizedError, Client as SdkClient2, LOG_LEVEL_META_KEY as LOG_LEVEL_META_KEY2 } from "@modelcontextprotocol/client";
918
918
 
919
+ // src/client/capabilities.ts
920
+ function buildClientCapabilities(supplied, inferred) {
921
+ const capabilities = { ...supplied };
922
+ if (inferred.sampling) {
923
+ capabilities.sampling = {
924
+ ...supplied?.sampling,
925
+ tools: supplied?.sampling?.tools ?? {}
926
+ };
927
+ }
928
+ if (inferred.elicitation) {
929
+ const elicitation = supplied?.elicitation;
930
+ capabilities.elicitation = elicitation ? { ...elicitation, form: elicitation.form ?? {} } : {};
931
+ }
932
+ if (inferred.rootsListChanged !== void 0) {
933
+ capabilities.roots = {
934
+ ...supplied?.roots,
935
+ listChanged: inferred.rootsListChanged
936
+ };
937
+ }
938
+ return capabilities;
939
+ }
940
+
941
+ // src/client/results.ts
942
+ function normalizeCallToolResult(result) {
943
+ return {
944
+ ...result,
945
+ structuredContent: result.structuredContent ?? null,
946
+ isError: result.isError === true
947
+ };
948
+ }
949
+
919
950
  // src/client/multi-server.ts
920
951
  import { Client as SdkClient, LOG_LEVEL_META_KEY } from "@modelcontextprotocol/client";
921
952
  var MultiServerClient = class _MultiServerClient {
@@ -927,6 +958,7 @@ var MultiServerClient = class _MultiServerClient {
927
958
  _config;
928
959
  _handlers;
929
960
  _roots;
961
+ _capabilities;
930
962
  _defaultOptions;
931
963
  _versionNegotiation;
932
964
  _resourceSubscriptions = /* @__PURE__ */ new Map();
@@ -950,6 +982,11 @@ var MultiServerClient = class _MultiServerClient {
950
982
  };
951
983
  this._versionNegotiation = options?.versionNegotiation ?? { mode: "auto" };
952
984
  this._roots = options?.roots;
985
+ this._capabilities = buildClientCapabilities(options?.capabilities, {
986
+ sampling: this._handlers.sampling !== void 0,
987
+ elicitation: this._handlers.elicitation !== void 0,
988
+ rootsListChanged: this._roots === void 0 ? void 0 : false
989
+ });
953
990
  this._defaultOptions = options?.defaultOptions ?? {};
954
991
  }
955
992
  // -------------------------------------------------------------------------
@@ -1078,11 +1115,7 @@ var MultiServerClient = class _MultiServerClient {
1078
1115
  { name: localName, arguments: args ?? {}, ...this._metaParamsFor(serverName) },
1079
1116
  sdkOptions
1080
1117
  );
1081
- return {
1082
- content: result.content,
1083
- structuredContent: result.structuredContent ?? null,
1084
- isError: result.isError === true
1085
- };
1118
+ return normalizeCallToolResult(result);
1086
1119
  }
1087
1120
  // -------------------------------------------------------------------------
1088
1121
  // Resources
@@ -1361,18 +1394,11 @@ ${errors.map(String).join("\n")}`);
1361
1394
  return new SdkClient(
1362
1395
  { name: "fastmcp-ts", version: "1.0.0" },
1363
1396
  {
1364
- capabilities: this._buildCapabilities(),
1397
+ capabilities: this._capabilities,
1365
1398
  versionNegotiation: this._versionNegotiation
1366
1399
  }
1367
1400
  );
1368
1401
  }
1369
- _buildCapabilities() {
1370
- return {
1371
- ...this._handlers.sampling ? { sampling: { tools: {} } } : {},
1372
- ...this._handlers.elicitation ? { elicitation: {} } : {},
1373
- ...this._roots ? { roots: { listChanged: false } } : {}
1374
- };
1375
- }
1376
1402
  _registerHandlers(sdk) {
1377
1403
  sdk.setNotificationHandler("notifications/message", (notification) => {
1378
1404
  void this._handlers.log({
@@ -1459,6 +1485,7 @@ var Client = class _Client {
1459
1485
  _auth;
1460
1486
  _handlers;
1461
1487
  _roots;
1488
+ _capabilities;
1462
1489
  _autoInitialize;
1463
1490
  _versionNegotiation;
1464
1491
  _prior;
@@ -1486,6 +1513,11 @@ var Client = class _Client {
1486
1513
  onPromptsListChanged: options?.handlers?.onPromptsListChanged
1487
1514
  };
1488
1515
  this._roots = options?.roots ? normalizeRootsOption(options.roots) : void 0;
1516
+ this._capabilities = buildClientCapabilities(options?.capabilities, {
1517
+ sampling: this._handlers.sampling !== void 0,
1518
+ elicitation: this._handlers.elicitation !== void 0,
1519
+ rootsListChanged: this._roots === void 0 ? void 0 : true
1520
+ });
1489
1521
  this._autoInitialize = options?.autoInitialize ?? true;
1490
1522
  this._versionNegotiation = options?.versionNegotiation ?? { mode: "auto" };
1491
1523
  this._prior = options?.prior;
@@ -1520,7 +1552,7 @@ var Client = class _Client {
1520
1552
  const sdkClient = new SdkClient2(
1521
1553
  { name: "fastmcp-ts", version: "1.0.0" },
1522
1554
  {
1523
- capabilities: this._buildCapabilities(),
1555
+ capabilities: this._capabilities,
1524
1556
  listChanged: this._buildListChangedConfig(),
1525
1557
  versionNegotiation: this._versionNegotiation,
1526
1558
  ...this._inputRequired ? { inputRequired: this._inputRequired } : {},
@@ -1689,11 +1721,7 @@ var Client = class _Client {
1689
1721
  const result = await this._reauthRetry(
1690
1722
  () => this._sdk().callTool({ name, arguments: args ?? {}, ...this._metaParams() }, sdkOptions)
1691
1723
  );
1692
- return {
1693
- content: result.content,
1694
- structuredContent: result.structuredContent ?? null,
1695
- isError: result.isError === true
1696
- };
1724
+ return normalizeCallToolResult(result);
1697
1725
  }
1698
1726
  // -------------------------------------------------------------------------
1699
1727
  // Resources (IResourcesClient)
@@ -1992,13 +2020,6 @@ var Client = class _Client {
1992
2020
  }
1993
2021
  return sdkOptions;
1994
2022
  }
1995
- _buildCapabilities() {
1996
- return {
1997
- ...this._handlers.sampling ? { sampling: { tools: {} } } : {},
1998
- ...this._handlers.elicitation ? { elicitation: {} } : {},
1999
- ...this._roots ? { roots: { listChanged: true } } : {}
2000
- };
2001
- }
2002
2023
  _buildListChangedConfig() {
2003
2024
  const { onToolsListChanged, onResourcesListChanged, onPromptsListChanged } = this._handlers;
2004
2025
  if (!onToolsListChanged && !onResourcesListChanged && !onPromptsListChanged) return void 0;