refactor: finish MCP SDK v2 migration

This commit is contained in:
Andrew Khadder 2026-07-14 17:07:30 -07:00
commit f94cb38b0b
No known key found for this signature in database
2 changed files with 684 additions and 540 deletions

View file

@ -24,10 +24,11 @@
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.0",
"@modelcontextprotocol/node": "2.0.0-beta.4",
"@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/server": "2.0.0-beta.4",
"cors": "^2.8.5",
"express": "^5.1.0",
"jose": "^6.0.0"
"jose": "^6.0.0",
"zod": "^4.1.13"
},
"devDependencies": {
"@types/cors": "^2.8.19",

View file

@ -21,13 +21,13 @@ import {
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { UrlElicitationRequiredError } from "@modelcontextprotocol/sdk/types.js";
import type {
CallToolResult,
ReadResourceResult,
} from "@modelcontextprotocol/sdk/types.js";
import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
import {
McpServer,
UrlElicitationRequiredError,
type CallToolResult,
type ReadResourceResult,
} from "@modelcontextprotocol/server";
import cors from "cors";
import express, { type Express, type Request, type Response } from "express";
import { SignJWT, jwtVerify } from "jose";
@ -35,6 +35,7 @@ import crypto from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";
// Works both from source (server.ts) and compiled (dist/server.js). Derived
// from import.meta.url rather than import.meta.filename/dirname, which are
@ -605,7 +606,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Show Auth Button",
description:
"Public tool: shows a button that triggers the protected get_secret tool.",
inputSchema: {},
inputSchema: z.object({}),
_meta: { ui: { resourceUri: buttonUri } },
},
async (): Promise<CallToolResult> => ({
@ -638,7 +639,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Get Secret",
description:
"Protected tool: returns secret data. Requires authentication.",
inputSchema: {},
inputSchema: z.object({}),
_meta: { ui: { resourceUri: secretUri } },
},
async (): Promise<CallToolResult> => {
@ -682,7 +683,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Revoke Auth Token",
description:
"Protected tool: revokes the caller's entire auth session (access + refresh token).",
inputSchema: {},
inputSchema: z.object({}),
},
async (): Promise<CallToolResult> => {
if (!authInfo) {
@ -720,7 +721,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Elicit URL (session-callback)",
description:
"URL elicitation via elicitInput. Blocks until the client accepts; sends ElicitCompleteNotification before returning.",
inputSchema: {},
inputSchema: z.object({}),
},
async (_args, extra): Promise<CallToolResult> => {
const eid = crypto.randomUUID();
@ -735,7 +736,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
message: "Please open this URL to continue.",
elicitationId: eid,
},
{ relatedRequestId: extra.requestId, timeout: 300_000 },
{ relatedRequestId: extra.mcpReq.id, timeout: 300_000 },
);
// Send completion notification before returning — lands on the same SSE
// stream as this tool response. For Streamable HTTP this is the ONLY
@ -767,7 +768,7 @@ export function createServer(authInfo?: AuthInfo, req?: Request): McpServer {
title: "Elicit by -32042 Error",
description:
"Throws UrlElicitationRequiredError (-32042). Client must open the URL, then retry. On retry, if the last-issued elicitationId was completed, sends ElicitCompleteNotification and succeeds.",
inputSchema: {},
inputSchema: z.object({}),
},
async (): Promise<CallToolResult> => {
// Retry path: check if the user completed the elicitation we last issued.
@ -1031,7 +1032,7 @@ export function createApp(): Express {
}
const server = createServer(authInfo, req);
const transport = new StreamableHTTPServerTransport({
const transport = new NodeStreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on("close", () => {