Skip to content

Add MCP Apps: interactive UI resources for MCP tools#112

Merged
rhennigan merged 52 commits intomainfrom
feature/mcp-apps
Feb 26, 2026
Merged

Add MCP Apps: interactive UI resources for MCP tools#112
rhennigan merged 52 commits intomainfrom
feature/mcp-apps

Conversation

@rhennigan
Copy link
Owner

Summary

Implements the MCP Apps extension (io.modelcontextprotocol/ui) for the MCPServer paclet, enabling MCP tools to deliver interactive HTML UIs alongside their text/image results. When an MCP host (e.g. Claude Desktop, VS Code) advertises UI support, tools can now return rich embedded viewers instead of plain text.

What's included

  • Extension negotiation — Detect UI-capable clients during initialize handshake and advertise server UI support in capabilities
  • UI resource registry (Kernel/UIResources.wl) — Load, list, and serve HTML apps from Assets/Apps/ via MCP resources/list and resources/read
  • Tool ↔ UI linkage — Dynamically attach _meta.ui (resourceUri, visibility) to tools/list responses for UI-capable clients
  • Four built-in MCP Apps:
    • WolframAlpha viewer — Embeds WA results via CloudDeploy + WolframNotebookEmbedder with dark mode, auto-resize, and follow-up queries
    • Evaluator viewer — Cloud notebook viewer for WL evaluation results with syntax-highlighted input/output
    • Notebook viewer — Embeds interactive Wolfram Cloud notebooks inline
    • MCPAppsTest — Diagnostic tool for verifying the full MCP Apps pipeline
  • EnableMCPApps option for InstallMCPServer — Allows users to disable MCP Apps at install time via MCP_APPS_ENABLED environment variable
  • Documentation — New docs/mcp-apps.md, updated README, AGENTS.md, developer docs, and symbol reference pages
  • Design specificationSpecs/MCPApps.md documenting the full architecture and protocol

Key implementation details

  • UI resources are served as text/html content via standard MCP resource protocol
  • CSP metadata in companion JSON files enables secure iframe sandboxing
  • Cloud notebook embedding uses the Wolfram Notebook Embedder JS library
  • All apps support dark/light theme via host-provided CSS custom properties
  • Auto-resize via ResizeObserver reporting to host

Test plan

  • 16 unit tests for UI resource registry (Tests/MCPApps.wlt) — loading, initialization, listing
  • 20 unit tests for extension negotiation (Tests/MCPApps.wlt) — client capability detection, init response
  • 16 unit tests for tool UI metadata (Tests/MCPApps.wlt) — metadata generation and integration
  • Tests for resource handlers — resources/list and resources/read
  • Tool-specific UI tests (Tests/WolframAlpha-UI.wlt, Tests/WolframLanguageEvaluator-UI.wlt, Tests/NotebookViewer.wlt, Tests/MCPAppsTest.wlt)
  • Manual: Verify MCP Apps render correctly in Claude Desktop with UI support enabled
  • Manual: Verify graceful degradation when client does not advertise UI support

🤖 Generated with Claude Code

rhennigan and others added 30 commits February 23, 2026 17:36
Detailed spec covering the integration of the MCP Apps extension
(io.modelcontextprotocol/ui) into the MCPServer paclet, enabling
interactive HTML UIs for WolframAlpha and WL Evaluator results in
MCP hosts like Claude Desktop and VS Code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaced the detailed per-item task list with a high-level phase overview
that references Specs/MCPApps.md for implementation details. This keeps
the TODO focused on tracking progress at the session level rather than
duplicating the spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, and tests

Add the foundational file structure for MCP Apps support:
- Kernel/UIResources.wl with UI resource registry, loading, serving, and tool metadata functions
- Assets/Apps/ with placeholder HTML/JSON for WolframAlpha and Evaluator viewers
- Tests/MCPApps.wlt with test skeleton for all new functions
- New shared symbols in CommonSymbols.wl and error messages in Messages.wl
- Apps asset location registered in PacletInfo.wl
- UIResources context added to Main.wl

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Modify handleMethod["initialize"] to detect UI-capable clients via
  clientSupportsUIQ and compute init response dynamically
- Add initResponse overloads that include extensions in capabilities
  when client advertises io.modelcontextprotocol/ui support
