diff --git a/package-lock.json b/package-lock.json index 26261a7ade..8d89d89794 100644 --- a/package-lock.json +++ b/package-lock.json @@ -169,46 +169,68 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "node_modules/@modelcontextprotocol/client": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0-alpha.3.tgz", + "integrity": "sha512-NNjaRRwHMKDgARgAlPt0Vkj963A+zoBOX2TtHptNjncjYCwadxx+reU5/H+nlimZmibhJEUznNMQr3UktzBVig==", "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" + "zod": "^4.2.0" }, "engines": { - "node": ">=18" + "node": ">=20" + } + }, + "node_modules/@modelcontextprotocol/core": { + "version": "2.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0-alpha.1.tgz", + "integrity": "sha512-AWdY7gcVq3mRdekXOI+Gh1W+B7aeWDaGERmcQ7PfSu9C0S78yu8jR+JseNWO375l6MM8FjIWVLD9U7KX2sbTpg==", + "license": "MIT", + "dependencies": { + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@modelcontextprotocol/node": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/node/-/node-2.0.0-alpha.3.tgz", + "integrity": "sha512-3S/1lsMoN4dLifs9cZXq5eZ0/yygjQY5iyx8dv9NKEM9r3347vSB3S025tIukr+Kc5y4uaq1ZsYg/idEycFe/Q==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9" + }, + "engines": { + "node": ">=20" }, "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" + "@modelcontextprotocol/server": "^2.0.0-alpha.3", + "hono": "^4.11.4" }, "peerDependenciesMeta": { - "@cfworker/json-schema": { + "hono": { "optional": true - }, - "zod": { - "optional": false } } }, + "node_modules/@modelcontextprotocol/server": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0-alpha.3.tgz", + "integrity": "sha512-PYdVDA6x3joCy/rw1mGdMSvqisPKlmt5QN/ILcT8R7efgvmhij14L87lJrWAm4pszaThzwpV49BmBBTZWtlY3A==", + "license": "MIT", + "dependencies": { + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@modelcontextprotocol/server-everything": { "resolved": "src/everything", "link": true @@ -217,6 +239,32 @@ "resolved": "src/filesystem", "link": true }, + "node_modules/@modelcontextprotocol/server-legacy": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server-legacy/-/server-legacy-2.0.0-alpha.3.tgz", + "integrity": "sha512-ny2TlhsXMlO5LguBB2udADMT1O96nFghKdh8P4BSkgh1AmQSq28PVrJaN3BVJQXlRv5PKRA4u9Ow0CNw3nfXKA==", + "deprecated": "This package is a frozen copy of v1's SSE transport and OAuth Authorization Server helpers for migration purposes only. Use StreamableHTTP from @modelcontextprotocol/server and a dedicated OAuth server in production. Will not receive new features.", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "cors": "^2.8.5", + "express-rate-limit": "^8.2.1", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "express": "^4.18.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + } + } + }, "node_modules/@modelcontextprotocol/server-memory": { "resolved": "src/memory", "link": true @@ -867,39 +915,6 @@ "node": ">= 0.6" } }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -1496,28 +1511,6 @@ "express": ">= 4.11" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -1770,6 +1763,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -1982,18 +1976,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -2747,15 +2729,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.22.12", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", @@ -3794,21 +3767,15 @@ "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - }, "src/everything": { "name": "@modelcontextprotocol/server-everything", "version": "2.0.0", "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/core": "^2.0.0-alpha.1", + "@modelcontextprotocol/node": "^2.0.0-alpha.3", + "@modelcontextprotocol/server": "^2.0.0-alpha.3", + "@modelcontextprotocol/server-legacy": "^2.0.0-alpha.3", "cors": "^2.8.5", "express": "^5.2.1", "jszip": "^3.10.1", @@ -3832,7 +3799,8 @@ "version": "0.6.3", "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/client": "^2.0.0-alpha.3", + "@modelcontextprotocol/server": "^2.0.0-alpha.3", "diff": "^8.0.3", "glob": "^10.5.0", "minimatch": "^10.0.1" @@ -3855,7 +3823,8 @@ "version": "0.6.3", "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0" + "@modelcontextprotocol/core": "^2.0.0-alpha.1", + "@modelcontextprotocol/server": "^2.0.0-alpha.3" }, "bin": { "mcp-server-memory": "dist/index.js" @@ -3873,7 +3842,7 @@ "version": "0.6.2", "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", + "@modelcontextprotocol/server": "^2.0.0-alpha.3", "chalk": "^5.3.0", "yargs": "^17.7.2" }, diff --git a/src/everything/__tests__/prompts.test.ts b/src/everything/__tests__/prompts.test.ts index bff176ac47..2e5fdbb340 100644 --- a/src/everything/__tests__/prompts.test.ts +++ b/src/everything/__tests__/prompts.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { McpServer } from '@modelcontextprotocol/server'; import { registerSimplePrompt } from '../prompts/simple.js'; import { registerArgumentsPrompt } from '../prompts/args.js'; import { registerPromptWithCompletions } from '../prompts/completions.js'; diff --git a/src/everything/__tests__/registrations.test.ts b/src/everything/__tests__/registrations.test.ts index 421d759e07..3293cc4a26 100644 --- a/src/everything/__tests__/registrations.test.ts +++ b/src/everything/__tests__/registrations.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { McpServer } from '@modelcontextprotocol/server'; // Create mock server function createMockServer() { @@ -79,9 +79,6 @@ describe('Registration Index Files', () => { expect(registeredTools).toContain('trigger-elicitation-request'); expect(registeredTools).toContain('trigger-url-elicitation'); expect(registeredTools).toContain('trigger-sampling-request'); - - // Task-based tools are registered via experimental.tasks.registerToolTask - expect(mockServerWithCapabilities.experimental.tasks.registerToolTask).toHaveBeenCalled(); }); it('should not register conditional tools when capabilities missing', async () => { diff --git a/src/everything/__tests__/resources.test.ts b/src/everything/__tests__/resources.test.ts index a22b904175..f7b4037b65 100644 --- a/src/everything/__tests__/resources.test.ts +++ b/src/everything/__tests__/resources.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { McpServer, ResourceTemplate } from '@modelcontextprotocol/server'; import { textResource, blobResource, diff --git a/src/everything/__tests__/tools.test.ts b/src/everything/__tests__/tools.test.ts index a50bbd6592..f20c4d0745 100644 --- a/src/everything/__tests__/tools.test.ts +++ b/src/everything/__tests__/tools.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { McpServer } from '@modelcontextprotocol/server'; import { registerEchoTool, EchoSchema } from '../tools/echo.js'; import { registerGetSumTool } from '../tools/get-sum.js'; import { registerGetEnvTool } from '../tools/get-env.js'; @@ -19,7 +19,6 @@ import { } from '../tools/trigger-url-elicitation.js'; import { registerGetRootsListTool } from '../tools/get-roots-list.js'; import { registerGZipFileAsResourceTool } from '../tools/gzip-file-as-resource.js'; -import { registerSimulateResearchQueryTool } from '../tools/simulate-research-query.js'; // Helper to capture registered tool handlers function createMockServer() { @@ -334,7 +333,7 @@ describe('Tools', () => { // Use very short duration for test const result = await handler( { duration: 0.1, steps: 2 }, - { _meta: {}, requestId: 'test-123' } + { mcpReq: { _meta: {}, id: 'test-123' } } ); expect(result.content[0].text).toContain('Long running operation completed'); @@ -349,7 +348,7 @@ describe('Tools', () => { const handler = handlers.get('trigger-long-running-operation')!; await handler( { duration: 0.1, steps: 2 }, - { _meta: { progressToken: 'token-123' }, requestId: 'test-456', sessionId: 'session-1' } + { mcpReq: { _meta: { progressToken: 'token-123' }, id: 'test-456' }, sessionId: 'session-1' } ); expect(mockServer.server.notification).toHaveBeenCalledTimes(2); @@ -585,7 +584,7 @@ describe('Tools', () => { const handler = handlers.get('trigger-sampling-request')!; const result = await handler( { prompt: 'Test prompt', maxTokens: 50 }, - { sendRequest: mockSendRequest } + { mcpReq: { send: mockSendRequest } } ); expect(mockSendRequest).toHaveBeenCalledWith( @@ -655,7 +654,7 @@ describe('Tools', () => { registerTriggerElicitationRequestTool(mockServer); const handler = handlers.get('trigger-elicitation-request')!; - const result = await handler({}, { sendRequest: mockSendRequest }); + const result = await handler({}, { mcpReq: { send: mockSendRequest } }); expect(result.content[0].text).toContain('✅'); expect(result.content[0].text).toContain('provided'); @@ -680,7 +679,7 @@ describe('Tools', () => { registerTriggerElicitationRequestTool(mockServer); const handler = handlers.get('trigger-elicitation-request')!; - const result = await handler({}, { sendRequest: mockSendRequest }); + const result = await handler({}, { mcpReq: { send: mockSendRequest } }); expect(result.content[0].text).toContain('❌'); expect(result.content[0].text).toContain('declined'); @@ -704,7 +703,7 @@ describe('Tools', () => { registerTriggerElicitationRequestTool(mockServer); const handler = handlers.get('trigger-elicitation-request')!; - const result = await handler({}, { sendRequest: mockSendRequest }); + const result = await handler({}, { mcpReq: { send: mockSendRequest } }); expect(result.content[0].text).toContain('⚠️'); expect(result.content[0].text).toContain('cancelled'); @@ -782,7 +781,7 @@ describe('Tools', () => { elicitationId: 'elicitation-123', errorPath: false, }, - { sendRequest: mockSendRequest } + { mcpReq: { send: mockSendRequest } } ); expect(mockSendRequest).toHaveBeenCalledWith( @@ -854,7 +853,7 @@ describe('Tools', () => { message: 'Open this page to verify your identity', errorPath: false, }, - { sendRequest: mockSendRequest } + { mcpReq: { send: mockSendRequest } } ); const sentParams = mockSendRequest.mock.calls[0][0].params; @@ -886,7 +885,7 @@ describe('Tools', () => { elicitationId: 'elicitation-123', errorPath: false, }, - { sendRequest: mockSendRequest } + { mcpReq: { send: mockSendRequest } } ); expect(result.content[0].text).toContain('❌ User declined to open the URL'); @@ -915,7 +914,7 @@ describe('Tools', () => { elicitationId: 'elicitation-123', errorPath: false, }, - { sendRequest: mockSendRequest } + { mcpReq: { send: mockSendRequest } } ); expect(result.content[0].text).toContain( @@ -988,7 +987,7 @@ describe('Tools', () => { message: 'Authorization is required to continue.', errorPath: true, }; - const extra = { sessionId: 'session-1', sendRequest: mockSendRequest }; + const extra = { sessionId: 'session-1', mcpReq: { send: mockSendRequest } }; // First call: error path issues the prerequisite and throws -32042. let prerequisiteUrl: string | undefined; @@ -1055,90 +1054,6 @@ describe('Tools', () => { }); }); - describe('simulate-research-query', () => { - function createMockServerWithTasks() { - const taskHandlers: Record = {}; - const mockServer = { - experimental: { - tasks: { - registerToolTask: vi.fn((_name: string, _config: any, handler: any) => { - Object.assign(taskHandlers, handler); - }), - }, - }, - server: { getClientCapabilities: vi.fn(() => ({ elicitation: {} })) }, - } as unknown as McpServer; - return { mockServer, taskHandlers }; - } - - function createMockTaskStore(taskId: string) { - return { - createTask: vi.fn().mockResolvedValue({ - taskId, - status: 'working', - createdAt: new Date().toISOString(), - lastUpdatedAt: new Date().toISOString(), - ttl: 300000, - pollInterval: 1000, - }), - updateTaskStatus: vi.fn().mockResolvedValue(undefined), - storeTaskResult: vi.fn().mockResolvedValue(undefined), - getTask: vi.fn(), - getTaskResult: vi.fn(), - }; - } - - it('should pass relatedTask to sendRequest when elicitation is triggered', async () => { - vi.useFakeTimers(); - - const { mockServer, taskHandlers } = createMockServerWithTasks(); - registerSimulateResearchQueryTool(mockServer); - - const mockTaskStore = createMockTaskStore('task-abc'); - const mockSendRequest = vi.fn().mockResolvedValue({ - action: 'accept', - content: { interpretation: 'technical' }, - }); - - await taskHandlers.createTask( - { topic: 'python', ambiguous: true }, - { taskStore: mockTaskStore, sendRequest: mockSendRequest } - ); - - await vi.runAllTimersAsync(); - vi.useRealTimers(); - - expect(mockSendRequest).toHaveBeenCalledWith( - expect.objectContaining({ method: 'elicitation/create' }), - expect.anything(), - expect.objectContaining({ relatedTask: { taskId: 'task-abc' } }) - ); - }); - - it('should complete without elicitation for non-ambiguous query', async () => { - vi.useFakeTimers(); - - const { mockServer, taskHandlers } = createMockServerWithTasks(); - registerSimulateResearchQueryTool(mockServer); - - const mockTaskStore = createMockTaskStore('task-def'); - const mockSendRequest = vi.fn(); - - await taskHandlers.createTask( - { topic: 'python', ambiguous: false }, - { taskStore: mockTaskStore, sendRequest: mockSendRequest } - ); - - await vi.runAllTimersAsync(); - vi.useRealTimers(); - - expect(mockSendRequest).not.toHaveBeenCalled(); - expect(mockTaskStore.storeTaskResult).toHaveBeenCalledWith( - 'task-def', 'completed', expect.anything() - ); - }); - }); - describe('gzip-file-as-resource', () => { it('should compress data URI and return resource link', async () => { const registeredResources: any[] = []; diff --git a/src/everything/package.json b/src/everything/package.json index 4f8b836407..acbc498a21 100644 --- a/src/everything/package.json +++ b/src/everything/package.json @@ -30,11 +30,14 @@ "test": "vitest run --coverage" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", "cors": "^2.8.5", "express": "^5.2.1", "jszip": "^3.10.1", - "zod": "^4.0.0" + "zod": "^4.0.0", + "@modelcontextprotocol/server": "^2.0.0-alpha.3", + "@modelcontextprotocol/core": "^2.0.0-alpha.1", + "@modelcontextprotocol/server-legacy": "^2.0.0-alpha.3", + "@modelcontextprotocol/node": "^2.0.0-alpha.3" }, "devDependencies": { "@types/cors": "^2.8.19", diff --git a/src/everything/prompts/args.ts b/src/everything/prompts/args.ts index 7e445a4ce4..b67b72790c 100644 --- a/src/everything/prompts/args.ts +++ b/src/everything/prompts/args.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; /** * Register a prompt with arguments @@ -16,6 +16,7 @@ export const registerArgumentsPrompt = (server: McpServer) => { }; // Register the prompt + /* @mcp-codemod-error Could not verify `argsSchema` is a schema object. Raw shapes are deprecated in v2 — pass a Standard Schema object (e.g. z.object({ … })); no change is needed if it already is one. */ server.registerPrompt( "args-prompt", { diff --git a/src/everything/prompts/completions.ts b/src/everything/prompts/completions.ts index e47c36e57b..d70c492ac3 100644 --- a/src/everything/prompts/completions.ts +++ b/src/everything/prompts/completions.ts @@ -1,6 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { completable } from "@modelcontextprotocol/sdk/server/completable.js"; +import { McpServer, completable } from "@modelcontextprotocol/server"; /** * Register a prompt with completable arguments @@ -42,6 +41,7 @@ export const registerPromptWithCompletions = (server: McpServer) => { }; // Register the prompt + /* @mcp-codemod-error Could not verify `argsSchema` is a schema object. Raw shapes are deprecated in v2 — pass a Standard Schema object (e.g. z.object({ … })); no change is needed if it already is one. */ server.registerPrompt( "completable-prompt", { diff --git a/src/everything/prompts/index.ts b/src/everything/prompts/index.ts index 6efa7b7297..22d6a22baf 100644 --- a/src/everything/prompts/index.ts +++ b/src/everything/prompts/index.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; import { registerSimplePrompt } from "./simple.js"; import { registerArgumentsPrompt } from "./args.js"; import { registerPromptWithCompletions } from "./completions.js"; diff --git a/src/everything/prompts/resource.ts b/src/everything/prompts/resource.ts index 03989aaa25..5d3c9690c6 100644 --- a/src/everything/prompts/resource.ts +++ b/src/everything/prompts/resource.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; import { resourceTypeCompleter, resourceIdForPromptCompleter, @@ -28,6 +28,7 @@ export const registerEmbeddedResourcePrompt = (server: McpServer) => { }; // Register the prompt + /* @mcp-codemod-error Could not verify `argsSchema` is a schema object. Raw shapes are deprecated in v2 — pass a Standard Schema object (e.g. z.object({ … })); no change is needed if it already is one. */ server.registerPrompt( "resource-prompt", { diff --git a/src/everything/prompts/simple.ts b/src/everything/prompts/simple.ts index a2a0d2eea6..8e2c5c67cd 100644 --- a/src/everything/prompts/simple.ts +++ b/src/everything/prompts/simple.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; /** * Register a simple prompt with no arguments diff --git a/src/everything/resources/files.ts b/src/everything/resources/files.ts index e38cb59633..f4b9b5d7fc 100644 --- a/src/everything/resources/files.ts +++ b/src/everything/resources/files.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { readdirSync, readFileSync, statSync } from "fs"; diff --git a/src/everything/resources/index.ts b/src/everything/resources/index.ts index 30c6f7dcf8..b7ec741376 100644 --- a/src/everything/resources/index.ts +++ b/src/everything/resources/index.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; import { registerResourceTemplates } from "./templates.js"; import { registerFileResources } from "./files.js"; import { fileURLToPath } from "url"; diff --git a/src/everything/resources/session.ts b/src/everything/resources/session.ts index 10e0db33c1..f34ee2f7a4 100644 --- a/src/everything/resources/session.ts +++ b/src/everything/resources/session.ts @@ -1,5 +1,4 @@ -import { McpServer, RegisteredResource } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { Resource, ResourceLink } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, RegisteredResource, Resource, ResourceLink } from "@modelcontextprotocol/server"; /** * Tracks registered session resources by URI to allow updating/removing on re-registration. diff --git a/src/everything/resources/subscriptions.ts b/src/everything/resources/subscriptions.ts index 2a5e57460f..73f027159b 100644 --- a/src/everything/resources/subscriptions.ts +++ b/src/everything/resources/subscriptions.ts @@ -1,8 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - SubscribeRequestSchema, - UnsubscribeRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; +import { McpServer } from "@modelcontextprotocol/server"; // Track subscriber session id lists by URI const subscriptions: Map> = new Map< @@ -36,13 +32,13 @@ const subsUpdateIntervals: Map = export const setSubscriptionHandlers = (server: McpServer) => { // Set the subscription handler server.server.setRequestHandler( - SubscribeRequestSchema, - async (request, extra) => { + "resources/subscribe", + async (request, ctx) => { // Get the URI to subscribe to const { uri } = request.params; // Get the session id (can be undefined for stdio) - const sessionId = extra.sessionId as string; + const sessionId = ctx.sessionId as string; // Acknowledge the subscribe request await server.sendLoggingMessage( @@ -67,13 +63,13 @@ export const setSubscriptionHandlers = (server: McpServer) => { // Set the unsubscription handler server.server.setRequestHandler( - UnsubscribeRequestSchema, - async (request, extra) => { + "resources/unsubscribe", + async (request, ctx) => { // Get the URI to subscribe to const { uri } = request.params; // Get the session id (can be undefined for stdio) - const sessionId = extra.sessionId as string; + const sessionId = ctx.sessionId as string; // Acknowledge the subscribe request await server.sendLoggingMessage( diff --git a/src/everything/resources/templates.ts b/src/everything/resources/templates.ts index 6d4903f74c..434a9a3292 100644 --- a/src/everything/resources/templates.ts +++ b/src/everything/resources/templates.ts @@ -3,8 +3,8 @@ import { CompleteResourceTemplateCallback, McpServer, ResourceTemplate, -} from "@modelcontextprotocol/sdk/server/mcp.js"; -import { completable } from "@modelcontextprotocol/sdk/server/completable.js"; + completable, +} from "@modelcontextprotocol/server"; // Resource types export const RESOURCE_TYPE_TEXT = "Text" as const; diff --git a/src/everything/server/index.ts b/src/everything/server/index.ts index f1459cc812..dc28137551 100644 --- a/src/everything/server/index.ts +++ b/src/everything/server/index.ts @@ -1,8 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - InMemoryTaskStore, - InMemoryTaskMessageQueue, -} from "@modelcontextprotocol/sdk/experimental/tasks"; +import { McpServer } from "@modelcontextprotocol/server"; import { setSubscriptionHandlers, stopSimulatedResourceUpdates, @@ -36,10 +32,6 @@ export const createServer: () => ServerFactoryResponse = () => { // Read the server instructions const instructions = readInstructions(); - // Create task store and message queue for task support - const taskStore = new InMemoryTaskStore(); - const taskMessageQueue = new InMemoryTaskMessageQueue(); - let initializeTimeout: NodeJS.Timeout | null = null; // Create the server @@ -73,8 +65,6 @@ export const createServer: () => ServerFactoryResponse = () => { }, }, instructions, - taskStore, - taskMessageQueue, } ); @@ -110,8 +100,6 @@ export const createServer: () => ServerFactoryResponse = () => { // Stop any simulated logging or resource updates that may have been initiated. stopSimulatedLogging(sessionId); stopSimulatedResourceUpdates(sessionId); - // Clean up task store timers - taskStore.cleanup(); if (initializeTimeout) clearTimeout(initializeTimeout); }, } satisfies ServerFactoryResponse; diff --git a/src/everything/server/logging.ts b/src/everything/server/logging.ts index 82edea162c..0cce55e98f 100644 --- a/src/everything/server/logging.ts +++ b/src/everything/server/logging.ts @@ -1,5 +1,4 @@ -import { LoggingLevel } from "@modelcontextprotocol/sdk/types.js"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { LoggingLevel, McpServer } from "@modelcontextprotocol/server"; // Map session ID to the interval for sending logging messages to the client const logsUpdateIntervals: Map = diff --git a/src/everything/server/roots.ts b/src/everything/server/roots.ts index 34b12b21ce..d0a4146ebb 100644 --- a/src/everything/server/roots.ts +++ b/src/everything/server/roots.ts @@ -1,8 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - Root, - RootsListChangedNotificationSchema, -} from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, Root } from "@modelcontextprotocol/server"; // Track roots by session id export const roots: Map = new Map< @@ -76,7 +72,7 @@ export const syncRoots = async (server: McpServer, sessionId?: string) => { if (!roots.has(sessionId)) { // Set the list changed notification handler server.server.setNotificationHandler( - RootsListChangedNotificationSchema, + "notifications/roots/list_changed", requestRoots ); diff --git a/src/everything/tools/echo.ts b/src/everything/tools/echo.ts index 0658e83195..8ae7943ad5 100644 --- a/src/everything/tools/echo.ts +++ b/src/everything/tools/echo.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { z } from "zod"; // Tool input schema diff --git a/src/everything/tools/get-annotated-message.ts b/src/everything/tools/get-annotated-message.ts index 5de72b029a..ba47d4e8a1 100644 --- a/src/everything/tools/get-annotated-message.ts +++ b/src/everything/tools/get-annotated-message.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { z } from "zod"; import { MCP_TINY_IMAGE } from "./get-tiny-image.js"; diff --git a/src/everything/tools/get-env.ts b/src/everything/tools/get-env.ts index 55eabfaa97..bbe447798b 100644 --- a/src/everything/tools/get-env.ts +++ b/src/everything/tools/get-env.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; // Tool configuration const name = "get-env"; diff --git a/src/everything/tools/get-resource-links.ts b/src/everything/tools/get-resource-links.ts index 7684cb64a5..e35bf83631 100644 --- a/src/everything/tools/get-resource-links.ts +++ b/src/everything/tools/get-resource-links.ts @@ -1,6 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { textResource, textResourceUri, diff --git a/src/everything/tools/get-resource-reference.ts b/src/everything/tools/get-resource-reference.ts index 5806365868..b11020b943 100644 --- a/src/everything/tools/get-resource-reference.ts +++ b/src/everything/tools/get-resource-reference.ts @@ -1,6 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { textResource, textResourceUri, diff --git a/src/everything/tools/get-roots-list.ts b/src/everything/tools/get-roots-list.ts index a8778e4c01..bc309e33c4 100644 --- a/src/everything/tools/get-roots-list.ts +++ b/src/everything/tools/get-roots-list.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { syncRoots } from "../server/roots.js"; // Tool configuration @@ -44,9 +43,9 @@ export const registerGetRootsListTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { // Get the current rootsFetch the current roots list from the client if need be - const currentRoots = await syncRoots(server, extra.sessionId); + const currentRoots = await syncRoots(server, ctx.sessionId); // Respond if client supports roots but doesn't have any configured if ( diff --git a/src/everything/tools/get-structured-content.ts b/src/everything/tools/get-structured-content.ts index f9bde5c9e4..11f323e14b 100644 --- a/src/everything/tools/get-structured-content.ts +++ b/src/everything/tools/get-structured-content.ts @@ -1,9 +1,9 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { + McpServer, CallToolResult, ContentBlock, -} from "@modelcontextprotocol/sdk/types.js"; +} from "@modelcontextprotocol/server"; // Tool input schema const GetStructuredContentInputSchema = { diff --git a/src/everything/tools/get-sum.ts b/src/everything/tools/get-sum.ts index 470293bf6f..d8bd04234e 100644 --- a/src/everything/tools/get-sum.ts +++ b/src/everything/tools/get-sum.ts @@ -1,6 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; // Tool input schema const GetSumSchema = z.object({ diff --git a/src/everything/tools/get-tiny-image.ts b/src/everything/tools/get-tiny-image.ts index c38c3c698b..e6355ca488 100644 --- a/src/everything/tools/get-tiny-image.ts +++ b/src/everything/tools/get-tiny-image.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; // A tiny encoded MCP logo image export const MCP_TINY_IMAGE = diff --git a/src/everything/tools/gzip-file-as-resource.ts b/src/everything/tools/gzip-file-as-resource.ts index 3dd6fdae4a..148a9afea8 100644 --- a/src/everything/tools/gzip-file-as-resource.ts +++ b/src/everything/tools/gzip-file-as-resource.ts @@ -1,6 +1,9 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult, Resource } from "@modelcontextprotocol/sdk/types.js"; +import { + McpServer, + CallToolResult, + Resource, +} from "@modelcontextprotocol/server"; import { gzipSync } from "node:zlib"; import { getSessionResourceURI, diff --git a/src/everything/tools/index.ts b/src/everything/tools/index.ts index 0272126eea..ded05e027e 100644 --- a/src/everything/tools/index.ts +++ b/src/everything/tools/index.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer } from "@modelcontextprotocol/server"; import { registerGetAnnotatedMessageTool } from "./get-annotated-message.js"; import { registerEchoTool } from "./echo.js"; import { registerGetEnvTool } from "./get-env.js"; @@ -16,7 +16,6 @@ import { registerTriggerLongRunningOperationTool } from "./trigger-long-running- import { registerTriggerSamplingRequestTool } from "./trigger-sampling-request.js"; import { registerTriggerSamplingRequestAsyncTool } from "./trigger-sampling-request-async.js"; import { registerTriggerElicitationRequestAsyncTool } from "./trigger-elicitation-request-async.js"; -import { registerSimulateResearchQueryTool } from "./simulate-research-query.js"; import { registerTriggerUrlElicitationTool } from "./trigger-url-elicitation.js"; /** @@ -47,8 +46,6 @@ export const registerConditionalTools = (server: McpServer) => { registerTriggerElicitationRequestTool(server); registerTriggerUrlElicitationTool(server); registerTriggerSamplingRequestTool(server); - // Task-based research tool (uses experimental tasks API) - registerSimulateResearchQueryTool(server); // Bidirectional task tools - server sends requests that client executes as tasks registerTriggerSamplingRequestAsyncTool(server); registerTriggerElicitationRequestAsyncTool(server); diff --git a/src/everything/tools/simulate-research-query.ts b/src/everything/tools/simulate-research-query.ts deleted file mode 100644 index 098df8a0a0..0000000000 --- a/src/everything/tools/simulate-research-query.ts +++ /dev/null @@ -1,345 +0,0 @@ -import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - CallToolResult, - GetTaskResult, - Task, - ElicitResult, - ElicitResultSchema, -} from "@modelcontextprotocol/sdk/types.js"; -import { CreateTaskResult } from "@modelcontextprotocol/sdk/experimental/tasks"; - -// Tool input schema -const SimulateResearchQuerySchema = z.object({ - topic: z.string().describe("The research topic to investigate"), - ambiguous: z - .boolean() - .default(false) - .describe( - "Simulate an ambiguous query that requires clarification (triggers input_required status)" - ), -}); - -// Research stages -const STAGES = [ - "Gathering sources", - "Analyzing content", - "Synthesizing findings", - "Generating report", -]; - -// Duration per stage in milliseconds -const STAGE_DURATION = 1000; - -// Internal state for tracking research tasks -interface ResearchState { - topic: string; - ambiguous: boolean; - currentStage: number; - clarification?: string; - completed: boolean; - result?: CallToolResult; -} - -// Map to store research state per task -const researchStates = new Map(); - -/** - * Runs the background research process. - * Updates task status as it progresses through stages. - * If clarification is needed, sends elicitation via sendRequest with relatedTask, - * which queues the request in the task message queue. The SDK delivers it through - * the tasks/result stream when the client calls tasks/result (per spec input_required flow). - * This works on all transports (STDIO, SSE, Streamable HTTP). - */ -async function runResearchProcess( - taskId: string, - args: z.infer, - taskStore: { - updateTaskStatus: ( - taskId: string, - status: Task["status"], - message?: string - ) => Promise; - storeTaskResult: ( - taskId: string, - status: "completed" | "failed", - result: CallToolResult - ) => Promise; - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - sendRequest: any -): Promise { - const state = researchStates.get(taskId); - if (!state) return; - - // Process each stage - for (let i = state.currentStage; i < STAGES.length; i++) { - state.currentStage = i; - - // Check if task was cancelled externally - if (state.completed) return; - - // Update status message for current stage - await taskStore.updateTaskStatus(taskId, "working", `${STAGES[i]}...`); - - // At synthesis stage (index 2), check if clarification is needed - if (i === 2 && state.ambiguous && !state.clarification) { - // Update status to show we're requesting input (spec SHOULD) - await taskStore.updateTaskStatus( - taskId, - "input_required", - `Found multiple interpretations for "${state.topic}". Requesting clarification...` - ); - - try { - // relatedTask queues elicitation via task message queue → delivered through tasks/result on all transports - const elicitResult: ElicitResult = await sendRequest( - { - method: "elicitation/create", - params: { - message: `The research query "${state.topic}" could have multiple interpretations. Please clarify what you're looking for:`, - requestedSchema: { - type: "object", - properties: { - interpretation: { - type: "string", - title: "Clarification", - description: - "Which interpretation of the topic do you mean?", - oneOf: getInterpretationsForTopic(state.topic), - }, - }, - required: ["interpretation"], - }, - }, - }, - ElicitResultSchema, - { relatedTask: { taskId } } - ); - - // Process elicitation response - if (elicitResult.action === "accept" && elicitResult.content) { - state.clarification = - (elicitResult.content as { interpretation?: string }) - .interpretation || "User accepted without selection"; - } else if (elicitResult.action === "decline") { - state.clarification = "User declined - using default interpretation"; - } else { - state.clarification = "User cancelled - using default interpretation"; - } - } catch (error) { - // Elicitation failed - use default interpretation and continue - console.warn( - `Elicitation failed for task ${taskId}:`, - error instanceof Error ? error.message : String(error) - ); - state.clarification = "technical (default - elicitation unavailable)"; - } - - // Resume with working status (spec SHOULD) - await taskStore.updateTaskStatus( - taskId, - "working", - `Continuing with interpretation: "${state.clarification}"...` - ); - - // Continue processing (no return - just keep going through the loop) - } - - // Simulate work for this stage - await new Promise((resolve) => setTimeout(resolve, STAGE_DURATION)); - } - - // All stages complete - generate result - state.completed = true; - const result = generateResearchReport(state); - state.result = result; - - await taskStore.storeTaskResult(taskId, "completed", result); -} - -/** - * Generates the final research report with educational content about tasks. - */ -function generateResearchReport(state: ResearchState): CallToolResult { - const topic = state.clarification - ? `${state.topic} (${state.clarification})` - : state.topic; - - const report = `# Research Report: ${topic} - -## Research Parameters -- **Topic**: ${state.topic} -${state.clarification ? `- **Clarification**: ${state.clarification}` : ""} - -## Synthesis -This research query was processed through ${STAGES.length} stages: -${STAGES.map((s, i) => `- Stage ${i + 1}: ${s} ✓`).join("\n")} - ---- - -## About This Demo (SEP-1686: Tasks) - -This tool demonstrates MCP's task-based execution pattern for long-running operations: - -**Task Lifecycle Demonstrated:** -1. \`tools/call\` with \`task\` parameter → Server returns \`CreateTaskResult\` (not the final result) -2. Client polls \`tasks/get\` → Server returns current status and \`statusMessage\` -3. Status progressed: \`working\` → ${ - state.clarification ? `\`input_required\` → \`working\` → ` : "" - }\`completed\` -4. Client calls \`tasks/result\` → Server returns this final result - -${ - state.clarification - ? `**Elicitation Flow:** -When the query was ambiguous, the server sent an \`elicitation/create\` request -to the client. The task status changed to \`input_required\` while awaiting user input. -${ - state.clarification.includes("unavailable") - ? `**Note:** Elicitation failed and a default interpretation was used.` - : `After receiving clarification ("${state.clarification}"), the task resumed processing and completed.` -} -` - : "" -} -**Key Concepts:** -- Tasks enable "call now, fetch later" patterns -- \`statusMessage\` provides human-readable progress updates -- Tasks have TTL (time-to-live) for automatic cleanup -- \`pollInterval\` suggests how often to check status -- Elicitation requests use \`relatedTask\` to queue via tasks/result (works on all transports) - -*This is a simulated research report from the Everything MCP Server.* -`; - - return { - content: [ - { - type: "text", - text: report, - }, - ], - }; -} - -/** - * Registers the 'simulate-research-query' tool as a task-based tool. - * - * This tool demonstrates the MCP Tasks feature (SEP-1686) with a real-world scenario: - * a research tool that gathers and synthesizes information from multiple sources. - * If the query is ambiguous, it pauses to ask for clarification before completing. - * - * @param {McpServer} server - The McpServer instance where the tool will be registered. - */ -export const registerSimulateResearchQueryTool = (server: McpServer) => { - // Check if client supports elicitation (needed for input_required flow) - const clientCapabilities = server.server.getClientCapabilities() || {}; - const clientSupportsElicitation: boolean = - clientCapabilities.elicitation !== undefined; - - server.experimental.tasks.registerToolTask( - "simulate-research-query", - { - title: "Simulate Research Query", - description: - "Simulates a deep research operation that gathers, analyzes, and synthesizes information. " + - "Demonstrates MCP task-based operations with progress through multiple stages. " + - "If 'ambiguous' is true and client supports elicitation, sends an elicitation request for clarification.", - inputSchema: SimulateResearchQuerySchema, - execution: { taskSupport: "required" }, - annotations: { - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - openWorldHint: false, - }, - }, - { - /** - * Creates a new research task and starts background processing. - */ - createTask: async (args, extra): Promise => { - const validatedArgs = SimulateResearchQuerySchema.parse(args); - - // Create the task in the store - const task = await extra.taskStore.createTask({ - ttl: 300000, // 5 minutes - pollInterval: 1000, - }); - - // Initialize research state - const state: ResearchState = { - topic: validatedArgs.topic, - ambiguous: validatedArgs.ambiguous && clientSupportsElicitation, - currentStage: 0, - completed: false, - }; - researchStates.set(task.taskId, state); - - // Start background research (don't await - runs asynchronously) - // Pass sendRequest for elicitation (queued via task message queue, works on all transports) - runResearchProcess( - task.taskId, - validatedArgs, - extra.taskStore, - extra.sendRequest - ).catch((error) => { - console.error(`Research task ${task.taskId} failed:`, error); - extra.taskStore - .updateTaskStatus(task.taskId, "failed", String(error)) - .catch(console.error); - }); - - return { task }; - }, - - /** - * Returns the current status of the research task. - */ - getTask: async (args, extra): Promise => { - return await extra.taskStore.getTask(extra.taskId); - }, - - /** - * Returns the task result. - * Elicitation is now handled directly in the background process. - */ - getTaskResult: async (args, extra): Promise => { - // Return the stored result - const result = await extra.taskStore.getTaskResult(extra.taskId); - - // Clean up state - researchStates.delete(extra.taskId); - - return result as CallToolResult; - }, - } - ); -}; - -/** - * Returns contextual interpretation options based on the topic. - */ -function getInterpretationsForTopic( - topic: string -): Array<{ const: string; title: string }> { - const lowerTopic = topic.toLowerCase(); - - // Example: contextual interpretations for "python" - if (lowerTopic.includes("python")) { - return [ - { const: "programming", title: "Python programming language" }, - { const: "snake", title: "Python snake species" }, - { const: "comedy", title: "Monty Python comedy group" }, - ]; - } - - // Default generic interpretations - return [ - { const: "technical", title: "Technical/scientific perspective" }, - { const: "historical", title: "Historical perspective" }, - { const: "current", title: "Current events/news perspective" }, - ]; -} diff --git a/src/everything/tools/toggle-simulated-logging.ts b/src/everything/tools/toggle-simulated-logging.ts index eb9a4b1e25..6397516217 100644 --- a/src/everything/tools/toggle-simulated-logging.ts +++ b/src/everything/tools/toggle-simulated-logging.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { beginSimulatedLogging, stopSimulatedLogging, @@ -38,8 +37,8 @@ export const registerToggleSimulatedLoggingTool = (server: McpServer) => { server.registerTool( name, config, - async (_args, extra): Promise => { - const sessionId = extra?.sessionId; + async (_args, ctx): Promise => { + const sessionId = ctx?.sessionId; let response: string; if (clients.has(sessionId)) { diff --git a/src/everything/tools/toggle-subscriber-updates.ts b/src/everything/tools/toggle-subscriber-updates.ts index 759ec20e51..bc2f5dea7a 100644 --- a/src/everything/tools/toggle-subscriber-updates.ts +++ b/src/everything/tools/toggle-subscriber-updates.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { beginSimulatedResourceUpdates, stopSimulatedResourceUpdates, @@ -41,8 +40,8 @@ export const registerToggleSubscriberUpdatesTool = (server: McpServer) => { server.registerTool( name, config, - async (_args, extra): Promise => { - const sessionId = extra?.sessionId; + async (_args, ctx): Promise => { + const sessionId = ctx?.sessionId; let response: string; if (clients.has(sessionId)) { diff --git a/src/everything/tools/trigger-elicitation-request-async.ts b/src/everything/tools/trigger-elicitation-request-async.ts index d6e61b7bf7..1e208c0f47 100644 --- a/src/everything/tools/trigger-elicitation-request-async.ts +++ b/src/everything/tools/trigger-elicitation-request-async.ts @@ -1,5 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; import { z } from "zod"; // Tool configuration @@ -58,7 +57,7 @@ export const registerTriggerElicitationRequestAsyncTool = ( server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { // Create the elicitation request WITH task metadata // Using z.any() schema to avoid complex type matching with _meta const request = { @@ -98,8 +97,8 @@ export const registerTriggerElicitationRequestAsyncTool = ( // Client may return either: // - ElicitResult (synchronous execution) // - CreateTaskResult (task-based execution with { task } object) - const elicitResponse = await extra.sendRequest( - request as Parameters[0], + const elicitResponse = await ctx.mcpReq.send( + request as Parameters[0], z.union([ // CreateTaskResult - client created a task z.object({ @@ -156,7 +155,7 @@ export const registerTriggerElicitationRequestAsyncTool = ( attempts++; // Get task status from client - const pollResult = await extra.sendRequest( + const pollResult = await ctx.mcpReq.send( { method: "tasks/get", params: { taskId }, @@ -213,7 +212,7 @@ export const registerTriggerElicitationRequestAsyncTool = ( } // Fetch the final result - const result = await extra.sendRequest( + const result = await ctx.mcpReq.send( { method: "tasks/result", params: { taskId }, diff --git a/src/everything/tools/trigger-elicitation-request.ts b/src/everything/tools/trigger-elicitation-request.ts index ca4742141e..42a4bae2fe 100644 --- a/src/everything/tools/trigger-elicitation-request.ts +++ b/src/everything/tools/trigger-elicitation-request.ts @@ -1,8 +1,5 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - ElicitResultSchema, - CallToolResult, -} from "@modelcontextprotocol/sdk/types.js"; +import { ElicitResultSchema } from "@modelcontextprotocol/core"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; // Tool configuration const name = "trigger-elicitation-request"; @@ -47,8 +44,8 @@ export const registerTriggerElicitationRequestTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { - const elicitationResult = await extra.sendRequest( + async (args, ctx): Promise => { + const elicitationResult = await ctx.mcpReq.send( { method: "elicitation/create", params: { diff --git a/src/everything/tools/trigger-long-running-operation.ts b/src/everything/tools/trigger-long-running-operation.ts index 95415e88e2..065f3699ea 100644 --- a/src/everything/tools/trigger-long-running-operation.ts +++ b/src/everything/tools/trigger-long-running-operation.ts @@ -1,6 +1,5 @@ import { z } from "zod"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { McpServer, CallToolResult } from "@modelcontextprotocol/server"; // Tool input schema const TriggerLongRunningOperationSchema = z.object({ @@ -43,11 +42,11 @@ export const registerTriggerLongRunningOperationTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { const validatedArgs = TriggerLongRunningOperationSchema.parse(args); const { duration, steps } = validatedArgs; const stepDuration = duration / steps; - const progressToken = extra._meta?.progressToken; + const progressToken = ctx.mcpReq._meta?.progressToken; for (let i = 1; i < steps + 1; i++) { await new Promise((resolve) => @@ -64,7 +63,7 @@ export const registerTriggerLongRunningOperationTool = (server: McpServer) => { progressToken, }, }, - { relatedRequestId: extra.requestId } + { relatedRequestId: ctx.mcpReq.id } ); } } diff --git a/src/everything/tools/trigger-sampling-request-async.ts b/src/everything/tools/trigger-sampling-request-async.ts index d61daddbd2..3a9fa6c2c4 100644 --- a/src/everything/tools/trigger-sampling-request-async.ts +++ b/src/everything/tools/trigger-sampling-request-async.ts @@ -1,8 +1,8 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { + McpServer, CallToolResult, CreateMessageRequest, -} from "@modelcontextprotocol/sdk/types.js"; +} from "@modelcontextprotocol/server"; import { z } from "zod"; // Tool input schema @@ -66,7 +66,7 @@ export const registerTriggerSamplingRequestAsyncTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { const validatedArgs = TriggerSamplingRequestAsyncSchema.parse(args); const { prompt, maxTokens } = validatedArgs; @@ -99,7 +99,7 @@ export const registerTriggerSamplingRequestAsyncTool = (server: McpServer) => { // Client may return either: // - CreateMessageResult (synchronous execution) // - CreateTaskResult (task-based execution with { task } object) - const samplingResponse = await extra.sendRequest( + const samplingResponse = await ctx.mcpReq.send( request, z.union([ // CreateTaskResult - client created a task @@ -160,7 +160,7 @@ export const registerTriggerSamplingRequestAsyncTool = (server: McpServer) => { attempts++; // Get task status from client - const pollResult = await extra.sendRequest( + const pollResult = await ctx.mcpReq.send( { method: "tasks/get", params: { taskId }, @@ -209,7 +209,7 @@ export const registerTriggerSamplingRequestAsyncTool = (server: McpServer) => { } // Fetch the final result - const result = await extra.sendRequest( + const result = await ctx.mcpReq.send( { method: "tasks/result", params: { taskId }, diff --git a/src/everything/tools/trigger-sampling-request.ts b/src/everything/tools/trigger-sampling-request.ts index fd9b5375c4..ede09182ed 100644 --- a/src/everything/tools/trigger-sampling-request.ts +++ b/src/everything/tools/trigger-sampling-request.ts @@ -1,9 +1,9 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { CreateMessageResultSchema } from "@modelcontextprotocol/core"; import { + McpServer, CallToolResult, CreateMessageRequest, - CreateMessageResultSchema, -} from "@modelcontextprotocol/sdk/types.js"; +} from "@modelcontextprotocol/server"; import { z } from "zod"; // Tool input schema @@ -53,7 +53,7 @@ export const registerTriggerSamplingRequestTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { const validatedArgs = TriggerSamplingRequestSchema.parse(args); const { prompt, maxTokens } = validatedArgs; @@ -77,7 +77,7 @@ export const registerTriggerSamplingRequestTool = (server: McpServer) => { }; // Send the sampling request to the client - const result = await extra.sendRequest( + const result = await ctx.mcpReq.send( request, CreateMessageResultSchema ); diff --git a/src/everything/tools/trigger-url-elicitation.ts b/src/everything/tools/trigger-url-elicitation.ts index a7de878de7..e685afeda9 100644 --- a/src/everything/tools/trigger-url-elicitation.ts +++ b/src/everything/tools/trigger-url-elicitation.ts @@ -1,11 +1,6 @@ import { randomUUID } from "node:crypto"; -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { - CallToolResult, - ElicitRequestURLParams, - ElicitResultSchema, - UrlElicitationRequiredError, -} from "@modelcontextprotocol/sdk/types.js"; +import { ElicitResultSchema } from "@modelcontextprotocol/core"; +import { McpServer, CallToolResult, ElicitRequestURLParams, UrlElicitationRequiredError } from "@modelcontextprotocol/server"; import { z } from "zod"; // Tool input schema @@ -107,7 +102,7 @@ export const registerTriggerUrlElicitationTool = (server: McpServer) => { server.registerTool( name, config, - async (args, extra): Promise => { + async (args, ctx): Promise => { const { url, message, @@ -116,7 +111,7 @@ export const registerTriggerUrlElicitationTool = (server: McpServer) => { } = args; const elicitationId = requestedElicitationId ?? randomUUID(); - const sessionId = extra.sessionId ?? "default"; + const sessionId = ctx.sessionId ?? "default"; // Key the one-shot error-path marker on inputs the client resends // verbatim when it retries the original tool call. A real client retries @@ -170,7 +165,7 @@ export const registerTriggerUrlElicitationTool = (server: McpServer) => { } // Request path: send elicitation/create and await the user's response - const elicitationResult = await extra.sendRequest( + const elicitationResult = await ctx.mcpReq.send( { method: "elicitation/create", params: elicitationParams, diff --git a/src/everything/transports/sse.ts b/src/everything/transports/sse.ts index 2406db7cfa..3283325fcb 100644 --- a/src/everything/transports/sse.ts +++ b/src/everything/transports/sse.ts @@ -1,4 +1,4 @@ -import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; +import { SSEServerTransport } from "@modelcontextprotocol/server-legacy/sse"; import express from "express"; import { createServer } from "../server/index.js"; import cors from "cors"; diff --git a/src/everything/transports/stdio.ts b/src/everything/transports/stdio.ts index 3e653bcf4d..111d79d8a4 100644 --- a/src/everything/transports/stdio.ts +++ b/src/everything/transports/stdio.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { StdioServerTransport } from "@modelcontextprotocol/server/stdio"; import { createServer } from "../server/index.js"; console.error("Starting default (STDIO) server..."); diff --git a/src/everything/transports/streamableHttp.ts b/src/everything/transports/streamableHttp.ts index 2e79abc554..70d4ee8b06 100644 --- a/src/everything/transports/streamableHttp.ts +++ b/src/everything/transports/streamableHttp.ts @@ -1,7 +1,5 @@ -import { - StreamableHTTPServerTransport, - EventStore, -} from "@modelcontextprotocol/sdk/server/streamableHttp.js"; +import { EventStore } from "@modelcontextprotocol/server"; +import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node"; import express, { Request, Response } from "express"; import { createServer } from "../server/index.js"; import { randomUUID } from "node:crypto"; @@ -51,9 +49,9 @@ app.use( ); // Map sessionId to server transport for each client -const transports: Map = new Map< +const transports: Map = new Map< string, - StreamableHTTPServerTransport + NodeStreamableHTTPServerTransport >(); // Handle POST requests for client messages @@ -63,7 +61,7 @@ app.post("/mcp", async (req: Request, res: Response) => { // Check for existing session ID const sessionId = req.headers["mcp-session-id"] as string | undefined; - let transport: StreamableHTTPServerTransport; + let transport: NodeStreamableHTTPServerTransport; if (sessionId && transports.has(sessionId)) { // Reuse existing transport @@ -73,7 +71,7 @@ app.post("/mcp", async (req: Request, res: Response) => { // New initialization request const eventStore = new InMemoryEventStore(); - transport = new StreamableHTTPServerTransport({ + transport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), eventStore, // Enable resumability onsessioninitialized: (sessionId: string) => { diff --git a/src/filesystem/__tests__/roots-utils.test.ts b/src/filesystem/__tests__/roots-utils.test.ts index 1a39483953..39ef1b3089 100644 --- a/src/filesystem/__tests__/roots-utils.test.ts +++ b/src/filesystem/__tests__/roots-utils.test.ts @@ -3,7 +3,7 @@ import { getValidRootDirectories } from '../roots-utils.js'; import { mkdtempSync, rmSync, mkdirSync, writeFileSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; -import type { Root } from '@modelcontextprotocol/sdk/types.js'; +import type { Root } from '@modelcontextprotocol/server'; describe('getValidRootDirectories', () => { let testDir1: string; diff --git a/src/filesystem/__tests__/structured-content.test.ts b/src/filesystem/__tests__/structured-content.test.ts index 4b8f92b0a3..362e619100 100644 --- a/src/filesystem/__tests__/structured-content.test.ts +++ b/src/filesystem/__tests__/structured-content.test.ts @@ -2,8 +2,8 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; -import { Client } from '@modelcontextprotocol/sdk/client/index.js'; -import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; +import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'; +import { Client } from '@modelcontextprotocol/client'; import { spawn } from 'child_process'; /** diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index 7b67e63e58..ae9bb1e994 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -1,12 +1,8 @@ #!/usr/bin/env node -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolResult, - RootsListChangedNotificationSchema, - type Root, -} from "@modelcontextprotocol/sdk/types.js"; +import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'; +import { McpServer, CallToolResult } from '@modelcontextprotocol/server'; +import type { Root } from '@modelcontextprotocol/server'; import fs from "fs/promises"; import { createReadStream } from "fs"; import path from "path"; @@ -216,7 +212,7 @@ server.registerTool( title: "Read File (Deprecated)", description: "Read the complete contents of a file as text. DEPRECATED: Use read_text_file instead.", inputSchema: ReadTextFileArgsSchema.shape, - outputSchema: { content: z.string() }, + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, readTextFileHandler @@ -234,12 +230,12 @@ server.registerTool( "the first N lines of a file, or the 'tail' parameter to read only " + "the last N lines of a file. Operates on the file as text regardless of extension. " + "Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), tail: z.number().optional().describe("If provided, returns only the last N lines of the file"), head: z.number().optional().describe("If provided, returns only the first N lines of the file") - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, readTextFileHandler @@ -252,16 +248,16 @@ server.registerTool( description: "Read an image or audio file. Returns the base64 encoded data and MIME type. " + "Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string() - }, - outputSchema: { + }), + outputSchema: z.object({ content: z.array(z.object({ type: z.enum(["image", "audio", "blob"]), data: z.string(), mimeType: z.string() })) - }, + }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -307,12 +303,12 @@ server.registerTool( "or compare multiple files. Each file's content is returned with its " + "path as a reference. Failed reads for individual files won't stop " + "the entire operation. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ paths: z.array(z.string()) .min(1) .describe("Array of file paths to read. Each path must be a string pointing to a valid file within allowed directories.") - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -344,11 +340,11 @@ server.registerTool( "Create a new file or completely overwrite an existing file with new content. " + "Use with caution as it will overwrite existing files without warning. " + "Handles text content with proper encoding. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), content: z.string() - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: false, idempotentHint: true, destructiveHint: true } }, async (args: z.infer) => { @@ -370,15 +366,15 @@ server.registerTool( "Make line-based edits to a text file. Each edit replaces exact line sequences " + "with new content. Returns a git-style diff showing the changes made. " + "Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), edits: z.array(z.object({ oldText: z.string().describe("Text to search for - must match exactly"), newText: z.string().describe("Text to replace with") })), dryRun: z.boolean().default(false).describe("Preview changes using git-style diff format") - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true } }, async (args: z.infer) => { @@ -400,10 +396,10 @@ server.registerTool( "nested directories in one operation. If the directory already exists, " + "this operation will succeed silently. Perfect for setting up directory " + "structures for projects or ensuring required paths exist. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string() - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: false, idempotentHint: true, destructiveHint: false } }, async (args: z.infer) => { @@ -426,10 +422,10 @@ server.registerTool( "Results clearly distinguish between files and directories with [FILE] and [DIR] " + "prefixes. This tool is essential for understanding directory structure and " + "finding specific files within a directory. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string() - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -454,11 +450,11 @@ server.registerTool( "Results clearly distinguish between files and directories with [FILE] and [DIR] " + "prefixes. This tool is useful for understanding directory structure and " + "finding specific files within a directory. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), sortBy: z.enum(["name", "size"]).optional().default("name").describe("Sort entries by name or size") - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -533,11 +529,11 @@ server.registerTool( "Each entry includes 'name', 'type' (file/directory), and 'children' for directories. " + "Files have no children array, while directories always have a children array (which may be empty). " + "The output is formatted with 2-space indentation for readability. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), excludePatterns: z.array(z.string()).optional().default([]) - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -603,11 +599,11 @@ server.registerTool( "and rename them in a single operation. If the destination exists, the " + "operation will fail. Works across different directories and can be used " + "for simple renaming within the same directory. Both source and destination must be within allowed directories.", - inputSchema: { + inputSchema: z.object({ source: z.string(), destination: z.string() - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true } }, async (args: z.infer) => { @@ -633,12 +629,12 @@ server.registerTool( "Use pattern like '*.ext' to match files in current directory, and '**/*.ext' to match files in all subdirectories. " + "Returns full paths to all matching items. Great for finding files when you don't know their exact location. " + "Only searches within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string(), pattern: z.string(), excludePatterns: z.array(z.string()).optional().default([]) - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -661,10 +657,10 @@ server.registerTool( "information including size, creation time, last modified time, permissions, " + "and type. This tool is perfect for understanding file characteristics " + "without reading the actual content. Only works within allowed directories.", - inputSchema: { + inputSchema: z.object({ path: z.string() - }, - outputSchema: { content: z.string() }, + }), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async (args: z.infer) => { @@ -689,8 +685,8 @@ server.registerTool( "Subdirectories within these allowed directories are also accessible. " + "Use this to understand which directories and their nested paths are available " + "before trying to access files.", - inputSchema: {}, - outputSchema: { content: z.string() }, + inputSchema: z.object({}), + outputSchema: z.object({ content: z.string() }), annotations: { readOnlyHint: true } }, async () => { @@ -715,7 +711,7 @@ async function updateAllowedDirectoriesFromRoots(requestedRoots: Root[]) { } // Handles dynamic roots updates during runtime, when client sends "roots/list_changed" notification, server fetches the updated roots and replaces all allowed directories with the new roots. -server.server.setNotificationHandler(RootsListChangedNotificationSchema, async () => { +server.server.setNotificationHandler('notifications/roots/list_changed', async () => { try { // Request the updated roots list from the client const response = await server.server.listRoots(); diff --git a/src/filesystem/package.json b/src/filesystem/package.json index c943ce24d3..12dca82b3a 100644 --- a/src/filesystem/package.json +++ b/src/filesystem/package.json @@ -25,10 +25,11 @@ "test": "vitest run --coverage" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", "diff": "^8.0.3", "glob": "^10.5.0", - "minimatch": "^10.0.1" + "minimatch": "^10.0.1", + "@modelcontextprotocol/server": "^2.0.0-alpha.3", + "@modelcontextprotocol/client": "^2.0.0-alpha.3" }, "devDependencies": { "@types/diff": "^5.0.9", diff --git a/src/filesystem/roots-utils.ts b/src/filesystem/roots-utils.ts index 5e26bb246b..39b05c733f 100644 --- a/src/filesystem/roots-utils.ts +++ b/src/filesystem/roots-utils.ts @@ -2,7 +2,7 @@ import { promises as fs, type Stats } from 'fs'; import path from 'path'; import os from 'os'; import { normalizePath } from './path-utils.js'; -import type { Root } from '@modelcontextprotocol/sdk/types.js'; +import type { Root } from '@modelcontextprotocol/server'; import { fileURLToPath } from "url"; /** diff --git a/src/memory/__tests__/resource.test.ts b/src/memory/__tests__/resource.test.ts index 432633050b..ed1f132962 100644 --- a/src/memory/__tests__/resource.test.ts +++ b/src/memory/__tests__/resource.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; -import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { SubscribeRequestSchema, UnsubscribeRequestSchema } from '@modelcontextprotocol/sdk/types.js'; +import type { McpServer } from '@modelcontextprotocol/server'; import { KnowledgeGraphManager, registerKnowledgeGraphResource, @@ -59,8 +58,8 @@ describe('knowledge-graph resource subscriptions', () => { return { mockServer, inner }; } - function handlerFor(inner: ReturnType['inner'], schema: unknown) { - const call = inner.setRequestHandler.mock.calls.find((c) => c[0] === schema); + function handlerFor(inner: ReturnType['inner'], method: string) { + const call = inner.setRequestHandler.mock.calls.find((c) => c[0] === method); if (!call) throw new Error('handler not registered'); return call[1] as (request: { params: { uri: string } }) => Promise; } @@ -80,9 +79,9 @@ describe('knowledge-graph resource subscriptions', () => { registerKnowledgeGraphSubscriptions(mockServer); - const schemas = inner.setRequestHandler.mock.calls.map((c) => c[0]); - expect(schemas).toContain(SubscribeRequestSchema); - expect(schemas).toContain(UnsubscribeRequestSchema); + const methods = inner.setRequestHandler.mock.calls.map((c) => c[0]); + expect(methods).toContain('resources/subscribe'); + expect(methods).toContain('resources/unsubscribe'); }); it('subscribe and unsubscribe handlers acknowledge with an empty result', async () => { @@ -91,7 +90,7 @@ describe('knowledge-graph resource subscriptions', () => { registerKnowledgeGraphSubscriptions(mockServer); const req = { params: { uri: 'memory://knowledge-graph' } }; - await expect(handlerFor(inner, SubscribeRequestSchema)(req)).resolves.toEqual({}); - await expect(handlerFor(inner, UnsubscribeRequestSchema)(req)).resolves.toEqual({}); + await expect(handlerFor(inner, 'resources/subscribe')(req)).resolves.toEqual({}); + await expect(handlerFor(inner, 'resources/unsubscribe')(req)).resolves.toEqual({}); }); }); diff --git a/src/memory/index.ts b/src/memory/index.ts index 9865c5318e..4643318728 100644 --- a/src/memory/index.ts +++ b/src/memory/index.ts @@ -1,8 +1,7 @@ #!/usr/bin/env node -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { SubscribeRequestSchema, UnsubscribeRequestSchema } from "@modelcontextprotocol/sdk/types.js"; +import { StdioServerTransport } from "@modelcontextprotocol/server/stdio"; +import { McpServer } from "@modelcontextprotocol/server"; import { z } from "zod"; import { promises as fs } from 'fs'; import path from 'path'; @@ -279,12 +278,12 @@ server.registerTool( { title: "Create Entities", description: "Create multiple new entities in the knowledge graph", - inputSchema: { + inputSchema: z.object({ entities: z.array(EntitySchema) - }, - outputSchema: { + }), + outputSchema: z.object({ entities: z.array(EntitySchema) - }, + }), annotations: { readOnlyHint: false, destructiveHint: false, @@ -308,12 +307,12 @@ server.registerTool( { title: "Create Relations", description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice", - inputSchema: { + inputSchema: z.object({ relations: z.array(RelationSchema) - }, - outputSchema: { + }), + outputSchema: z.object({ relations: z.array(RelationSchema) - }, + }), annotations: { readOnlyHint: false, destructiveHint: false, @@ -337,18 +336,18 @@ server.registerTool( { title: "Add Observations", description: "Add new observations to existing entities in the knowledge graph", - inputSchema: { + inputSchema: z.object({ observations: z.array(z.object({ entityName: z.string().describe("The name of the entity to add the observations to"), contents: z.array(z.string()).describe("An array of observation contents to add") })) - }, - outputSchema: { + }), + outputSchema: z.object({ results: z.array(z.object({ entityName: z.string(), addedObservations: z.array(z.string()) })) - }, + }), annotations: { readOnlyHint: false, destructiveHint: false, @@ -372,13 +371,13 @@ server.registerTool( { title: "Delete Entities", description: "Delete multiple entities and their associated relations from the knowledge graph", - inputSchema: { + inputSchema: z.object({ entityNames: z.array(z.string()).describe("An array of entity names to delete") - }, - outputSchema: { + }), + outputSchema: z.object({ success: z.boolean(), message: z.string() - }, + }), annotations: { readOnlyHint: false, destructiveHint: true, @@ -402,16 +401,16 @@ server.registerTool( { title: "Delete Observations", description: "Delete specific observations from entities in the knowledge graph", - inputSchema: { + inputSchema: z.object({ deletions: z.array(z.object({ entityName: z.string().describe("The name of the entity containing the observations"), observations: z.array(z.string()).describe("An array of observations to delete") })) - }, - outputSchema: { + }), + outputSchema: z.object({ success: z.boolean(), message: z.string() - }, + }), annotations: { readOnlyHint: false, destructiveHint: true, @@ -435,13 +434,13 @@ server.registerTool( { title: "Delete Relations", description: "Delete multiple relations from the knowledge graph", - inputSchema: { + inputSchema: z.object({ relations: z.array(RelationSchema).describe("An array of relations to delete") - }, - outputSchema: { + }), + outputSchema: z.object({ success: z.boolean(), message: z.string() - }, + }), annotations: { readOnlyHint: false, destructiveHint: true, @@ -465,11 +464,11 @@ server.registerTool( { title: "Read Graph", description: "Read the entire knowledge graph", - inputSchema: {}, - outputSchema: { + inputSchema: z.object({}), + outputSchema: z.object({ entities: z.array(EntitySchema), relations: z.array(RelationSchema) - }, + }), annotations: { readOnlyHint: true, destructiveHint: false, @@ -492,13 +491,13 @@ server.registerTool( { title: "Search Nodes", description: "Search for nodes in the knowledge graph based on a query", - inputSchema: { + inputSchema: z.object({ query: z.string().describe("The search query to match against entity names, types, and observation content") - }, - outputSchema: { + }), + outputSchema: z.object({ entities: z.array(EntitySchema), relations: z.array(RelationSchema) - }, + }), annotations: { readOnlyHint: true, destructiveHint: false, @@ -521,13 +520,13 @@ server.registerTool( { title: "Open Nodes", description: "Open specific nodes in the knowledge graph by their names", - inputSchema: { + inputSchema: z.object({ names: z.array(z.string()).describe("An array of entity names to retrieve") - }, - outputSchema: { + }), + outputSchema: z.object({ entities: z.array(EntitySchema), relations: z.array(RelationSchema) - }, + }), annotations: { readOnlyHint: true, destructiveHint: false, @@ -575,11 +574,11 @@ export function registerKnowledgeGraphResource( // notifications/resources/updated when mutation tools change the graph. export function registerKnowledgeGraphSubscriptions(server: McpServer) { server.server.registerCapabilities({ resources: { subscribe: true } }); - server.server.setRequestHandler(SubscribeRequestSchema, async (request) => { + server.server.setRequestHandler("resources/subscribe", async (request) => { resourceSubscribers.add(request.params.uri); return {}; }); - server.server.setRequestHandler(UnsubscribeRequestSchema, async (request) => { + server.server.setRequestHandler("resources/unsubscribe", async (request) => { resourceSubscribers.delete(request.params.uri); return {}; }); diff --git a/src/memory/package.json b/src/memory/package.json index e32d25a3e2..4883d95f7f 100644 --- a/src/memory/package.json +++ b/src/memory/package.json @@ -25,7 +25,8 @@ "test": "vitest run --coverage" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0" + "@modelcontextprotocol/server": "^2.0.0-alpha.3", + "@modelcontextprotocol/core": "^2.0.0-alpha.1" }, "devDependencies": { "@types/node": "^22", diff --git a/src/sequentialthinking/index.ts b/src/sequentialthinking/index.ts index 217845bb3d..15fbbd527f 100644 --- a/src/sequentialthinking/index.ts +++ b/src/sequentialthinking/index.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'; +import { McpServer } from '@modelcontextprotocol/server'; import { z } from "zod"; import { SequentialThinkingServer } from './lib.js'; @@ -80,7 +80,7 @@ You should: 9. Repeat the process until satisfied with the solution 10. Provide a single, ideally correct answer as the final output 11. Only set nextThoughtNeeded to false when truly done and a satisfactory answer is reached`, - inputSchema: { + inputSchema: z.object({ thought: z.string().describe("Your current thinking step"), nextThoughtNeeded: coercedBoolean.describe("Whether another thought step is needed"), thoughtNumber: z.coerce.number().int().min(1).describe("Current thought number (numeric value, e.g., 1, 2, 3)"), @@ -90,20 +90,20 @@ You should: branchFromThought: z.coerce.number().int().min(1).optional().describe("Branching point thought number"), branchId: z.string().optional().describe("Branch identifier"), needsMoreThoughts: coercedBoolean.optional().describe("If more thoughts are needed") - }, + }), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, - outputSchema: { + outputSchema: z.object({ thoughtNumber: z.number(), totalThoughts: z.number(), nextThoughtNeeded: z.boolean(), branches: z.array(z.string()), thoughtHistoryLength: z.number() - }, + }), }, async (args) => { const result = thinkingServer.processThought(args); diff --git a/src/sequentialthinking/package.json b/src/sequentialthinking/package.json index a88de803b5..f6ce8e5b02 100644 --- a/src/sequentialthinking/package.json +++ b/src/sequentialthinking/package.json @@ -25,9 +25,9 @@ "test": "vitest run --coverage" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", "chalk": "^5.3.0", - "yargs": "^17.7.2" + "yargs": "^17.7.2", + "@modelcontextprotocol/server": "^2.0.0-alpha.3" }, "devDependencies": { "@types/node": "^22",