Skip to content

Commit 2e0870c

Browse files
authored
Merge branch 'main' into groups/prompt-meta
2 parents 01a51f6 + 4a7cdf4 commit 2e0870c

21 files changed

Lines changed: 1362 additions & 409 deletions

.github/workflows/main.yml

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,47 @@ jobs:
5858

5959
- run: pnpm test:all
6060

61+
test-runtimes:
62+
runs-on: ubuntu-latest
63+
strategy:
64+
fail-fast: false
65+
matrix:
66+
include:
67+
- runtime: bun
68+
version: "1.x"
69+
- runtime: deno
70+
version: v2.x
71+
steps:
72+
- uses: actions/checkout@v6
73+
- name: Install pnpm
74+
uses: pnpm/action-setup@v4
75+
with:
76+
run_install: false
77+
- uses: actions/setup-node@v6
78+
with:
79+
node-version: 24
80+
cache: pnpm
81+
cache-dependency-path: pnpm-lock.yaml
82+
- name: Set up Bun
83+
if: matrix.runtime == 'bun'
84+
uses: oven-sh/setup-bun@v2
85+
with:
86+
bun-version: ${{ matrix.version }}
87+
- name: Set up Deno
88+
if: matrix.runtime == 'deno'
89+
uses: denoland/setup-deno@v2
90+
with:
91+
deno-version: ${{ matrix.version }}
92+
- run: pnpm install
93+
- run: pnpm build:all
94+
- name: Run ${{ matrix.runtime }} integration tests
95+
run: pnpm --filter @modelcontextprotocol/test-integration test:integration:${{ matrix.runtime }}
96+
6197
publish:
6298
runs-on: ubuntu-latest
6399
if: github.event_name == 'release'
64100
environment: release
65-
needs: [build, test]
101+
needs: [build, test, test-runtimes]
66102

67103
permissions:
68104
contents: read

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
The Model Context Protocol (MCP) allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction.
2727

28-
This repository contains the TypeScript SDK implementation of the MCP specification and ships:
28+
This repository contains the TypeScript SDK implementation of the MCP specification. It runs on **Node.js**, **Bun**, and **Deno**, and ships:
2929

3030
- MCP **server** libraries (tools/resources/prompts, Streamable HTTP, stdio, auth helpers)
3131
- MCP **client** libraries (transports, high-level helpers, OAuth helpers)
@@ -57,12 +57,20 @@ They are intentionally thin adapters: they should not introduce new MCP function
5757

5858
```bash
5959
npm install @modelcontextprotocol/server zod
60+
# or
61+
bun add @modelcontextprotocol/server zod
62+
# or
63+
deno add npm:@modelcontextprotocol/server npm:zod
6064
```
6165

6266
### Client
6367

6468
```bash
6569
npm install @modelcontextprotocol/client zod
70+
# or
71+
bun add @modelcontextprotocol/client zod
72+
# or
73+
deno add npm:@modelcontextprotocol/client npm:zod
6674
```
6775

6876
### Optional middleware packages

docs/client-quickstart.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ This quickstart assumes you have familiarity with:
1919

2020
Before starting, ensure your system meets these requirements:
2121

22-
- Node.js 20 or higher installed
22+
- Node.js 20 or higher installed (or **Bun** / **Deno** — the SDK supports all three runtimes)
2323
- Latest version of `npm` installed
2424
- An Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys)
2525

26+
> [!TIP]
27+
> This tutorial uses Node.js and npm, but you can substitute `bun` or `deno` commands where appropriate. For example, use `bun add` instead of `npm install`, or run the client with `bun run` / `deno run`.
28+
2629
## Set up your environment
2730

2831
First, let's create and set up our project:
@@ -109,7 +112,7 @@ First, let's set up our imports and create the basic client class in `src/index.
109112

110113
```ts source="../examples/client-quickstart/src/index.ts#prelude"
111114
import Anthropic from '@anthropic-ai/sdk';
112-
import { Client, StdioClientTransport, type CallToolResult } from '@modelcontextprotocol/client';
115+
import { Client, StdioClientTransport } from '@modelcontextprotocol/client';
113116
import readline from 'readline/promises';
114117

115118
const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
@@ -201,7 +204,7 @@ Now let's add the core functionality for processing queries and handling tool ca
201204
const result = await this.mcp.callTool({
202205
name: toolName,
203206
arguments: toolArgs,
204-
}) as CallToolResult;
207+
});
205208

206209
finalText.push(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
207210

docs/server-quickstart.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ node --version
3636
npm --version
3737
```
3838