- Remove pre-computed $initResult; response is now built per-request
- Call initializeUIResources at server startup
- Fix clientSupportsUIQ to use nested Association lookup instead of
  KeyExistsQ (which doesn't support nested key paths)
- Add 20 unit tests for extension negotiation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix loadUIResource to use ByteArrayToString/ReadByteArray instead of
ReadString with unsupported CharacterEncoding option. Fix listUIResources
DownValues ordering bug by using If instead of separate conditional
definitions. Add 16 unit tests for loadUIResource, initializeUIResources,
and listUIResources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wire up resources/list handler to call listUIResources[] for dynamic
  UI resource listing based on client capabilities
- Add resources/read handler via handleResourceRead that serves HTML
  content from the UI resource registry with proper error handling
- Return MCP error code -32602 for unknown or invalid resource URIs
- Fix readUIResource control flow bug: use If/Else instead of
  If+semicolon so throwFailure properly short-circuits execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dynamic _meta.ui attachment to tools/list responses for UI-capable
clients. Tools with registered UI resources (WolframAlpha, Evaluator)
now include resourceUri and visibility metadata when the client
supports the MCP Apps extension.

Key changes:
- Fix toolUIMetadata to use If instead of /; to avoid definition
  reordering
- Add withToolUIMetadata to dynamically enrich tool lists at request
  time (needed because $toolList is pre-computed before $clientSupportsUI
  is set)
- Wire withToolUIMetadata into handleMethod["tools/list"]
- Add 16 unit tests covering metadata generation and integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document proposed rules for common Wolfram Language pitfalls:
ReadString with CharacterEncoding, Nothing in associations,
and KeyExistsQ with nested key paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
writeError and debugPrint in UIResources.wl resolved to the
UIResources`Private` context instead of the Common` context where
their definitions live (defined in StartMCPServer.wl). This made
the logging calls in initializeUIResources effectively no-ops.

Fixed by declaring both symbols as shared in CommonSymbols.wl.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements a tool that embeds interactive Wolfram Cloud notebooks
inline using the Wolfram Notebook Embedder library. Includes HTML
app with dark mode support, auto-resize, and CSP metadata.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements a minimal diagnostic tool that echoes input with server
metadata. The companion HTML app provides a visual checklist for
verifying the full MCP Apps pipeline: initialization, tool I/O,
host theming, and app-initiated tool calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds tool subcontexts and UI resource associations for both new
tools. Updates existing MCPApps tests to expect 4 registered UI
resources. Marks interactive testing milestone complete in TODO.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The tool name now better reflects its purpose as a viewer for Wolfram Cloud notebooks. Updated package context, internal symbols, tool registration, UI resource mapping, and all tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Load WolframNotebookEmbedder dynamically via a Promise instead of a
static script tag. The embedNotebook function now waits for the library
to be ready before attempting to use it, preventing the intermittent
"WolframNotebookEmbedder library failed to load" error that occurred
when the tool-input message arrived before the CDN script finished
downloading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of building a custom HTML viewer that parses base64 images and
renders pods, embed the WolframAlpha website directly in an iframe. This
leverages the full native WA experience (pods, drill-down, related
queries) without reimplementing it. Removes the WolframAlphaFollowUp
app-only tool since follow-ups are handled by updating the iframe URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set a defensive default of False at server startup so shared UI capability checks never depend on symbol unbound state.

Co-authored-by: Cursor <cursoragent@cursor.com>
WolframAlpha blocks iframe embedding, so the Phase 2 spec is rewritten
to use Chatbook's FormatWolframAlphaPods -> CloudDeploy ->
WolframNotebookEmbedder instead. Updates graceful degradation table,
security CSP, testing plan, protocol messages, and files summary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add _meta forwarding in evaluateTool so structured tool results can pass
metadata (e.g. notebookUrl) through to MCP clients. Also register the
NotebookViewer tool in the default Wolfram server configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CloudDeploy-based notebook embedding for WolframAlpha results when
the client supports MCP Apps. The tool deploys formatted WA pods to
Wolfram Cloud and returns a notebookUrl in both content-item _meta and
top-level _meta to ensure the viewer receives it via both tools/call
responses and tool-result notifications.

The HTML viewer now checks top-level _meta first (forwarded by the host
in ui/notifications/tool-result) then falls back to content-item _meta
(from direct tools/call). Raw text content is never displayed - only
the embedded notebook or an error message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the generic input/button with a styled input field matching the
WolframAlpha website: orange border, SVG clear (X) and compute (=) buttons
inside the input frame, focus glow, and dark mode support. Remove the
redundant "Open in W|A" link since the output already includes one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add cell margins and hide cell brackets in the deployed notebook for a
cleaner embedded appearance. Add AppearanceElements -> None to CloudDeploy
to remove the default cloud notebook chrome.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rhennigan and others added 16 commits February 25, 2026 13:23
The NotebookViewer tool is no longer needed as notebook embedding is now
handled directly by the WolframAlpha MCP App viewer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use more neutral dark grays instead of blue-tinted backgrounds for the
dark color scheme to better match typical dark mode conventions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set $CloudEvaluation = True during both WolframAlpha evaluation and pod
formatting so Chatbook produces cloud-compatible output. Add explicit
FontColor -> Black to the output cell to ensure readability against the
default white cloud notebook background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all prescriptive Wolfram Language code blocks that would quickly
get out of sync with the actual codebase. Replace with prose descriptions
of requirements, data structures (as tables), and pipeline steps. Keep
all JSON protocol examples (which define the contract) and CSP metadata.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check off the WolframAlpha viewer app and metadata tasks in the MCP Apps
TODO. Add exploratory notes for the WL evaluator CloudDeploy pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…uageEvaluator

When $clientSupportsUI and $CloudConnected, the evaluator now creates a cloud
notebook containing syntax-highlighted input + formatted output and returns a
notebookUrl metadata item. The evaluator-viewer MCP App embeds the notebook
via WolframNotebookEmbedder with text+image fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ExportByteArray on non-Image graphics (e.g. Manipulate) can produce
animated PNGs, which is not desired for base64 image content items.
Rasterize first to ensure a static image.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Observe a content-wrapping <div id="app-root"> instead of
document.documentElement for auto-resize height reporting. The <html>
element fills the iframe viewport, so its scrollHeight never decreases
after the host enlarges the iframe. A regular div sizes to its content
intrinsically, correctly reporting smaller heights when content shrinks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document a new "EnableMCPApps" option for InstallMCPServer that allows
users to disable MCP Apps UI features at install time via the
MCP_APPS_ENABLED environment variable. Renumber subsequent sections
and test cases, and update the implementation files summary and phase
dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These task lists have been fully addressed — the implementation is
complete and tracked in the spec and git history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add runtime check via MCP_APPS_ENABLED environment variable so users can
disable MCP Apps UI features at install time with "EnableMCPApps" -> False.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the MCP Apps system (interactive UI resources) in README,
AGENTS.md, and all relevant developer docs. Adds new docs/mcp-apps.md
with comprehensive coverage of capability negotiation, UI resources,
tool-UI linkage, architecture, and extension guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for the MCP Apps extension (io.modelcontextprotocol/ui) to the MCPServer paclet, enabling UI-capable MCP hosts to render interactive HTML apps alongside tool results via resources/list/resources/read and _meta.ui tool annotations.

Changes:

  • Implements UI capability negotiation during initialize and advertises UI support in server capabilities when enabled.
  • Adds a UI resource registry backed by Assets/Apps/* and exposes it through MCP resources/list and resources/read.
  • Enhances tool listings/results for UI-capable clients (tool _meta.ui linkage; WA/WL evaluator UI-enhanced result metadata; adds NotebookViewer and MCPAppsTest tools) plus extensive docs/specs/tests.

Reviewed changes

Copilot reviewed 38 out of 42 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
docs/tools.md Documents MCP Apps tools and notes UI-enhanced modes for existing tools.
docs/testing.md Adds test-file boilerplate guidance and updates how to run tests.
docs/servers.md Documents automatic MCP Apps enablement and how to disable it per install.
docs/mcp-clients.md Documents MCP_APPS_ENABLED and EnableMCPApps install option behavior.
docs/mcp-apps.md New end-user/developer documentation for MCP Apps architecture and extension points.
docs/getting-started.md Updates repository layout doc to include new Assets/Apps and UIResources module.
docs/README.md Adds MCP Apps to the developer docs index.
Tests/WolframLanguageEvaluator-UI.wlt Adds UI-path tests for the evaluator tool and helpers used in UI mode.
Tests/WolframAlpha-UI.wlt Adds UI-path tests for WolframAlpha helper behavior and branching.
Tests/NotebookViewer.wlt Adds tests for the new NotebookViewer tool and UI resource integration.
Tests/MCPAppsTest.wlt Adds tests for the new MCPAppsTest tool and UI resource integration.
Tests/MCPApps.wlt Adds broad unit/integration tests for negotiation, registry, handlers, and tool metadata.
TODO.md Updates MCP apps TODO section and adds follow-on feature ideas.
Specs/MCPApps.md New detailed design specification for MCP Apps support and security model.
README.md Updates top-level README with MCP Apps feature and tool/option docs.
PacletInfo.wl Registers Assets/Apps as a paclet asset location ("Apps").
Kernel/UIResources.wl Introduces UI resource registry, negotiation helpers, and tool UI metadata helpers.
Kernel/Tools/WolframLanguageEvaluator.wl Adds UI-enhanced evaluation path that CloudDeploys a notebook and returns _meta.notebookUrl.
Kernel/Tools/WolframAlpha.wl Adds UI-enhanced WA path that CloudDeploys a formatted notebook and returns _meta.notebookUrl.
Kernel/Tools/Tools.wl Registers new tool subcontexts (NotebookViewer, MCPAppsTest).
Kernel/Tools/NotebookViewer.wl New tool to emit viewer JSON payload for embedding a Cloud notebook in the UI app.
Kernel/Tools/MCPAppsTest.wl New diagnostic tool for end-to-end MCP Apps pipeline verification.
Kernel/StartMCPServer.wl Adds initialize-time UI negotiation, resource handlers, tool list augmentation, and _meta forwarding.
Kernel/Messages.wl Adds message tags for UI resource failures.
Kernel/Main.wl Ensures Wolfram\MCPServer`UIResources`` context is loaded.
Kernel/InstallMCPServer.wl Adds EnableMCPApps option and injects MCP_APPS_ENABLED=false when disabled.
Kernel/CommonSymbols.wl Declares shared MCP Apps symbols for cross-module access.
Assets/Apps/wolframalpha-viewer.html Adds WolframAlpha interactive viewer app (embedder + fallback rendering).
Assets/Apps/wolframalpha-viewer.json Adds CSP metadata for WA viewer.
Assets/Apps/notebook-viewer.html Adds generic notebook viewer app.
Assets/Apps/notebook-viewer.json Adds CSP metadata for notebook viewer.
Assets/Apps/mcp-apps-test.html Adds diagnostic MCP Apps test app.
Assets/Apps/mcp-apps-test.json Adds CSP metadata for diagnostic app.
Assets/Apps/evaluator-viewer.html Adds WL evaluator interactive viewer app.
Assets/Apps/evaluator-viewer.json Adds CSP metadata for evaluator viewer.
AGENTS.md Updates agent guidance and architecture listing to include MCP Apps components.
.cspell.json Adds MCP Apps-related vocabulary to spellchecker allowlist.
.claude/skills/update-docs/SKILL.md Adds a documentation update skill for automated doc maintenance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

rhennigan and others added 6 commits February 26, 2026 13:36
Update DefaultMCPTools-Keys test to include MCPAppsTest and NotebookViewer
tools. Remove WolframAlpha-UI tests that incorrectly expected graceful
handling of invalid inputs — toContentList and makeUIResult should give
internal failures for unhandled argument patterns. Clean up commented-out
catch-all definition in toContentList.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Use Hash[..., Automatic, "HexString"] instead of
IntegerString[Hash[..., "SHA256"], 16] for cleaner hex string generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When makeEvaluatorUIResult fails (e.g. cloud deploy error),
reuse the already-computed string result from evaluateWolframLanguageForUI
instead of calling evaluateWolframLanguage which re-runs the evaluation.
This prevents duplicated side effects and doubled runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d vs internal errors

Previously all failures from readUIResource were mapped to -32602 with a
generic "UI resource not found" message. Now UIResourceNotFound failures
return -32602 (invalid params) while unexpected/internal failures return
-32603 (internal error) with the actual failure message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rhennigan rhennigan requested a review from Copilot February 26, 2026 18:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 44 changed files in this pull request and generated 13 comments.

Comments suppressed due to low confidence (1)

Tests/MCPApps.wlt:1

  • This test tries to simulate “env var not set” by localizing/unsetting $Environment, but mcpAppsEnabledQ reads Environment["MCP_APPS_ENABLED"] (the function), so it won’t be affected by $Environment and can become flaky if MCP_APPS_ENABLED is set in the CI environment. Use Block[{Environment}, ...] (as the later tests do) to control what Environment["MCP_APPS_ENABLED"] returns in this test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rhennigan
Copy link
Owner Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@rhennigan rhennigan merged commit f58cba8 into main Feb 26, 2026
5 of 6 checks passed
@rhennigan rhennigan deleted the feature/mcp-apps branch February 26, 2026 20:05
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