v2 ci: add Bun and Deno integration tests (#1607)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Konstantin Konstantinov 2026-03-05 21:38:17 +02:00 • committed by GitHub
commit 049f26ef53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 176 additions and 6 deletions

View file

@ -58,11 +58,47 @@ jobs:
- run: pnpm test:all
test-runtimes:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- runtime: bun
version: "1.x"
- runtime: deno
version: v2.x
steps:
- uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Set up Bun
if: matrix.runtime == 'bun'
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ matrix.version }}
- name: Set up Deno
if: matrix.runtime == 'deno'
uses: denoland/setup-deno@v2
with:
deno-version: ${{ matrix.version }}
- run: pnpm install
- run: pnpm build:all
- name: Run ${{ matrix.runtime }} integration tests
run: pnpm --filter @modelcontextprotocol/test-integration test:integration:${{ matrix.runtime }}
publish:
runs-on: ubuntu-latest
if: github.event_name == 'release'
environment: release
needs: [build, test]
needs: [build, test, test-runtimes]
permissions:
contents: read

View file

@ -25,7 +25,7 @@
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.
This repository contains the TypeScript SDK implementation of the MCP specification and ships:
This repository contains the TypeScript SDK implementation of the MCP specification. It runs on **Node.js**, **Bun**, and **Deno**, and ships:
- MCP **server** libraries (tools/resources/prompts, Streamable HTTP, stdio, auth helpers)
- 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
```bash
npm install @modelcontextprotocol/server zod
# or
bun add @modelcontextprotocol/server zod
# or
deno add npm:@modelcontextprotocol/server npm:zod
```
### Client
```bash
npm install @modelcontextprotocol/client zod
# or
bun add @modelcontextprotocol/client zod
# or
deno add npm:@modelcontextprotocol/client npm:zod
```
### Optional middleware packages

View file

@ -19,10 +19,13 @@ This quickstart assumes you have familiarity with:
Before starting, ensure your system meets these requirements:
- Node.js 20 or higher installed
- Node.js 20 or higher installed (or **Bun** / **Deno** — the SDK supports all three runtimes)
- Latest version of `npm` installed
- An Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys)
> [!TIP]
> 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`.
## Set up your environment
First, let's create and set up our project:

View file

@ -36,6 +36,9 @@ node --version
npm --version
```
> [!TIP]
> 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.
## Set up your environment
First, let's install Node.js and npm if you haven't already. You can download them from [nodejs.org](https://nodejs.org/).

View file

@ -29,7 +29,9 @@
"test:watch": "vitest",
"start": "npm run server",
"server": "tsx watch --clear-screen=false scripts/cli.ts server",
"client": "tsx scripts/cli.ts client"
"client": "tsx scripts/cli.ts client",
"test:integration:bun": "bun test test/server/bun.test.ts",
"test:integration:deno": "deno test --no-check --allow-net --allow-read --allow-env test/server/deno.test.ts"
},
"devDependencies": {
"@modelcontextprotocol/core": "workspace:^",

View file

@ -0,0 +1,57 @@
/**
* Bun integration test
*
* Verifies the MCP server and client packages work natively on Bun.
* Run with: bun test test/server/bun.test.ts
*/
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
import { McpServer, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server';
// eslint-disable-next-line import/no-unresolved
import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
import * as z from 'zod/v4';
describe('MCP on Bun', () => {
let httpServer: ReturnType<typeof Bun.serve>;
let transport: WebStandardStreamableHTTPServerTransport;
beforeAll(async () => {
const mcpServer = new McpServer({ name: 'test-server', version: '1.0.0' });
mcpServer.registerTool(
'greet',
{
description: 'Greet someone',
inputSchema: z.object({ name: z.string() })
},
async ({ name }) => ({
content: [{ type: 'text' as const, text: `Hello, ${name}!` }]
})
);
transport = new WebStandardStreamableHTTPServerTransport();
await mcpServer.connect(transport);
httpServer = Bun.serve({
port: 0,
fetch: req => transport.handleRequest(req)
});
});
afterAll(async () => {
await transport?.close();
httpServer?.stop();
});
it('should handle MCP tool calls', async () => {
const client = new Client({ name: 'test-client', version: '1.0.0' });
const clientTransport = new StreamableHTTPClientTransport(new URL(`http://localhost:${httpServer.port}`));
await client.connect(clientTransport);
const result = await client.callTool({ name: 'greet', arguments: { name: 'Bun' } });
expect(result.content).toEqual([{ type: 'text', text: 'Hello, Bun!' }]);
await client.close();
});
});

View file

@ -0,0 +1,53 @@
/**
* Deno integration test
*
* Verifies the MCP server and client packages work natively on Deno.
* Run with: deno test --no-check --allow-net --allow-read --allow-env test/server/deno.test.ts
*/
import assert from 'node:assert/strict';
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
import { McpServer, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
Deno.test({
name: 'MCP tool calls work on Deno',
sanitizeOps: false,
sanitizeResources: false,
async fn() {
const mcpServer = new McpServer({ name: 'test-server', version: '1.0.0' });
mcpServer.registerTool(
'greet',
{
description: 'Greet someone',
inputSchema: z.object({ name: z.string() })
},
async ({ name }) => ({
content: [{ type: 'text' as const, text: `Hello, ${name}!` }]
})
);
const transport = new WebStandardStreamableHTTPServerTransport();
await mcpServer.connect(transport);
const httpServer = Deno.serve({ port: 0 }, req => transport.handleRequest(req));
const port = httpServer.addr.port;
try {
const client = new Client({ name: 'test-client', version: '1.0.0' });
const clientTransport = new StreamableHTTPClientTransport(new URL(`http://localhost:${port}`));
await client.connect(clientTransport);
const result = await client.callTool({ name: 'greet', arguments: { name: 'Deno' } });
assert.deepStrictEqual(result.content, [{ type: 'text', text: 'Hello, Deno!' }]);
await client.close();
} finally {
await transport.close();
await httpServer.shutdown();
}
}
});

View file

@ -1,7 +1,7 @@
{
"extends": "@modelcontextprotocol/tsconfig",
"include": ["./"],
"exclude": ["node_modules", "dist"],
"exclude": ["node_modules", "dist", "test/server/bun.test.ts", "test/server/deno.test.ts"],
"compilerOptions": {
"paths": {
"*": ["./*"],

View file

@ -1,3 +1,11 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import baseConfig from '../../common/vitest-config/vitest.config.js';
export default baseConfig;
export default mergeConfig(
baseConfig,
defineConfig({
test: {
exclude: ['**/dist/**', '**/bun.test.ts', '**/deno.test.ts']
}
})
);