From 32d03f84ab2f357066cb61799695eac2b223b1a2 Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Fri, 23 Jan 2026 09:13:07 +0800 Subject: [PATCH] chore: upgrade sample-servers to MCP SDK 1.25.3 and zod 4 --- packages/mcp-auth/package.json | 2 +- packages/sample-servers/.env.example | 5 + packages/sample-servers/README.md | 10 +- packages/sample-servers/package.json | 4 +- .../sample-servers/src/todo-manager/index.ts | 131 +++++++++--------- packages/sample-servers/src/whoami/index.js | 57 +++----- packages/sample-servers/src/whoami/index.ts | 55 +++----- pnpm-lock.yaml | 117 +++++++++++++--- 8 files changed, 221 insertions(+), 160 deletions(-) create mode 100644 packages/sample-servers/.env.example diff --git a/packages/mcp-auth/package.json b/packages/mcp-auth/package.json index 9d5682b..926fab6 100644 --- a/packages/mcp-auth/package.json +++ b/packages/mcp-auth/package.json @@ -77,7 +77,7 @@ "cors": "^2.8.5", "jose": "^6.0.10", "snakecase-keys": "^8.0.1", - "zod": "^3.24.3" + "zod": "^4.3.5" }, "peerDependencies": { "express": "^5.0.1" diff --git a/packages/sample-servers/.env.example b/packages/sample-servers/.env.example new file mode 100644 index 0000000..64cc7e6 --- /dev/null +++ b/packages/sample-servers/.env.example @@ -0,0 +1,5 @@ +# WhoAmI server & Todo manager server +MCP_AUTH_ISSUER=https://your-tenant.logto.app/oidc + +# Todo manager server only +MCP_RESOURCE_IDENTIFIER=https://todo.example.com/api/ diff --git a/packages/sample-servers/README.md b/packages/sample-servers/README.md index fbdfe99..43f0975 100644 --- a/packages/sample-servers/README.md +++ b/packages/sample-servers/README.md @@ -43,5 +43,11 @@ pnpm start:todo-manager ## Environment variables -Make sure to set the following environment variable before running the servers: -- `MCP_AUTH_ISSUER`: The URL of your MCP Auth server +### WhoAmI server + +- `MCP_AUTH_ISSUER`: The issuer URL of your authorization server (e.g., `https://your-tenant.logto.app/oidc`) + +### Todo manager server + +- `MCP_AUTH_ISSUER`: The issuer URL of your authorization server (e.g., `https://your-tenant.logto.app/oidc`) +- `MCP_RESOURCE_IDENTIFIER`: The resource identifier for the protected resource (e.g., `https://todo.example.com/api/`). Note: The trailing slash is recommended due to an MCP SDK behavior that appends `/` when constructing resource indicators. diff --git a/packages/sample-servers/package.json b/packages/sample-servers/package.json index c8a26fb..c4f377e 100644 --- a/packages/sample-servers/package.json +++ b/packages/sample-servers/package.json @@ -25,11 +25,11 @@ "node": "^20.19.0 || ^22.0.0 || ^23.0.0 || ^24.0.0" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.17.1", + "@modelcontextprotocol/sdk": "^1.25.3", "dotenv": "^16.5.0", "express": "5.0.1", "mcp-auth": "workspace:^", - "zod": "^3.24.3" + "zod": "^4.3.5" }, "devDependencies": { "@silverhand/eslint-config": "^6.0.1", diff --git a/packages/sample-servers/src/todo-manager/index.ts b/packages/sample-servers/src/todo-manager/index.ts index a4d292e..54eb899 100644 --- a/packages/sample-servers/src/todo-manager/index.ts +++ b/packages/sample-servers/src/todo-manager/index.ts @@ -2,22 +2,31 @@ import assert from 'node:assert'; import { type AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { configDotenv } from 'dotenv'; import express from 'express'; -import { fetchServerConfig, MCPAuth, MCPAuthBearerAuthError } from 'mcp-auth'; +import { MCPAuth, MCPAuthBearerAuthError } from 'mcp-auth'; import { z } from 'zod'; import { TodoService } from './todo-service.js'; configDotenv(); +const { MCP_AUTH_ISSUER, MCP_RESOURCE_IDENTIFIER } = process.env; + +if (!MCP_AUTH_ISSUER) { + throw new Error('MCP_AUTH_ISSUER environment variable is required'); +} + +if (!MCP_RESOURCE_IDENTIFIER) { + throw new Error('MCP_RESOURCE_IDENTIFIER environment variable is required'); +} + const todoService = new TodoService(); const assertUserId = (authInfo?: AuthInfo) => { - const { subject } = authInfo ?? {}; - assert(subject, 'Invalid auth info'); - return subject; + assert(authInfo?.subject, 'Invalid auth info'); + return authInfo.subject; }; const hasRequiredScopes = (userScopes: string[], requiredScopes: string[]): boolean => { @@ -30,11 +39,13 @@ const server = new McpServer({ version: '0.0.0', }); -server.tool( +server.registerTool( 'create-todo', - 'Create a new todo', - { content: z.string() }, - ({ content }: { content: string }, { authInfo }) => { + { + description: 'Create a new todo', + inputSchema: { content: z.string() }, + }, + ({ content }, { authInfo }) => { const userId = assertUserId(authInfo); /** @@ -52,29 +63,38 @@ server.tool( } ); -server.tool('get-todos', 'List all todos', ({ authInfo }) => { - const userId = assertUserId(authInfo); +server.registerTool( + 'get-todos', + { + description: 'List all todos', + inputSchema: {}, + }, + (_params, { authInfo }) => { + const userId = assertUserId(authInfo); - /** - * If user has 'read:todos' scope, they can access all todos (todoOwnerId = undefined) - * If user doesn't have 'read:todos' scope, they can only access their own todos (todoOwnerId = userId) - */ - const todoOwnerId = hasRequiredScopes(authInfo?.scopes ?? [], ['read:todos']) - ? undefined - : userId; + /** + * If user has 'read:todos' scope, they can access all todos (todoOwnerId = undefined) + * If user doesn't have 'read:todos' scope, they can only access their own todos (todoOwnerId = userId) + */ + const todoOwnerId = hasRequiredScopes(authInfo?.scopes ?? [], ['read:todos']) + ? undefined + : userId; - const todos = todoService.getAllTodos(todoOwnerId); + const todos = todoService.getAllTodos(todoOwnerId); - return { - content: [{ type: 'text', text: JSON.stringify(todos) }], - }; -}); + return { + content: [{ type: 'text', text: JSON.stringify(todos) }], + }; + } +); -server.tool( +server.registerTool( 'delete-todo', - 'Delete a todo by id', - { id: z.string() }, - ({ id }: { id: string }, { authInfo }) => { + { + description: 'Delete a todo by id', + inputSchema: { id: z.string() }, + }, + ({ id }, { authInfo }) => { const userId = assertUserId(authInfo); const todo = todoService.getTodoById(id); @@ -116,51 +136,34 @@ server.tool( } ); -const { MCP_AUTH_ISSUER } = process.env; - -if (!MCP_AUTH_ISSUER) { - throw new Error('MCP_AUTH_ISSUER environment variable is required'); -} - -const authServerConfig = await fetchServerConfig(MCP_AUTH_ISSUER, { type: 'oidc' }); - const mcpAuth = new MCPAuth({ - server: authServerConfig, + protectedResources: { + metadata: { + resource: MCP_RESOURCE_IDENTIFIER, + authorizationServers: [{ issuer: MCP_AUTH_ISSUER, type: 'oidc' }], + scopesSupported: ['create:todos', 'read:todos', 'delete:todos'], + }, + }, }); const PORT = 3001; const app = express(); -app.use(mcpAuth.delegatedRouter()); -app.use(mcpAuth.bearerAuth('jwt')); - -// Below is the boilerplate code from MCP SDK documentation -const transports: Record = {}; - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.get('/sse', async (_req, res) => { - // Create SSE transport for legacy clients - const transport = new SSEServerTransport('/messages', res); - // eslint-disable-next-line @silverhand/fp/no-mutation - transports[transport.sessionId] = transport; - - res.on('close', () => { - // eslint-disable-next-line @silverhand/fp/no-delete, @typescript-eslint/no-dynamic-delete - delete transports[transport.sessionId]; - }); +app.use(mcpAuth.protectedResourceMetadataRouter()); +app.use( + mcpAuth.bearerAuth('jwt', { + resource: MCP_RESOURCE_IDENTIFIER, + audience: MCP_RESOURCE_IDENTIFIER, + }) +); +app.post('/', async (request, response) => { + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); await server.connect(transport); -}); - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.post('/messages', async (req, res) => { - const sessionId = String(req.query.sessionId); - const transport = transports[sessionId]; - if (transport) { - await transport.handlePostMessage(req, res, req.body); - } else { - res.status(400).send('No transport found for sessionId'); - } + await transport.handleRequest(request, response, request.body); + response.on('close', () => { + void transport.close(); + }); }); app.listen(PORT); diff --git a/packages/sample-servers/src/whoami/index.js b/packages/sample-servers/src/whoami/index.js index caf4846..ab17b12 100644 --- a/packages/sample-servers/src/whoami/index.js +++ b/packages/sample-servers/src/whoami/index.js @@ -1,5 +1,3 @@ -// @ts-check - /** * This is the JavaScript version of the WhoAmI server. * @@ -7,7 +5,7 @@ * @see {@link file://./whoami.ts} for the TypeScript version. */ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { configDotenv } from 'dotenv'; import express from 'express'; import { fetchServerConfig, MCPAuth, MCPAuthTokenVerificationError } from 'mcp-auth'; @@ -21,13 +19,20 @@ const server = new McpServer({ }); // Add a tool to the server that returns the current user's information -server.tool('whoami', ({ authInfo }) => { - return { - content: [ - { type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) }, - ], - }; -}); +server.registerTool( + 'whoami', + { + description: 'Get the current user information', + inputSchema: {}, + }, + (_params, { authInfo }) => { + return { + content: [ + { type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) }, + ], + }; + } +); const { MCP_AUTH_ISSUER } = process.env; @@ -85,33 +90,13 @@ const app = express(); app.use(mcpAuth.delegatedRouter()); app.use(mcpAuth.bearerAuth(verifyToken)); -// Below is the boilerplate code from MCP SDK documentation -const transports = {}; - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.get('/sse', async (_req, res) => { - // Create SSE transport for legacy clients - const transport = new SSEServerTransport('/messages', res); - // eslint-disable-next-line @silverhand/fp/no-mutation - transports[transport.sessionId] = transport; - - res.on('close', () => { - // eslint-disable-next-line @silverhand/fp/no-delete - delete transports[transport.sessionId]; - }); - +app.post('/', async (request, response) => { + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); await server.connect(transport); -}); - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.post('/messages', async (req, res) => { - const sessionId = String(req.query.sessionId); - const transport = transports[sessionId]; - if (transport) { - await transport.handlePostMessage(req, res, req.body); - } else { - res.status(400).send('No transport found for sessionId'); - } + await transport.handleRequest(request, response, request.body); + response.on('close', () => { + transport.close(); + }); }); app.listen(PORT); diff --git a/packages/sample-servers/src/whoami/index.ts b/packages/sample-servers/src/whoami/index.ts index 88fe81d..c328473 100644 --- a/packages/sample-servers/src/whoami/index.ts +++ b/packages/sample-servers/src/whoami/index.ts @@ -6,7 +6,7 @@ */ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { configDotenv } from 'dotenv'; import express from 'express'; import { @@ -25,13 +25,20 @@ const server = new McpServer({ }); // Add a tool to the server that returns the current user's information -server.tool('whoami', ({ authInfo }) => { - return { - content: [ - { type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) }, - ], - }; -}); +server.registerTool( + 'whoami', + { + description: 'Get the current user information', + inputSchema: {}, + }, + (_params, { authInfo }) => { + return { + content: [ + { type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) }, + ], + }; + } +); const { MCP_AUTH_ISSUER } = process.env; @@ -86,33 +93,13 @@ const app = express(); app.use(mcpAuth.delegatedRouter()); app.use(mcpAuth.bearerAuth(verifyToken)); -// Below is the boilerplate code from MCP SDK documentation -const transports: Record = {}; - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.get('/sse', async (_req, res) => { - // Create SSE transport for legacy clients - const transport = new SSEServerTransport('/messages', res); - // eslint-disable-next-line @silverhand/fp/no-mutation - transports[transport.sessionId] = transport; - - res.on('close', () => { - // eslint-disable-next-line @silverhand/fp/no-delete, @typescript-eslint/no-dynamic-delete - delete transports[transport.sessionId]; - }); - +app.post('/', async (request, response) => { + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); await server.connect(transport); -}); - -// eslint-disable-next-line unicorn/prevent-abbreviations -app.post('/messages', async (req, res) => { - const sessionId = String(req.query.sessionId); - const transport = transports[sessionId]; - if (transport) { - await transport.handlePostMessage(req, res, req.body); - } else { - res.status(400).send('No transport found for sessionId'); - } + await transport.handleRequest(request, response, request.body); + response.on('close', () => { + void transport.close(); + }); }); app.listen(PORT); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 586bce5..d8de590 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,12 +33,12 @@ importers: specifier: ^8.0.1 version: 8.0.1 zod: - specifier: ^3.24.3 - version: 3.24.3 + specifier: ^4.3.5 + version: 4.3.6 devDependencies: '@modelcontextprotocol/sdk': specifier: ^1.17.1 - version: 1.17.1 + version: 1.25.3(hono@4.11.5)(zod@4.3.6) '@silverhand/eslint-config': specifier: ^6.0.1 version: 6.0.1(eslint@8.57.0)(prettier@3.5.3)(typescript@5.8.3) @@ -91,8 +91,8 @@ importers: packages/sample-servers: dependencies: '@modelcontextprotocol/sdk': - specifier: ^1.17.1 - version: 1.17.1 + specifier: ^1.25.3 + version: 1.25.3(hono@4.11.5)(zod@4.3.6) dotenv: specifier: ^16.5.0 version: 16.5.0 @@ -103,8 +103,8 @@ importers: specifier: workspace:^ version: link:../mcp-auth zod: - specifier: ^3.24.3 - version: 3.24.3 + specifier: ^4.3.5 + version: 4.3.6 devDependencies: '@silverhand/eslint-config': specifier: ^6.0.1 @@ -398,6 +398,12 @@ packages: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -443,9 +449,15 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@modelcontextprotocol/sdk@1.17.1': - resolution: {integrity: sha512-CPle1OQehbWqd25La9Ack5B07StKIxh4+Bf19qnpZKJC1oI22Y0czZHbifjw1UoczIfKBwBDAp/dFxvHG13B5A==} + '@modelcontextprotocol/sdk@1.25.3': + resolution: {integrity: sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true '@mswjs/interceptors@0.38.6': resolution: {integrity: sha512-qFlpmObPqeUs4u3oFYv/OM/xyX+pNa5TRAjqjvMhbGYlyMhzSrE5UfncL2rUcEeVfD9Gebgff73hPwqcOwJQNA==} @@ -880,9 +892,20 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -1554,6 +1577,9 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -1738,6 +1764,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.11.5: + resolution: {integrity: sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==} + engines: {node: '>=16.9.0'} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -1963,6 +1993,9 @@ packages: jose@6.0.10: resolution: {integrity: sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -2000,6 +2033,12 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2516,6 +2555,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3084,13 +3127,13 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: - zod: ^3.24.1 + zod: ^3.25 || ^4 - zod@3.24.3: - resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: @@ -3380,6 +3423,10 @@ snapshots: '@eslint/js@8.57.0': {} + '@hono/node-server@1.19.9(hono@4.11.5)': + dependencies: + hono: 4.11.5 + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -3436,9 +3483,11 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@modelcontextprotocol/sdk@1.17.1': + '@modelcontextprotocol/sdk@1.25.3(hono@4.11.5)(zod@4.3.6)': dependencies: - ajv: 6.12.6 + '@hono/node-server': 1.19.9(hono@4.11.5) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 @@ -3446,11 +3495,14 @@ snapshots: eventsource-parser: 3.0.3 express: 5.0.1 express-rate-limit: 7.5.1(express@5.0.1) + jose: 6.1.3 + json-schema-typed: 8.0.2 pkce-challenge: 5.0.0 raw-body: 3.0.0 - zod: 3.24.3 - zod-to-json-schema: 3.24.6(zod@3.24.3) + zod: 4.3.6 + zod-to-json-schema: 3.25.1(zod@4.3.6) transitivePeerDependencies: + - hono - supports-color '@mswjs/interceptors@0.38.6': @@ -3892,6 +3944,10 @@ snapshots: acorn@8.14.1: {} + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -3899,6 +3955,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} @@ -4713,6 +4776,8 @@ snapshots: fast-safe-stringify@2.1.1: {} + fast-uri@3.1.0: {} + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -4922,6 +4987,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.11.5: {} + hosted-git-info@2.8.9: {} html-escaper@2.0.2: {} @@ -5153,6 +5220,8 @@ snapshots: jose@6.0.10: {} + jose@6.1.3: {} + joycon@3.1.1: {} js-tokens@4.0.0: {} @@ -5178,6 +5247,10 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json-stringify-safe@5.0.1: {} @@ -5621,6 +5694,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -6305,8 +6380,8 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.24.6(zod@3.24.3): + zod-to-json-schema@3.25.1(zod@4.3.6): dependencies: - zod: 3.24.3 + zod: 4.3.6 - zod@3.24.3: {} + zod@4.3.6: {}