v2 ci: add Bun and Deno integration tests (#1607)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
26c7242d67
commit
049f26ef53
9 changed files with 176 additions and 6 deletions
38
.github/workflows/main.yml
vendored
38
.github/workflows/main.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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/).
|
||||
|
|
|
|||
|
|
@ -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:^",
|
||||
|
|
|
|||
57
test/integration/test/server/bun.test.ts
Normal file
57
test/integration/test/server/bun.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
53
test/integration/test/server/deno.test.ts
Normal file
53
test/integration/test/server/deno.test.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -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": {
|
||||
"*": ["./*"],
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue