Skip to content

feat(mcp): update a running Shiny MCP App in place via update_<appId>_app (#4415)#4418

Merged
schloerke merged 10 commits into
mcpfrom
schloerke/issue-4415
Jul 17, 2026
Merged

feat(mcp): update a running Shiny MCP App in place via update_<appId>_app (#4415)#4418
schloerke merged 10 commits into
mcpfrom
schloerke/issue-4415

Conversation

@schloerke

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #4414. Gives an MCP host/model an explicit update verb so it can change an already-open Shiny MCP App in place instead of re-opening it (which today renders a fresh instance per open_* call).

When an app declares mcpConfigure(arguments = ...), Shiny now auto-registers a companion update_<appId>_app tool. A model call to it runs server-side, targets a specific running session, and pushes new arguments through the existing mcpUpdates() reactive channel — no re-render, no author code beyond the single observe(mcpUpdates()) apps already write.

Design (5 decisions)

  1. Explicit session targetingupdate_* takes a required session token; no broadcast/most-recent guessing. To update several instances the model loops.
  2. Server-side reactiveVal overlay — each MCP session holds a server-push reactiveVal; mcpUpdates() overlays it on the client-delivered init args (per-key, latest wins) then allow-list filters. Successive pushes accumulate.
  3. Registry via existing appsByToken — keyed by session$token; unknown/stale/non-MCP token → tool error (never silent success).
  4. Auto tool, only when arguments declared — handler pushes inside withReactiveDomain(session, …) + requestFlush() so the app's observer fires in the right context.
  5. Token delivery — on connect the app announces its session$token to the model (reserved-key envelope through mcpUpdateModelContext, + a text instruction); mcpUpdateModelContext() payload now stamps session into structuredContent.

Entirely R-side — the JS bridge already forwards these messages.

Known limitations (see mcp/limitations.md)

  • Host-passthrough spike: needs end-to-end confirmation that a real host (claude.ai) forwards the {session, state} structured content + instruction so the model can echo the id. (Verify in Claude Desktop.)
  • Multi-instance: with several open instances the model must pick the right token; no server-side guarantee.

Docs & tests

  • Spec: mcp/design-mcp-update-running-app.md; plan: mcp/implementation-plan-update-running-app.md.
  • ?mcp-session roxygen, mcp/design-mcpConfigure.md, mcp/limitations.md, NEWS.md updated; demo apps (clock/demo/cars) get explanatory comments — the update path needs zero app-code change.
  • Full MCP test suite: 279 passing (registry lifecycle, overlay/accumulate semantics, dispatch incl. error paths, tool visibility, connect-time announcement, envelope shape).

🤖 Generated with Claude Code

@schloerke

Copy link
Copy Markdown
Collaborator Author

✅ Verified end-to-end in Claude Desktop (2026-07-17)

Both open items from mcp/limitations.md now confirmed working against a real host (Claude Desktop, stdio transport):

  • Host-passthrough spike (§4): the host forwards the announced session token into the model's context, and the model calls update_<appId>_app in place to change the running instance — it no longer re-opens a fresh instance.
  • Multi-instance targeting (§5): with two instances of the app open, updating the first instance's label targeted the correct session token.

The multi-instance case remains a model-judgment path (no server-side guarantee), so the caveat stays documented — but it works in practice for the common case. Pushed c44eac267 marking both as confirmed. Not yet spot-checked on claude.ai (web); the tunnel transport is expected to carry it.

@schloerke
schloerke merged commit c394d5b into mcp Jul 17, 2026
12 checks passed
@schloerke
schloerke deleted the schloerke/issue-4415 branch July 17, 2026 20:16
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.

1 participant