feat: register MCP author tools with registerMcpTool() + ellmer::tool()#4412
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the experimental
options(shiny.mcp.tools = list(...))MCP author-tool API with an exportedregisterMcpTool()that acceptsellmer::tool()objects — the same tool-definition style used bymcptoolsand James Wade'sshinymcp.Before: hand-written JSON Schema +
handler, configured via a process option.After: typed
ellmer::tool()objects, registered via a function.What changed
registerMcpTool(...)— accepts one or moreellmer::ToolDefobjects, stored in.globals$mcpAuthorTools(keyed by name, last-write-wins). Validates eagerly: a non-ellmer::tool()argument or a name colliding with a reserved tool (the app-opening tool or the internal_shiny_*tunnel tools) is a hard error at registration time. Name mirrorsregisterInputHandler().tools/listderives each tool'sinputSchemafrom the ToolDef's typed@argumentsvia ellmer's provider-agnosticas_json(), the same path asmcptools::tool_as_json()(keeps us aligned for future upstreaming).tools/callruns the tool withrlang::exec(tool, !!!args). Return-value handling is unchanged (character → text, list →structuredContent, promises supported, errors →isError).ellmeradded toSuggests (>= 0.4.0), gated byrlang::check_installed(). Nothing on the core MCP path touches ellmer unless a tool is registered.options(shiny.mcp.tools)is removed — no fallback. This API was experimental and unreleased (only reachedmcp, notmain), so no deprecation.Scope
Author tools only. The app-opening tool (
options(shiny.mcp.tool), singular) and every othershiny.mcp.*option are intentionally unchanged — a separate follow-up.Docs & demos
?registerMcpToolhelp;mcp-session"Additional tools" section now points at it; pkgdown + NEWS updated.mcp/demo-app,mcp/demo-app2) andmcp/architecture/README/QUESTIONS migrated to the new API.mcp/design-register-mcp-tool.mdandmcp/implementation-plan-register-mcp-tool.md.Testing
Full MCP test suite green (author-tool tests gated with
skip_if_not_installed("ellmer")); the single skip is the CRAN-only stdio subprocess test. Covers registration/validation, tools/list schema (includingrequiredarray shape), tools/call execution, error propagation, and async/promise handlers.