39+
> [!TIP]
40+
> The MCP SDK also works with **Bun** and **Deno**. This tutorial uses Node.js, but you can substitute `bun` or `deno` commands where appropriate. For HTTP-based servers on Bun or Deno, use `WebStandardStreamableHTTPServerTransport` instead of the Node.js-specific transport — see the [server guide](./server.md) for details.
41+
3942
## Set up your environment
4043

4144
First, let's install Node.js and npm if you haven't already. You can download them from [nodejs.org](https://nodejs.org/).

examples/client-quickstart/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//#region prelude
22
import Anthropic from '@anthropic-ai/sdk';
3-
import { Client, StdioClientTransport, type CallToolResult } from '@modelcontextprotocol/client';
3+
import { Client, StdioClientTransport } from '@modelcontextprotocol/client';
44
import readline from 'readline/promises';
55

66
const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
@@ -84,7 +84,7 @@ class MCPClient {
8484
const result = await this.mcp.callTool({
8585
name: toolName,
8686
arguments: toolArgs,
87-
}) as CallToolResult;
87+
});
8888

8989
finalText.push(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
9090

examples/client/src/elicitationUrlExample.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import { createServer } from 'node:http';
99
import { createInterface } from 'node:readline';
1010

1111
import type {
12-
CallToolRequest,
13-
CallToolResult,
1412
ElicitRequest,
1513
ElicitRequestURLParams,
1614
ElicitResult,
@@ -687,16 +685,8 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<vo
687685
}
688686

689687
try {
690-
const request: CallToolRequest = {
691-
method: 'tools/call',
692-
params: {
693-
name,
694-
arguments: args
695-
}
696-
};
697-
698688
console.log(`Calling tool '${name}' with args:`, args);
699-
const result = (await client.request(request)) as CallToolResult;
689+
const result = await client.callTool({ name, arguments: args });
700690

701691
console.log('Tool result:');
702692
const resourceLinks: ResourceLink[] = [];

examples/client/src/multipleClientsParallel.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/client';
1+
import type { CallToolResult } from '@modelcontextprotocol/client';
22
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
33

44
/**
@@ -48,19 +48,14 @@ async function createAndRunClient(config: ClientConfig): Promise<{ id: string; r
4848

4949
// Call the specified tool
5050
console.log(`[${config.id}] Calling tool: ${config.toolName}`);
51-
const toolRequest: CallToolRequest = {
52-
method: 'tools/call',
53-
params: {
54-
name: config.toolName,
55-
arguments: {
56-
...config.toolArguments,
57-
// Add client ID to arguments for identification in notifications
58-
caller: config.id
59-
}
51+
const result = await client.callTool({
52+
name: config.toolName,
53+
arguments: {
54+
...config.toolArguments,
55+
// Add client ID to arguments for identification in notifications
56+
caller: config.id
6057
}
61-
};
62-
63-
const result = (await client.request(toolRequest)) as CallToolResult;
58+
});
6459
console.log(`[${config.id}] Tool call completed`);
6560

6661
// Keep the connection open for a bit to receive notifications

examples/client/src/parallelToolCallsClient.ts

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CallToolRequest, CallToolResult, ListToolsRequest } from '@modelcontextprotocol/client';
1+
import type { CallToolResult, ListToolsRequest } from '@modelcontextprotocol/client';
22
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
33

44
/**
@@ -108,58 +108,40 @@ async function listTools(client: Client): Promise<void> {
108108
async function startParallelNotificationTools(client: Client): Promise<Record<string, CallToolResult>> {
109109
try {
110110
// Define multiple tool calls with different configurations
111-
const toolCalls: Array<{ caller: string; request: CallToolRequest }> = [
111+
const toolCalls = [
112112
{
113113
caller: 'fast-notifier',
114-
request: {
115-
method: 'tools/call',
116-
params: {
117-
name: 'start-notification-stream',
118-
arguments: {
119-
interval: 2, // 0.5 second between notifications
120-
count: 10, // Send 10 notifications
121-
caller: 'fast-notifier' // Identify this tool call
122-
}
123-
}
114+
args: {
115+
interval: 2, // 0.5 second between notifications
116+
count: 10, // Send 10 notifications
117+
caller: 'fast-notifier' // Identify this tool call
124118
}
125119
},
126120
{
127121
caller: 'slow-notifier',
128-
request: {
129-
method: 'tools/call',
130-
params: {
131-
name: 'start-notification-stream',
132-
arguments: {
133-
interval: 5, // 2 seconds between notifications
134-
count: 5, // Send 5 notifications
135-
caller: 'slow-notifier' // Identify this tool call
136-
}
137-
}
122+
args: {
123+
interval: 5, // 2 seconds between notifications
124+
count: 5, // Send 5 notifications
125+
caller: 'slow-notifier' // Identify this tool call
138126
}
139127
},
140128
{
141129
caller: 'burst-notifier',
142-
request: {
143-
method: 'tools/call',
144-
params: {
145-
name: 'start-notification-stream',
146-
arguments: {
147-
interval: 1, // 0.1 second between notifications
148-
count: 3, // Send just 3 notifications
149-
caller: 'burst-notifier' // Identify this tool call
150-
}
151-
}
130+
args: {
131+
interval: 1, // 0.1 second between notifications
132+
count: 3, // Send just 3 notifications
133+
caller: 'burst-notifier' // Identify this tool call
152134
}
153135
}
154136
];
155137

156138
console.log(`Starting ${toolCalls.length} notification tools in parallel...`);
157139

158140
// Start all tool calls in parallel
159-
const toolPromises = toolCalls.map(({ caller, request }) => {
141+
const toolPromises = toolCalls.map(({ caller, args }) => {
160142
console.log(`Starting tool call for ${caller}...`);
161143
return client
162-
.request(request)
144+
.callTool({ name: 'start-notification-stream', arguments: args })
163145
.then(result => ({ caller, result }))
164146
.catch(error => {
165147
console.error(`Error in tool call for ${caller}:`, error);
@@ -173,7 +155,7 @@ async function startParallelNotificationTools(client: Client): Promise<Record<st
173155
// Organize results by caller
174156
const resultsByTool: Record<string, CallToolResult> = {};
175157
for (const { caller, result } of results) {
176-
resultsByTool[caller] = result as CallToolResult;
158+
resultsByTool[caller] = result;
177159
}
178160

179161
return resultsByTool;

examples/client/src/simpleOAuthClient.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createServer } from 'node:http';
44
import { createInterface } from 'node:readline';
55
import { URL } from 'node:url';
66

7-
import type { CallToolRequest, CallToolResult, ListToolsRequest, OAuthClientMetadata } from '@modelcontextprotocol/client';
7+
import type { CallToolResult, ListToolsRequest, OAuthClientMetadata } from '@modelcontextprotocol/client';
88
import { Client, StreamableHTTPClientTransport, UnauthorizedError } from '@modelcontextprotocol/client';
99
import open from 'open';
1010

@@ -306,15 +306,10 @@ class InteractiveOAuthClient {
306306
}
307307

308308
try {
309-
const request: CallToolRequest = {
310-
method: 'tools/call',
311-
params: {
312-
name: toolName,
313-
arguments: toolArgs
314-
}
315-
};
316-
317-
const result = (await this.client.request(request)) as CallToolResult;
309+
const result = await this.client.callTool({
310+
name: toolName,
311+
arguments: toolArgs
312+
});
318313

319314
console.log(`\n🔧 Tool '${toolName}' result:`);
320315
if (result.content) {

examples/client/src/simpleStreamableHttp.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { createInterface } from 'node:readline';
22

33
import type {
4-
CallToolRequest,
54
CallToolResult,
65
GetPromptRequest,
76
ListPromptsRequest,
@@ -646,16 +645,8 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<vo
646645
}
647646

648647
try {
649-
const request: CallToolRequest = {
650-
method: 'tools/call',
651-
params: {
652-
name,
653-
arguments: args
654-
}
655-
};
656-
657648
console.log(`Calling tool '${name}' with args:`, args);
658-
const result = (await client.request(request)) as CallToolResult;
649+
const result = await client.callTool({ name, arguments: args });
659650

660651
console.log('Tool result:');
661652
const resourceLinks: ResourceLink[] = [];
@@ -746,23 +737,18 @@ async function runNotificationsToolWithResumability(interval: number, count: num
746737
console.log(`Starting notification stream with resumability: interval=${interval}ms, count=${count || 'unlimited'}`);
747738
console.log(`Using resumption token: ${notificationsToolLastEventId || 'none'}`);
748739

749-
const request: CallToolRequest = {
750-
method: 'tools/call',
751-
params: {
752-
name: 'start-notification-stream',
753-
arguments: { interval, count }
754-
}
755-
};
756-
757740
const onLastEventIdUpdate = (event: string) => {
758741
notificationsToolLastEventId = event;
759742
console.log(`Updated resumption token: ${event}`);
760743
};
761744

762-
const result = (await client.request(request, {
763-
resumptionToken: notificationsToolLastEventId,
764-
onresumptiontoken: onLastEventIdUpdate
765-
})) as CallToolResult;
745+
const result = await client.callTool(
746+
{ name: 'start-notification-stream', arguments: { interval, count } },
747+
{
748+
resumptionToken: notificationsToolLastEventId,
749+
onresumptiontoken: onLastEventIdUpdate
750+
}
751+
);
766752

767753
console.log('Tool result:');
768754
for (const item of result.content) {

0 commit comments

Comments
 (0)