Skip to content

pdf-server: default to a single interact app tool (per-action tools behind --split-app-tools) - #830

Merged
ochafik merged 1 commit into
mainfrom
pdf-app-interact-tool
Oct 27, 2026
Merged

ochafik merged 1 commit into
mainfrom
pdf-app-interact-tool

Conversation

@ochafik

@ochafik ochafik commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Summary

The pdf-server view registered thirteen app tools (navigate, search, add_annotations, ...). On hosts that ask the user to approve each app tool separately, that is thirteen approval cards for one PDF viewer. This folds them into a single interact app tool by default, mirroring the server-side interact the example already ships for hosts without app-tool support:

  • One interact app tool with an action enum plus flat optional parameters, and an optional commands batch with the same contract as the server-side tool: content[i] is the result of commands[i], a failed step's slot is text starting with ERROR at step i/n (action) and the batch stops there, and isError is not set on multi-step batches (some host SDKs collapse isError results to content[0].text, which would drop images from earlier successful steps). Single-action calls return the handler's result verbatim — structuredContent, image content and isError included.
  • The thirteen definitions became data (APP_TOOL_DEFS): same handlers, same zod schemas. The schemas now double as per-action validation inside interact, so {action: "navigate"} without page fails with a per-action message.
  • --split-app-tools CLI flag restores the per-action tools for hosts that pick tools by name or do not charge an approval per tool. The tool surface is declared at the ui/initialize handshake, so the choice has to reach the view before connect(): the server injects a one-line PDF_APP_CONFIG script into the served view HTML (cached alongside the base bundle; logged fallback if no <head> tag is found).
  • get-document-info is renamed get_document_info so the action enum is uniformly snake_case.

The app tool and the server tool deliberately share the interact name and schema shape: a model that has learned one surface can use the other, and hosts expose only one of them per context.

Test plan

  • Unit (bun test examples/pdf-server, 197 pass): existing suite plus new tests for the split-mode HTML injection (skipped when the view bundle is not built, as in the publish workflow's test job, which runs the unit suite without building examples).
  • New e2e spec pdf-app-interact.spec.ts (5 tests, driving the view's tools by posting tools/call JSON-RPC from the sandbox frame): the view lists only interact; single-action dispatch reflected in viewer state; per-action required-param validation and the unknown-action fallback; a commands batch with 1:1 slots; and mid-batch failure semantics (ERROR slot, stop, no isError).
  • pdf-page-restore.spec.ts migrated to the interact surface (it drove the old navigate app tool); its frame/JSON-RPC helpers are extracted to tests/e2e/pdf-app-helpers.ts instead of a third copy. 7/7 pdf e2e tests pass locally; the one pdf-annotations.spec.ts failure in my environment reproduces identically on clean main.
  • tsc --noEmit for both the view and server configs; prettier clean.

Note: #820 adds get_current_pdf as a fourteenth app tool and will want a small rebase onto this — the tool becomes a fourteenth action.


Generated by Claude Code

Thirteen per-action app tools meant thirteen approval cards on hosts
that ask the user to approve each app tool separately. Fold them into
one interact app tool mirroring the server-side interact: an action
enum plus flat parameters, an optional commands batch with the same
contract (content[i] per commands[i], a failed step's slot starts with
ERROR, no isError on multi-step batches since some host SDKs collapse
isError results to content[0].text), and per-action validation from
the same zod schemas the split tools used.

The per-action tools stay available behind a new --split-app-tools
CLI flag: the server injects a one-line config script into the served
view HTML (cached alongside the base bundle), which the view reads
before connect(). get-document-info becomes get_document_info so the
action enum is uniformly snake_case.

Tests: unit coverage for the config injection (skipped when the view
bundle is not built, as in the publish workflow's test job), a new
e2e spec driving the app-side interact end to end (listing, dispatch,
validation, batch, mid-batch failure), and pdf-page-restore.spec.ts
migrated to the interact surface with the frame/JSON-RPC helpers
extracted to tests/e2e/pdf-app-helpers.ts instead of a third copy.

Co-authored-by: ochafik <ochafik@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Oct 27, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@830

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@830

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@830

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@830

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@830

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@830

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@830

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@830

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@830

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@830

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@830

@modelcontextprotocol/server-lazy-auth

npm i https://pkg.pr.new/@modelcontextprotocol/server-lazy-auth@830

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@830

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@830

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@830

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@830

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@830

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@830

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@830

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@830

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@830

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@830

commit: 9a95fe4

@ochafik
ochafik merged commit f6f01d5 into main Oct 27, 2026
21 checks passed
@ochafik ochafik mentioned this pull request Oct 27, 2026
ochafik added a commit that referenced this pull request Oct 27, 2026
Patch release: the pdf-server example defaults to a single interact app
tool with the per-action tools behind --split-app-tools (#830), the
map-server example gains a get-screenshot app tool (#821), the
pdf-server viewer restores the saved page on tool-result re-delivery
(#828), and the dependency refresh clears the open npm audit findings
(solid-js 1.9.17, sharp ^0.35.5 and in-range transitive updates, #827).

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants