@ai-sdk/mcp 2.0.43 → 2.0.45

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 2.0.45
4
+
5
+ ### Patch Changes
6
+
7
+ - 33ba8fd: feat(mcp): surface server-provided tool annotations in tool metadata
8
+ - 3da84fd: Accept MCP tool results that return `structuredContent` without `content` by adding the serialized structured result as text.
9
+
10
+ ## 2.0.44
11
+
12
+ ### Patch Changes
13
+
14
+ - 809e922: fix(mcp): accept trailing slashes on origin-only OAuth issuers
15
+
3
16
  ## 2.0.43
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -373,8 +373,23 @@ type McpProviderMetadata = {
373
373
  clientName?: string;
374
374
  title?: string;
375
375
  toolName?: string;
376
+ annotations?: McpToolAnnotations;
376
377
  app?: JSONObject;
377
378
  };
379
+ /**
380
+ * Behavioral hints reported by an MCP server for a tool.
381
+ *
382
+ * These annotations are untrusted unless the server itself is trusted.
383
+ *
384
+ * @see https://modelcontextprotocol.io/specification/2026-07-28/schema#toolannotations
385
+ */
386
+ type McpToolAnnotations = {
387
+ title?: string;
388
+ readOnlyHint?: boolean;
389
+ destructiveHint?: boolean;
390
+ idempotentHint?: boolean;
391
+ openWorldHint?: boolean;
392
+ };
378
393
  /** MCP tool metadata - keys should follow MCP _meta key format specification */
379
394
  declare const ToolMetaSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
380
395
  type ToolMeta = z.infer<typeof ToolMetaSchema>;
@@ -475,6 +490,10 @@ declare const ListToolsResultSchema: z.ZodObject<{
475
490
  outputSchema: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
476
491
  annotations: z.ZodOptional<z.ZodObject<{
477
492
  title: z.ZodOptional<z.ZodString>;
493
+ readOnlyHint: z.ZodOptional<z.ZodBoolean>;
494
+ destructiveHint: z.ZodOptional<z.ZodBoolean>;
495
+ idempotentHint: z.ZodOptional<z.ZodBoolean>;
496
+ openWorldHint: z.ZodOptional<z.ZodBoolean>;
478
497
  }, z.core.$loose>>;
479
498
  _meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
480
499
  }, z.core.$loose>>;
@@ -494,7 +513,7 @@ declare const ListResourcesResultSchema: z.ZodObject<{
494
513
  }, z.core.$loose>>;
495
514
  }, z.core.$loose>;
496
515
  type ListResourcesResult = z.infer<typeof ListResourcesResultSchema>;
