@ai-sdk/mcp 1.0.42 → 1.0.44

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,26 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 1.0.44
4
+
5
+ ### Patch Changes
6
+
7
+ - 77775a4: feat(mcp): expose `statusCode`, `url`, and `responseBody` on `MCPClientError` for HTTP transport failures
8
+
9
+ `MCPClientError` now carries structured HTTP context when it originates from the
10
+ streamable HTTP transport. This lets downstream consumers (e.g. agent frameworks
11
+ that need to decide whether to fall back from streamable HTTP to legacy SSE
12
+ transport per the MCP spec) branch on the actual response status without parsing
13
+ the error message string.
14
+
15
+ Fields are optional — they remain `undefined` for stdio transport errors and for
16
+ non-response failures (network errors, aborts).
17
+
18
+ ## 1.0.43
19
+
20
+ ### Patch Changes
21
+
22
+ - e2b923f: fix(mcp): deduplicate auth refresh on http transport
23
+
3
24
  ## 1.0.42
4
25
 
5
26
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # AI SDK - Model Context Protocol Client
2
+
3
+ The **Model Context Protocol (MCP) client** for the
4
+ [AI SDK](https://ai-sdk.dev/docs) lets you connect to MCP servers and use their
5
+ tools with AI SDK functions like `generateText` and `streamText`.
6
+
7
+ ## Setup
8
+
9
+ The MCP client is available in the `@ai-sdk/mcp` module. You can install it with
10
+
11
+ ```bash
12
+ npm i @ai-sdk/mcp ai zod
13
+ ```
14
+
15
+ ## Skill for Coding Agents
16
+
17
+ If you use coding agents such as Claude Code or Cursor, we highly recommend
18
+ adding the AI SDK skill to your repository:
19
+
20
+ ```shell
21
+ npx skills add vercel/ai
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ Create an MCP client with `createMCPClient()`, fetch the server tools with
27
+ `mcpClient.tools()`, and pass them to an AI SDK call:
28
+
29
+ ```ts
30
+ import { createMCPClient } from '@ai-sdk/mcp';
31
+ import { generateText, isStepCount } from 'ai';
32
+
33
+ const mcpClient = await createMCPClient({
34
+ transport: {
35
+ type: 'http',
36
+ url: 'https://your-server.com/mcp',
37
+ headers: {
38
+ Authorization: `Bearer ${process.env.MCP_API_KEY}`,
39
+ },
40
+ },
41
+ });
42
+
43
+ try {
44
+ const tools = await mcpClient.tools();
45
+
46
+ const { text } = await generateText({
47
+ model: 'openai/gpt-5.4',
48
+ tools,
49
+ stopWhen: isStepCount(10),
50
+ prompt: 'Use the available tools to answer the user question.',
51
+ });
52
+
53
+ console.log(text);
54
+ } finally {
55
+ await mcpClient.close();
56
+ }
57
+ ```
58
+
59
+ The client converts MCP tool definitions into AI SDK tools, so model calls can
60
+ use them through the standard `tools` option.
61
+
62
+ For streaming responses, close the MCP client when the stream finishes:
63
+
64
+ ```ts
65
+ import { createMCPClient } from '@ai-sdk/mcp';
66
+ import { streamText } from 'ai';
67
+
68
+ const mcpClient = await createMCPClient({
69
+ transport: {
70
+ type: 'http',
71
+ url: 'https://your-server.com/mcp',
72
+ },
73
+ });
74
+
75
+ const result = streamText({
76
+ model: 'openai/gpt-5.4',
77
+ tools: await mcpClient.tools(),
78
+ prompt: 'Use the available tools to answer the user question.',
79
+ onFinish: async () => {
80
+ await mcpClient.close();
81
+ },
82
+ });
83
+
84
+ for await (const textPart of result.textStream) {
85
+ process.stdout.write(textPart);
86
+ }
87
+ ```
88
+
89
+ ## Transports
90
+
91
+ HTTP is recommended for production deployments:
92
+
93
+ ```ts
94
+ import { createMCPClient } from '@ai-sdk/mcp';
95
+
96
+ const mcpClient = await createMCPClient({
97
+ transport: {
98
+ type: 'http',
99
+ url: 'https://your-server.com/mcp',
100
+ },
101
+ });
102
+ ```
103
+
104
+ SSE is also supported for MCP servers that use Server-Sent Events:
105
+
106
+ ```ts
107
+ const mcpClient = await createMCPClient({
108
+ transport: {
109
+ type: 'sse',
110
+ url: 'https://your-server.com/sse',
111
+ },
112
+ });
113
+ ```
114
+
115
+ For local MCP servers, you can use stdio transport from the `@ai-sdk/mcp/mcp-stdio`
116
+ subpath:
117
+
118
+ ```ts
119
+ import { createMCPClient } from '@ai-sdk/mcp';
120
+ import { Experimental_StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';
121
+
122
+ const mcpClient = await createMCPClient({
123
+ transport: new Experimental_StdioMCPTransport({
124
+ command: 'node',
125
+ args: ['server.js'],
126
+ }),
127
+ });
128
+ ```
129
+
130
+ ## Documentation
131
+
132
+ Please check out the
133
+ [AI SDK MCP documentation](https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools) for
134
+ more information.
package/dist/index.js CHANGED
@@ -54,12 +54,18 @@ var MCPClientError = class extends (_b = import_provider.AISDKError, _a = symbol
54
54
  message,
55
55
  cause,
56
56
  data,
57
- code
57
+ code,
58
+ statusCode,
59
+ url,
60
+ responseBody
58
61
  }) {
59
62
  super({ name: name3, message, cause });
60
63
  this[_a] = true;
61
64
  this.data = data;
62
65
  this.code = code;
66
+ this.statusCode = statusCode;
67
+ this.url = url;
68
+ this.responseBody = responseBody;
63
69
  }
64
70
  static isInstance(error) {
65
71
  return import_provider.AISDKError.hasMarker(error, marker);
@@ -1351,6 +1357,24 @@ var HttpMCPTransport = class {
1351
1357
  (0, import_provider_utils4.getRuntimeEnvironmentUserAgent)()
1352
1358
  );
1353
1359
  }
1360
+ /**
1361
+ * Runs a single OAuth recovery flow for concurrent 401 responses.
1362
+ */
1363
+ authorizeOnce(resourceMetadataUrl) {
1364
+ if (!this.authProvider) {
1365
+ return Promise.resolve("REDIRECT");
1366
+ }
1367
+ if (!this.authPromise) {
1368
+ this.authPromise = auth(this.authProvider, {
1369
+ serverUrl: this.url,
1370
+ resourceMetadataUrl,
1371
+ fetchFn: this.fetchFn
1372
+ }).finally(() => {
1373
+ this.authPromise = void 0;
1374
+ });
1375
+ }
1376
+ return this.authPromise;
1377
+ }
1354
1378
  async start() {
1355
1379
  if (this.abortController) {
1356
1380
  throw new MCPClientError({
@@ -1401,11 +1425,7 @@ var HttpMCPTransport = class {
1401
1425
  if (response.status === 401 && this.authProvider && !triedAuth) {
1402
1426
  this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1403
1427
  try {
1404
- const result = await auth(this.authProvider, {
1405
- serverUrl: this.url,
1406
- resourceMetadataUrl: this.resourceMetadataUrl,
1407
- fetchFn: this.fetchFn
1408
- });
1428
+ const result = await this.authorizeOnce(this.resourceMetadataUrl);
1409
1429
  if (result !== "AUTHORIZED") {
1410
1430
  const error2 = new UnauthorizedError();
1411
1431
  throw error2;
@@ -1429,7 +1449,10 @@ var HttpMCPTransport = class {
1429
1449
  errorMessage += ". This server does not support HTTP transport. Try using `sse` transport instead";
1430
1450
  }
1431
1451
  const error2 = new MCPClientError({
1432
- message: errorMessage
1452
+ message: errorMessage,
1453
+ statusCode: response.status,
1454
+ url: this.url.href,
1455
+ responseBody: text != null ? text : void 0
1433
1456
  });
1434
1457
  (_c = this.onerror) == null ? void 0 : _c.call(this, error2);
1435
1458
  throw error2;
@@ -1448,7 +1471,9 @@ var HttpMCPTransport = class {
1448
1471
  if (contentType.includes("text/event-stream")) {
1449
1472
  if (!response.body) {
1450
1473
  const error2 = new MCPClientError({
1451
- message: "MCP HTTP Transport Error: text/event-stream response without body"
1474
+ message: "MCP HTTP Transport Error: text/event-stream response without body",
1475
+ statusCode: response.status,
1476
+ url: this.url.href
1452
1477
  });
1453
1478
  (_e = this.onerror) == null ? void 0 : _e.call(this, error2);
1454
1479
  throw error2;
@@ -1486,7 +1511,9 @@ var HttpMCPTransport = class {
1486
1511
  return;
1487
1512
  }
1488
1513
  const error = new MCPClientError({
1489
- message: `MCP HTTP Transport Error: Unexpected content type: ${contentType}`
1514
+ message: `MCP HTTP Transport Error: Unexpected content type: ${contentType}`,
1515
+ statusCode: response.status,
1516
+ url: this.url.href
1490
1517
  });
1491
1518
  (_f = this.onerror) == null ? void 0 : _f.call(this, error);
1492
1519
  throw error;
@@ -1551,11 +1578,7 @@ var HttpMCPTransport = class {
1551
1578
  if (response.status === 401 && this.authProvider && !triedAuth) {
1552
1579
  this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1553
1580
  try {
1554
- const result = await auth(this.authProvider, {
1555
- serverUrl: this.url,
1556
- resourceMetadataUrl: this.resourceMetadataUrl,
1557
- fetchFn: this.fetchFn
1558
- });
1581
+ const result = await this.authorizeOnce(this.resourceMetadataUrl);
1559
1582
  if (result !== "AUTHORIZED") {
1560
1583
  const error = new UnauthorizedError();
1561
1584
  (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);
@@ -1572,7 +1595,9 @@ var HttpMCPTransport = class {
1572
1595
  }
1573
1596
  if (!response.ok || !response.body) {
1574
1597
  const error = new MCPClientError({
1575
- message: `MCP HTTP Transport Error: GET SSE failed: ${response.status} ${response.statusText}`
1598
+ message: `MCP HTTP Transport Error: GET SSE failed: ${response.status} ${response.statusText}`,
1599
+ statusCode: response.status,
1600
+ url: this.url.href
1576
1601
  });
1577
1602
  (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1578
1603
  return;