R as an MCP server

The mcptools package enables apps like Claude Desktop, Claude Code, and VS Code GitHub Copilot to run R code using the Model Context Protocol (MCP). This vignette highlights the basics of using mcptools to launch R-based MCP servers before delving a bit further into advanced usage.

library(mcptools)

The basics

In the context of R as an MCP server, there are three main concepts to understand:

A system architecture diagram showing three main components: Client (left), Server (center), and Session (right). The Client box lists AI coding assistants including Claude Desktop, Claude Code, Copilot Chat in VS Code, and Positron Assistant. The Server is initiated with `mcp_server()` and contains tools for R functions like reading package documentation, running R code, and inspecting global environment objects. Sessions can be configured with `mcp_session()` and can optionally connect to interactive R sessions, with two example projects shown: 'Some R Project' and 'Other R Project'.

(In case this caught your eye: yes, the server is itself an R session. In mcptools’s documentation, we’ll always refer to the server R session just as the server; the fact that it’s implemented in R is only a technical detail.)

In the case you have some client that you want to connect to R, all you need to do is configure the command Rscript -e "mcptools::mcp_server()" according to your client’s instructions. Optionally, if you’d like the server to be able to access variables in interactive R sessions, add mcptools::mcp_session() to your .Rprofile, perhaps by first calling usethis::edit_r_profile().

Then, you’re good to go!

Multiple clients and R sessions

While a single client (and potentially a single R session) probably covers many users’ use cases, mcptools supports multiple clients and multiple R sessions. For example, for the former, you may be both chatting in Claude Desktop and running Claude Code in a terminal somewhere. Or, in the multiple R sessions situation, you may have two or more Positron instances running at once, with different data science projects in each.

As for multiple clients, this will “just work”; there’s nothing to keep in mind here.

As for multiple R sessions, mcptools will choose a default R session for your model to talk to without the client knowing it even had multiple options. So, you might have a project “goats” open in one Positron window and another project, “sheep”, open in another Positron window. mcptools provides models with two tools to facilitate toggling between sessions. The first, list_r_sessions(), allows the client to “discover” R sessions available to it by their working directory and (inferred) IDE. Then, the tool select_r_session() allows the client to (persistently) choose an R session. So, you could write “In my goats R session, \[some question\].” In that case, the model might call list_r_sessions() to find the full identifier for that goats session, then select_r_session(), then whatever other tools it will use to respond to your question. Notably, if you ask a follow-up question (and you haven’t closed the Positron window with goats pulled up in the meantime) in the same client chat, the client doesn’t need to use list_r_sessions() and select_r_session() again, and can just call whatever tools it needs to answer your follow-up.

As for both multiple clients and multiple R sessions, this will generally “just work.” That said, do note that clients can only be connected to one R session at a time. For most clients, like Claude Code, this isn’t much of an issue. For chat apps like Claude Desktop, though, you may run into hiccups when you have multiple chats actively going at the same time. For example, imagine I ask Claude via Claude Desktop about some problem in my R session “goats” and then, a moment later, spin up a different chat and ask about my “sheep” project. In the second chat, Claude will likely use select_r_session() to choose the “sheep” project. If I then go back to the chat about “goats” and ask a follow-up, the R session that any tool calls dispatch to will actually also be the “sheep” project. If the tool call, say, reads documentation, this isn’t an issue. If the tool call describe some variable in the global environment, though, the value of that variable may not exist in—or be different in—the “sheep” project.

Custom tools

By default, mcptools supplies clients with only the necessary infrastructural tools to implement interaction with active sessions. You may be interested in using mcptools via btw’s wrappers, which provide a set of atomic tools for data science. These tools allow clients to:

Users might be interested in extending these tools or supplying completely different ones. For example, you might register:

You can configure any set of tools that could be passed to the $set_tools() method of an ellmer Chat object as the tools that mcptools will supply to clients. To do so, supply a list of outputs from ellmer::tool() to the tools argument of mcp_server(). Relatedly, you’ll need to make sure that your code that specifies the new tools can run in a fresh R session; be sure to either namespace functions from libraries (like ellmer::tool() instead of tool()) or load the libraries entirely.