497
- declare const CallToolResultSchema: z.ZodUnion<[z.ZodObject<{
516
+ declare const CallToolResultSchema: z.ZodUnion<[z.ZodUnion<[z.ZodObject<{
498
517
  _meta: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
499
518
  resultType: z.ZodOptional<z.ZodString>;
500
519
  content: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
@@ -525,13 +544,112 @@ declare const CallToolResultSchema: z.ZodUnion<[z.ZodObject<{
525
544
  name: z.ZodString;
526
545
  description: z.ZodOptional<z.ZodString>;
527
546
  mimeType: z.ZodOptional<z.ZodString>;
547
+ }, z.core.$loose>, z.ZodObject<{
548
+ type: z.ZodString;
549
+ }, z.core.$loose>]>>;
550
+ structuredContent: z.ZodOptional<z.ZodUnknown>;
551
+ isError: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
552
+ }, z.core.$loose>, z.ZodPipe<z.ZodPipe<z.ZodObject<{
553
+ _meta: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
554
+ resultType: z.ZodOptional<z.ZodString>;
555
+ content: z.ZodOptional<z.ZodNever>;
556
+ structuredContent: z.ZodJSONSchema;
557
+ isError: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
558
+ }, z.core.$loose>, z.ZodTransform<{
559
+ [x: string]: unknown;
560
+ content: ({
561
+ [x: string]: unknown;
562
+ type: "text";
563
+ text: string;
564
+ } | {
565
+ [x: string]: unknown;
566
+ type: "image";
567
+ data: string;
568
+ mimeType: string;
569
+ } | {
570
+ [x: string]: unknown;
571
+ type: "resource";
572
+ resource: {
573
+ [x: string]: unknown;
574
+ uri: string;
575
+ text: string;
576
+ name?: string | undefined;
577
+ title?: string | undefined;
578
+ mimeType?: string | undefined;
579
+ } | {
580
+ [x: string]: unknown;
581
+ uri: string;
582
+ blob: string;
583
+ name?: string | undefined;
584
+ title?: string | undefined;
585
+ mimeType?: string | undefined;
586
+ };
587
+ } | {
588
+ [x: string]: unknown;
589
+ type: "resource_link";
590
+ uri: string;
591
+ name: string;
592
+ description?: string | undefined;
593
+ mimeType?: string | undefined;
594
+ } | {
595
+ [x: string]: unknown;
596
+ type: string;
597
+ })[];
598
+ _meta?: {
599
+ [x: string]: unknown;
600
+ } | undefined;
601
+ resultType?: string | undefined;
602
+ structuredContent?: unknown;
603
+ isError?: boolean | undefined;
604
+ }, {
605
+ [x: string]: unknown;
606
+ structuredContent: z.core.util.JSONType;
607
+ _meta?: {
608
+ [x: string]: unknown;
609
+ } | undefined;
610
+ resultType?: string | undefined;
611
+ content?: undefined;
612
+ isError?: boolean | undefined;
613
+ }>>, z.ZodObject<{
614
+ _meta: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
615
+ resultType: z.ZodOptional<z.ZodString>;
616
+ content: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
617
+ type: z.ZodLiteral<"text">;
618
+ text: z.ZodString;
619
+ }, z.core.$loose>, z.ZodObject<{
620
+ type: z.ZodLiteral<"image">;
621
+ data: z.ZodBase64;
622
+ mimeType: z.ZodString;
623
+ }, z.core.$loose>, z.ZodObject<{
624
+ type: z.ZodLiteral<"resource">;
625
+ resource: z.ZodUnion<readonly [z.ZodObject<{
626
+ uri: z.ZodString;
627
+ name: z.ZodOptional<z.ZodString>;
628
+ title: z.ZodOptional<z.ZodString>;
629
+ mimeType: z.ZodOptional<z.ZodString>;
630
+ text: z.ZodString;
631
+ }, z.core.$loose>, z.ZodObject<{
632
+ uri: z.ZodString;
633
+ name: z.ZodOptional<z.ZodString>;
634
+ title: z.ZodOptional<z.ZodString>;
635
+ mimeType: z.ZodOptional<z.ZodString>;
636
+ blob: z.ZodBase64;
637
+ }, z.core.$loose>]>;
638
+ }, z.core.$loose>, z.ZodObject<{
639
+ type: z.ZodLiteral<"resource_link">;
640
+ uri: z.ZodString;
641
+ name: z.ZodString;
642
+ description: z.ZodOptional<z.ZodString>;
643
+ mimeType: z.ZodOptional<z.ZodString>;
644
+ }, z.core.$loose>, z.ZodObject<{
645
+ type: z.ZodString;
528
646
  }, z.core.$loose>]>>;
529
647
  structuredContent: z.ZodOptional<z.ZodUnknown>;
530
648
  isError: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
531
- }, z.core.$loose>, z.ZodObject<{
649
+ }, z.core.$loose>>]>, z.ZodObject<{
532
650
  _meta: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
533
651
  resultType: z.ZodOptional<z.ZodString>;
534
- toolResult: z.ZodUnknown;
652
+ toolResult: z.ZodNonOptional<z.ZodUnknown>;
535
653
  }, z.core.$loose>]>;
536
654
  type CallToolResult = z.infer<typeof CallToolResultSchema>;
537
655
  declare const ListResourceTemplatesResultSchema: z.ZodObject<{
@@ -858,4 +976,4 @@ declare function fingerprintMCPAppResource(resource: MCPAppResource): Promise<st
858
976
  */
859
977
  declare function detectMCPAppResourceDrift(current: string, baseline: string): boolean;
860
978
 
861
- export { type CallToolResult, type CompleteRequestParams, type CompleteResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type InitializeResult, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPAppResource, type MCPAppResourceCSP, type MCPAppResourceMeta, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, type MCPTransportCloseOptions, type MCPTransportSendOptions, MCP_APP_MIME_TYPE, type McpProviderMetadata, type OAuthAuthorizationServerInformation, type OAuthClientInformation, type OAuthClientMetadata, type OAuthClientProvider, type OAuthTokens, UnauthorizedError, auth, createMCPClient, detectMCPAppResourceDrift, type MCPClient as experimental_MCPClient, type ClientCapabilities as experimental_MCPClientCapabilities, type MCPClientConfig as experimental_MCPClientConfig, createMCPClient as experimental_createMCPClient, fingerprintMCPAppResource, mcpAppClientCapabilities, readMCPAppResource, splitMCPAppTools, validateJSONRPCMessage };
979
+ export { type CallToolResult, type CompleteRequestParams, type CompleteResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type InitializeResult, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPAppResource, type MCPAppResourceCSP, type MCPAppResourceMeta, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, type MCPTransportCloseOptions, type MCPTransportSendOptions, MCP_APP_MIME_TYPE, type McpProviderMetadata, type McpToolAnnotations, type OAuthAuthorizationServerInformation, type OAuthClientInformation, type OAuthClientMetadata, type OAuthClientProvider, type OAuthTokens, UnauthorizedError, auth, createMCPClient, detectMCPAppResourceDrift, type MCPClient as experimental_MCPClient, type ClientCapabilities as experimental_MCPClientCapabilities, type MCPClientConfig as experimental_MCPClientConfig, createMCPClient as experimental_createMCPClient, fingerprintMCPAppResource, mcpAppClientCapabilities, readMCPAppResource, splitMCPAppTools, validateJSONRPCMessage };
package/dist/index.js CHANGED
@@ -90,7 +90,11 @@ var ToolSchema = z.object({
90
90
  outputSchema: z.optional(z.object({}).loose()),
91
91
  annotations: z.optional(
92
92
  z.object({
93
- title: z.optional(z.string())
93
+ title: z.optional(z.string()),
94
+ readOnlyHint: z.optional(z.boolean()),
95
+ destructiveHint: z.optional(z.boolean()),
96
+ idempotentHint: z.optional(z.boolean()),
97
+ openWorldHint: z.optional(z.boolean())
94
98
  }).loose()
95
99
  ),
96
100
  _meta: ToolMetaSchema
@@ -153,23 +157,46 @@ var ResourceLinkContentSchema = z.object({
153
157
  description: z.optional(z.string()),
154
158
  mimeType: z.optional(z.string())
155
159
  }).loose();
156
- var CallToolResultSchema = ResultSchema.extend({
160
+ var UnknownContentSchema = z.object({ type: z.string() }).loose().refine(
161
+ (content) => !["text", "image", "resource", "resource_link"].includes(content.type),
162
+ { message: "Known content types must match their schema" }
163
+ );
164
+ var CallToolResultWithContentSchema = ResultSchema.extend({
157
165
  content: z.array(
158
166
  z.union([
159
167
  TextContentSchema,
160
168
  ImageContentSchema,
161
169
  EmbeddedResourceSchema,
162
- ResourceLinkContentSchema
170
+ ResourceLinkContentSchema,
171
+ UnknownContentSchema
163
172
  ])
164
173
  ),
165
174
  /**
166
- * @see https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content
175
+ * @see https://modelcontextprotocol.io/specification/2026-07-28/server/tools#structured-content
167
176
  */
168
177
  structuredContent: z.optional(z.unknown()),
169
178
  isError: z.boolean().default(false).optional()
170
- }).or(
179
+ });
180
+ var CallToolResultWithStructuredContentSchema = ResultSchema.extend({
181
+ content: z.never().optional(),
182
+ structuredContent: z.json(),
183
+ isError: z.boolean().default(false).optional()
184
+ }).transform(
185
+ (result) => ({
186
+ ...result,
187
+ content: [
188
+ {
189
+ type: "text",
190
+ text: JSON.stringify(result.structuredContent)
191
+ }
192
+ ]
193
+ })
194
+ ).pipe(CallToolResultWithContentSchema);
195
+ var CallToolResultSchema = CallToolResultWithContentSchema.or(
196
+ CallToolResultWithStructuredContentSchema
197
+ ).or(
171
198
  ResultSchema.extend({
172
- toolResult: z.unknown()
199
+ toolResult: z.unknown().nonoptional()
173
200
  })
174
201
  );
175
202
  var ResourceTemplateSchema = z.object({
@@ -840,7 +867,8 @@ function buildDiscoveryUrls(authorizationServerUrl) {
840
867
  return urlsToTry;
841
868
  }
842
869
  function assertMetadataIssuerMatches(metadata, expectedIssuer) {
843
- if (metadata.issuer !== expectedIssuer) {
870
+ const issuerMatches = metadata.issuer === expectedIssuer || expectedIssuer === new URL(expectedIssuer).origin && metadata.issuer === `${expectedIssuer}/`;
871
+ if (!issuerMatches) {
844
872
  throw new MCPClientOAuthError({
845
873
  message: `OAuth authorization server metadata issuer ${metadata.issuer} does not match expected issuer ${expectedIssuer}`
846
874
  });
@@ -3120,6 +3148,15 @@ var DefaultMCPClient = class {
3120
3148
  clientName: this.clientInfo.name,
3121
3149
  toolName: name3,
3122
3150
  ...resolvedTitle != null ? { title: resolvedTitle } : {},
3151
+ ...annotations != null ? {
3152
+ annotations: {
3153
+ ...annotations.title != null ? { title: annotations.title } : {},
3154
+ ...annotations.readOnlyHint != null ? { readOnlyHint: annotations.readOnlyHint } : {},
3155
+ ...annotations.destructiveHint != null ? { destructiveHint: annotations.destructiveHint } : {},
3156
+ ...annotations.idempotentHint != null ? { idempotentHint: annotations.idempotentHint } : {},
3157
+ ...annotations.openWorldHint != null ? { openWorldHint: annotations.openWorldHint } : {}
3158
+ }
3159
+ } : {},
3123
3160
  ...(appMeta == null ? void 0 : appMeta.resourceUri) != null ? {
3124
3161
  app: {
3125
3162
  ...appMeta,
@@ -3185,7 +3222,9 @@ var DefaultMCPClient = class {
3185
3222
  return validationResult.value;
3186
3223
  }
3187
3224
  if ("content" in result && Array.isArray(result.content)) {
3188
- const textContent = result.content.find((c) => c.type === "text");
3225
+ const textContent = result.content.find(
3226
+ (content) => content.type === "text"
3227
+ );
3189
3228
  if (textContent && "text" in textContent) {
3190
3229
  const parseResult = await safeParseJSON({
3191
3230
  text: textContent.text,