Skip to content

Commit 0464603

Browse files
fix(pdf-server): port to v2 (raw-shape inputSchema → z.object, .tool→.registerTool)
All 33 fails fixed: v2 registerTool requires StandardSchema (raw shapes lack ~standard.validate). Also extra.signal→extra.mcpReq.signal, drop stale v1 import. test:full now 277/2/0 (was 197/1/33). e2e API tests pass; browser tests need playwright install (env, not v2 break).
1 parent 6365821 commit 0464603

2 files changed

Lines changed: 21 additions & 24 deletions

File tree

examples/pdf-server/server.ts

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
import { randomUUID } from "crypto";
1414
import fs from "node:fs";
1515
import path from "node:path";
16-
import { McpServer } from "@modelcontextprotocol/server";
17-
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
16+
import { McpServer, type Server } from "@modelcontextprotocol/server";
1817
import {
1918
registerAppResource,
2019
registerAppTool,
@@ -1200,10 +1199,9 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
12001199
const { readPdfRange } = createPdfCache();
12011200

12021201
// Tool: list_pdfs - List available PDFs
1203-
server.tool(
1202+
server.registerTool(
12041203
"list_pdfs",
1205-
"List available PDFs that can be displayed",
1206-
{},
1204+
{ description: "List available PDFs that can be displayed" },
12071205
async (): Promise<CallToolResult> => {
12081206
const seen = new Set<string>();
12091207
const localFiles: string[] = [];
@@ -1285,7 +1283,7 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
12851283
title: "Read PDF Bytes",
12861284
description:
12871285
"Read a range of bytes from a PDF (max 512KB per request). The model should NOT call this tool directly.",
1288-
inputSchema: {
1286+
inputSchema: z.object({
12891287
url: z.string().describe("PDF URL or local file path"),
12901288
offset: z.number().min(0).default(0).describe("Byte offset"),
12911289
byteCount: z
@@ -1294,7 +1292,7 @@ export function createServer(options: CreateServerOptions = {}): McpServer {
12941292
.max(MAX_CHUNK_BYTES)
12951293
.default(MAX_CHUNK_BYTES)
12961294
.describe("Bytes to read"),
1297-
},
1295+
}),
12981296
outputSchema: z.object({
12991297
url: z.string(),
13001298
bytes: z.string().describe("Base64 encoded bytes"),
@@ -1381,7 +1379,7 @@ Returns a viewUUID in structuredContent. Pass it to \`interact\`:
13811379
13821380
Accepts local files (use list_pdfs), client MCP root directories, or any HTTPS URL.
13831381
Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before display.`,
1384-
inputSchema: {
1382+
inputSchema: z.object({
13851383
url: z
13861384
.string()
13871385
.default(DEFAULT_PDF)
@@ -1397,7 +1395,7 @@ Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before
13971395
"If true and the PDF has form fields, prompt the user to fill them before displaying",
13981396
),
13991397
}),
1400-
},
1398+
}),
14011399
outputSchema: z.object({
14021400
viewUUID: z
14031401
.string()
@@ -2348,7 +2346,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
23482346
**FORMS** — fill_form: fill fields with \`fields\` array of {name, value}.
23492347
23502348
**SAVE** — save_as: write the annotated PDF (annotations + form values) to a file. Pass \`path\` (absolute path or file://) for a new location, or omit \`path\` to overwrite the original. Set \`overwrite: true\` to replace an existing file (always required when omitting \`path\`).`,
2351-
inputSchema: {
2349+
inputSchema: z.object({
23522350
viewUUID: z
23532351
.string()
23542352
.describe(
@@ -2445,7 +2443,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
24452443
.describe(
24462444
"Array of commands to execute sequentially. More efficient than separate calls. Tip: end with get_pages+getScreenshots to verify changes.",
24472445
),
2448-
},
2446+
}),
24492447
},
24502448
async (
24512449
{
@@ -2522,7 +2520,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
25222520
const result = await processInteractCommand(
25232521
uuid,
25242522
commandList[i],
2525-
extra.signal,
2523+
extra.mcpReq.signal,
25262524
);
25272525
if (result.isError) {
25282526
const errText = result.content
@@ -2579,7 +2577,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
25792577
title: "Submit Page Data",
25802578
description:
25812579
"Submit rendered page data for a get_pages request (used by viewer). The model should NOT call this tool directly.",
2582-
inputSchema: {
2580+
inputSchema: z.object({
25832581
requestId: z
25842582
.string()
25852583
.describe("The request ID from the get_pages command"),
@@ -2592,7 +2590,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
25922590
}),
25932591
)
25942592
.describe("Page data entries"),
2595-
},
2593+
}),
25962594
_meta: { ui: { visibility: ["app"] } },
25972595
},
25982596
async ({ requestId, pages }): Promise<CallToolResult> => {
@@ -2622,7 +2620,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
26222620
title: "Submit Save Data",
26232621
description:
26242622
"Submit annotated PDF bytes for a save_as request (used by viewer). The model should NOT call this tool directly.",
2625-
inputSchema: {
2623+
inputSchema: z.object({
26262624
requestId: z
26272625
.string()
26282626
.describe("The request ID from the save_as command"),
@@ -2631,7 +2629,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
26312629
.string()
26322630
.optional()
26332631
.describe("Error message if the viewer failed to build bytes"),
2634-
},
2632+
}),
26352633
_meta: { ui: { visibility: ["app"] } },
26362634
},
26372635
async ({ requestId, data, error }): Promise<CallToolResult> => {
@@ -2661,7 +2659,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
26612659
title: "Submit Viewer State",
26622660
description:
26632661
"Submit a viewer-state snapshot for a get_viewer_state request (used by viewer). The model should NOT call this tool directly.",
2664-
inputSchema: {
2662+
inputSchema: z.object({
26652663
requestId: z
26662664
.string()
26672665
.describe("The request ID from the get_viewer_state command"),
@@ -2673,7 +2671,7 @@ Example — add a signature image and a stamp, then screenshot to verify:
26732671
.string()
26742672
.optional()
26752673
.describe("Error message if the viewer failed to read state"),
2676-
},
2674+
}),
26772675
_meta: { ui: { visibility: ["app"] } },
26782676
},
26792677
async ({ requestId, state, error }): Promise<CallToolResult> => {
@@ -2703,9 +2701,9 @@ Example — add a signature image and a stamp, then screenshot to verify:
27032701
title: "Poll PDF Commands",
27042702
description:
27052703
"Poll for pending commands for a PDF viewer. The model should NOT call this tool directly.",
2706-
inputSchema: {
2704+
inputSchema: z.object({
27072705
viewUUID: z.string().describe("The viewUUID of the PDF viewer"),
2708-
},
2706+
}),
27092707
_meta: { ui: { visibility: ["app"] } },
27102708
},
27112709
async ({ viewUUID: uuid }): Promise<CallToolResult> => {
@@ -2750,10 +2748,10 @@ Example — add a signature image and a stamp, then screenshot to verify:
27502748
title: "Save PDF",
27512749
description:
27522750
"Save annotated PDF bytes back to a local file. The model should NOT call this tool directly — use interact with action: save_as instead.",
2753-
inputSchema: {
2751+
inputSchema: z.object({
27542752
url: z.string().describe("Original PDF URL or local file path"),
27552753
data: z.string().describe("Base64-encoded PDF bytes"),
2756-
},
2754+
}),
27572755
outputSchema: z.object({
27582756
filePath: z.string(),
27592757
mtimeMs: z.number(),

examples/pdf-server/src/mcp-app.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import {
1212
applyDocumentTheme,
1313
applyHostStyleVariables,
1414
} from "@modelcontextprotocol/ext-apps";
15-
import type { CallToolResult } from "@modelcontextprotocol/server";
16-
import type { ContentBlock } from "@modelcontextprotocol/sdk/spec.types.js";
15+
import type { CallToolResult, ContentBlock } from "@modelcontextprotocol/client";
1716
import * as pdfjsLib from "pdfjs-dist";
1817
import { AnnotationLayer, AnnotationMode, TextLayer } from "pdfjs-dist";
1918
import "pdfjs-dist/web/pdf_viewer.css";

0 commit comments

Comments
 (0)