Merge branch 'main' into fix/module-format

This commit is contained in:
Charles 2025-01-03 21:31:48 +08:00 • committed by GitHub
commit 0e76d4469e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 92 additions and 14 deletions

View file

@ -24,6 +24,10 @@ npm install @modelcontextprotocol/sdk
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const transport = new StdioClientTransport({
command: "path/to/server",
@ -61,6 +65,10 @@ const resourceContent = await client.request(
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server({
name: "example-server",

View file

@ -1,6 +1,6 @@
{
"name": "@modelcontextprotocol/sdk",
"version": "1.0.4",
"version": "1.1.0",
"description": "Model Context Protocol implementation for TypeScript",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",

View file

@ -12,13 +12,17 @@ export class SSEClientTransport implements Transport {
private _endpoint?: URL;
private _abortController?: AbortController;
private _url: URL;
private _eventSourceInit?: EventSourceInit;
private _requestInit?: RequestInit;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
constructor(url: URL) {
constructor(url: URL, opts?: { eventSourceInit?: EventSourceInit, requestInit?: RequestInit }) {
this._url = url;
this._eventSourceInit = opts?.eventSourceInit;
this._requestInit = opts?.requestInit;
}
start(): Promise<void> {
@ -29,7 +33,7 @@ export class SSEClientTransport implements Transport {
}
return new Promise((resolve, reject) => {
this._eventSource = new EventSource(this._url.href);
this._eventSource = new EventSource(this._url.href, this._eventSourceInit);
this._abortController = new AbortController();
this._eventSource.onerror = (event) => {
@ -90,14 +94,17 @@ export class SSEClientTransport implements Transport {
}
try {
const response = await fetch(this._endpoint, {
const headers = new Headers(this._requestInit?.headers);
headers.set("content-type", "application/json");
const init = {
...this._requestInit,
method: "POST",
headers: {
"Content-Type": "application/json",
},
headers,
body: JSON.stringify(message),
signal: this._abortController?.signal,
});
signal: this._abortController?.signal
};
const response = await fetch(this._endpoint, init);
if (!response.ok) {
const text = await response.text().catch(() => null);

View file

@ -0,0 +1,63 @@
import { Protocol } from "./protocol.js";
import { Transport } from "./transport.js";
import {
McpError,
ErrorCode,
Request,
Result,
Notification,
} from "../types.js";
import { ZodType, z } from "zod";
// Mock Transport class
class MockTransport implements Transport {
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: unknown) => void;
async start(): Promise<void> {}
async close(): Promise<void> {
this.onclose?.();
}
async send(_message: unknown): Promise<void> {}
}
describe("protocol tests", () => {
let protocol: Protocol<Request, Notification, Result>;
let transport: MockTransport;
beforeEach(() => {
transport = new MockTransport();
protocol = new (class extends Protocol<Request, Notification, Result> {
protected assertCapabilityForMethod(): void {}
protected assertNotificationCapability(): void {}
protected assertRequestHandlerCapability(): void {}
})();
});
test("should throw a timeout error if the request exceeds the timeout", async () => {
await protocol.connect(transport);
const request = { method: "example", params: {} };
try {
const mockSchema: ZodType<{ result: string }> = z.object({
result: z.string(),
});
await protocol.request(request, mockSchema, {
timeout: 0,
});
} catch (error) {
expect(error).toBeInstanceOf(McpError);
if (error instanceof McpError) {
expect(error.code).toBe(ErrorCode.RequestTimeout);
}
}
});
test("should invoke onclose when the connection is closed", async () => {
const oncloseMock = jest.fn();
protocol.onclose = oncloseMock;
await protocol.connect(transport);
await transport.close();
expect(oncloseMock).toHaveBeenCalled();
});
});

View file

@ -100,13 +100,13 @@ export const JSONRPCResponseSchema = z
.strict();
/**
* An incomplete set of error codes that may appear in JSON-RPC responses.
* Error codes defined by the JSON-RPC specification.
*/
export enum ErrorCode {
// SDK error codes
ConnectionClosed = -1,
RequestTimeout = -2,
ConnectionClosed = -32000,
RequestTimeout = -32001,
// Standard JSON-RPC error codes
ParseError = -32700,
InvalidRequest = -32600,
@ -1237,4 +1237,4 @@ export type ClientResult = z.infer<typeof ClientResultSchema>;
/* Server messages */
export type ServerRequest = z.infer<typeof ServerRequestSchema>;
export type ServerNotification = z.infer<typeof ServerNotificationSchema>;
export type ServerResult = z.infer<typeof ServerResultSchema>;
export type ServerResult = z.infer<typeof ServerResultSchema>;