-
Notifications
You must be signed in to change notification settings - Fork 2
implement R as an MCP client #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The first portion of this test should run with the configured GitHub secrets, and we can enable the second portion with a `live-api.yaml`
In attempt to resolve: ``` ── Error ('test-client.R:25:3'): mcp_tools works ─────────────────────────────── <c_error/rlib_error_3_0/rlib_error/error/condition> Error in `c("process_initialize(self, private, command, args, stdin, stdout, ", " stderr, pty, pty_options, connections, poll_connection, env, " )`: ! Native call to `processx_exec` failed Caused by error in `chain_call(c_processx_exec, command, c(command, args), pty, pty_options, ...`: ! cannot start processx process '' (system error 2, No such file or directory) @unix/processx.c:613 (processx_exec) ```
* Use `parse_json()` over `fromJSON()` to avoid conversion to data frame * Handle every ellmer object type, including arrays/objects, and actually note if they're required or not Still need to find a way to not set defaults in the function definition if the argument is required.
This Action fails on macOS and the post action runs indefinitely when that happens.
Naming things feels really tricky here. Here's one proposal, but I'm not that excited about it:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some specific bits where your intuition is appreciated, @gadenbuie :)
R/client.R
Outdated
#' @returns | ||
#' * `mcp_tools()` returns a list of ellmer tools that can be passed directly | ||
#' to the `$set_tools()` method of an [ellmer::Chat] object. | ||
#' * `set_mcp_config()` returns the path to the new MCP config file, invisibly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you feel these two entry points are a reasonable interface to this functionality? i.e. 1) configure connections in the same way as Claude Desktop via a .json file, and then 2) collect them all as a $set_tools()
-compatible list?
server_as_ellmer_tools <- function(server) { | ||
tools <- server$tools$tools | ||
|
||
tools_out <- list() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a browser()
-worthy point, to poke at the tools
object. Is this a reasonable way to go from that json to a list of ellmer tools? Does this duplicate anything in ellmer / fail to make use of relevant functions from that package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could potentially build on the contents_record()
and contents_replay()
helper methods proposed by Barret over in tidyverse/ellmer#503. In that world, I think you'd want to create an McpToolDef
class with ellmer:::ToolDef
as its parent and then you'd have custom methods for each. (Or anyway, you'll probably want to keep contents_record()
and contents_replay()
in mind because their intended to support serializing a Chat
object for bookmarking in shinychat.)
NAMESPACE
Outdated
@@ -3,4 +3,6 @@ | |||
export(mcp_server) | |||
export(mcp_session) | |||
export(mcp_set_tools) | |||
export(mcp_tools) | |||
export(set_mcp_config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on better names certainly appreciated, though maybe this has much to do with #35.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think mcp_tools()
needs a verb. Is it a counterpart to mcp_set_tools()
? If so, then maybe mcp_get_tools()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right in #34 (comment) and I'd advocate for
- Sticking with
mcp_server_
andmcp_client_
as prefixes - Calling
mcp_session()
something else likemcp_server_add_session()
ormcp_server_connect_session()
or justmcp_server_connect()
(I think you could get away with this last one if there's a hard line betweenmcp_server_
andmcp_client_
. - Separating
mcp_{serer,client}_tools()
into_get_tools()
and_set_tools()
, but only if both actions are relevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, I think you should also differentiate between mcp_server_
as in R-as-a-server and other external or remote MCP servers, which might use remote as the name. I think this would mean the$mcp_servers
would be the$mcp_remote_servers
or just the$mcp_remotes
. Just in general, anything you can do to remove the cognitive overhead of "server" appearing all over the place would be great
`mcp_client_config()` is a getter, and its output can be adjusted by configuring an option. Users can just supply a different path to `mcp_tools()` to fetch a different set of tools. Uses the newer suggested name since `set_*()` no longer makes sense, but otherwise doesn't make changes to naming.
A proof of concept to close #29.
Marking as draft as 1) this is a very scrappy implementation at the moment and 2)we would definitely want to revisit naming before merging. Also worth noting that this only implements the stdio protocol and not (yet) the http one.With the GitHub MCP server mentioned in the docs configured:
Created on 2025-05-28 with reprex v2.1.1