Merge pull request #410 from cliffhall/update-protocol-version

Update protocol version
This commit is contained in:
ihrpr 2025-04-29 17:54:30 +01:00 • committed by GitHub
commit b0255e51ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 220 additions and 14 deletions

View file

@ -39,7 +39,7 @@ describe("OAuth Authorization", () => {
const [url, options] = calls[0];
expect(url.toString()).toBe("https://auth.example.com/.well-known/oauth-authorization-server");
expect(options.headers).toEqual({
"MCP-Protocol-Version": "2024-11-05"
"MCP-Protocol-Version": "2025-03-26"
});
});
@ -478,4 +478,4 @@ describe("OAuth Authorization", () => {
).rejects.toThrow("Dynamic client registration failed");
});
});
});
});

View file

@ -165,6 +165,194 @@ test("should reject unsupported protocol version", async () => {
expect(clientTransport.close).toHaveBeenCalled();
});
test("should connect new client to old, supported server version", async () => {
const OLD_VERSION = SUPPORTED_PROTOCOL_VERSIONS[1];
const server = new Server(
{
name: "test server",
version: "1.0",
},
{
capabilities: {
resources: {},
tools: {},
},
},
);
server.setRequestHandler(InitializeRequestSchema, (_request) => ({
protocolVersion: OLD_VERSION,
capabilities: {
resources: {},
tools: {},
},
serverInfo: {
name: "old server",
version: "1.0",
},
}));
server.setRequestHandler(ListResourcesRequestSchema, () => ({
resources: [],
}));
server.setRequestHandler(ListToolsRequestSchema, () => ({
tools: [],
}));
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
const client = new Client(
{
name: "new client",
version: "1.0",
protocolVersion: LATEST_PROTOCOL_VERSION,
},
{
capabilities: {
sampling: {},
},
enforceStrictCapabilities: true,
},
);
await Promise.all([
client.connect(clientTransport),
server.connect(serverTransport),
]);
expect(client.getServerVersion()).toEqual({
name: "old server",
version: "1.0",
});
});
test("should negotiate version when client is old, and newer server supports its version", async () => {
const OLD_VERSION = SUPPORTED_PROTOCOL_VERSIONS[1];
const server = new Server(
{
name: "new server",
version: "1.0",
},
{
capabilities: {
resources: {},
tools: {},
},
},
);
server.setRequestHandler(InitializeRequestSchema, (_request) => ({
protocolVersion: LATEST_PROTOCOL_VERSION,
capabilities: {
resources: {},
tools: {},
},
serverInfo: {
name: "new server",
version: "1.0",
},
}));
server.setRequestHandler(ListResourcesRequestSchema, () => ({
resources: [],
}));
server.setRequestHandler(ListToolsRequestSchema, () => ({
tools: [],
}));
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
const client = new Client(
{
name: "old client",
version: "1.0",
protocolVersion: OLD_VERSION,
},
{
capabilities: {
sampling: {},
},
enforceStrictCapabilities: true,
},
);
await Promise.all([
client.connect(clientTransport),
server.connect(serverTransport),
]);
expect(client.getServerVersion()).toEqual({
name: "new server",
version: "1.0",
});
});
test("should throw when client is old, and server doesn't support its version", async () => {
const OLD_VERSION = SUPPORTED_PROTOCOL_VERSIONS[1];
const FUTURE_VERSION = "FUTURE_VERSION";
const server = new Server(
{
name: "new server",
version: "1.0",
},
{
capabilities: {
resources: {},
tools: {},
},
},
);
server.setRequestHandler(InitializeRequestSchema, (_request) => ({
protocolVersion: FUTURE_VERSION,
capabilities: {
resources: {},
tools: {},
},
serverInfo: {
name: "new server",
version: "1.0",
},
}));
server.setRequestHandler(ListResourcesRequestSchema, () => ({
resources: [],
}));
server.setRequestHandler(ListToolsRequestSchema, () => ({
tools: [],
}));
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
const client = new Client(
{
name: "old client",
version: "1.0",
protocolVersion: OLD_VERSION,
},
{
capabilities: {
sampling: {},
},
enforceStrictCapabilities: true,
},
);
await Promise.all([
expect(client.connect(clientTransport)).rejects.toThrow(
"Server's protocol version is not supported: FUTURE_VERSION"
),
server.connect(serverTransport),
]);
});
test("should respect server capabilities", async () => {
const server = new Server(
{

17
src/types.test.ts Normal file
View file

@ -0,0 +1,17 @@
import { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from "./types.js";
describe("Types", () => {
test("should have correct latest protocol version", () => {
expect(LATEST_PROTOCOL_VERSION).toBeDefined();
expect(LATEST_PROTOCOL_VERSION).toBe("2025-03-26");
});
test("should have correct supported protocol versions", () => {
expect(SUPPORTED_PROTOCOL_VERSIONS).toBeDefined();
expect(SUPPORTED_PROTOCOL_VERSIONS).toBeInstanceOf(Array);
expect(SUPPORTED_PROTOCOL_VERSIONS).toContain(LATEST_PROTOCOL_VERSION);
expect(SUPPORTED_PROTOCOL_VERSIONS).toContain("2024-11-05");
expect(SUPPORTED_PROTOCOL_VERSIONS).toContain("2024-10-07");
});
});

View file

@ -1,8 +1,9 @@
import { z, ZodTypeAny } from "zod";
export const LATEST_PROTOCOL_VERSION = "2024-11-05";
export const LATEST_PROTOCOL_VERSION = "2025-03-26";
export const SUPPORTED_PROTOCOL_VERSIONS = [
LATEST_PROTOCOL_VERSION,
"2024-11-05",
"2024-10-07",
];
@ -754,11 +755,11 @@ export const PromptListChangedNotificationSchema = NotificationSchema.extend({
/* Tools */
/**
* Additional properties describing a Tool to clients.
*
* NOTE: all properties in ToolAnnotations are **hints**.
* They are not guaranteed to provide a faithful description of
*
* NOTE: all properties in ToolAnnotations are **hints**.
* They are not guaranteed to provide a faithful description of
* tool behavior (including descriptive properties like `title`).
*
*
* Clients should never make tool use decisions based on ToolAnnotations
* received from untrusted servers.
*/
@ -771,7 +772,7 @@ export const ToolAnnotationsSchema = z
/**
* If true, the tool does not modify its environment.
*
*
* Default: false
*/
readOnlyHint: z.optional(z.boolean()),
@ -779,19 +780,19 @@ export const ToolAnnotationsSchema = z
/**
* If true, the tool may perform destructive updates to its environment.
* If false, the tool performs only additive updates.
*
*
* (This property is meaningful only when `readOnlyHint == false`)
*
*
* Default: true
*/
destructiveHint: z.optional(z.boolean()),
/**
* If true, calling the tool repeatedly with the same arguments
* If true, calling the tool repeatedly with the same arguments
* will have no additional effect on the its environment.
*
*
* (This property is meaningful only when `readOnlyHint == false`)
*
*
* Default: false
*/
idempotentHint: z.optional(z.boolean()),
@ -801,7 +802,7 @@ export const ToolAnnotationsSchema = z
* entities. If false, the tool's domain of interaction is closed.
* For example, the world of a web search tool is open, whereas that
* of a memory tool is not.
*
*
* Default: true
*/
openWorldHint: z.optional(z.boolean()),