Skip to content

Instantly share code, notes, and snippets.

@jimbrig
Forked from simonpcouch/mcp_client_demo.R
Created May 20, 2025 23:48
Show Gist options
  • Save jimbrig/5546c4635e8313d6d18d619839f85c63 to your computer and use it in GitHub Desktop.
Save jimbrig/5546c4635e8313d6d18d619839f85c63 to your computer and use it in GitHub Desktop.
A demo implementation of the MCP client protocol in R
# an example server: acquaint's MCP server for R sessions
r_process <- callr::r_bg(
function() acquaint::mcp_server(),
stdout = "|",
stdin = "|"
)
Sys.sleep(1)
log_cat_client <- function(x, append = TRUE) {
log_file <- "~/mcp_client_test.txt"
cat(x, "\n\n", sep = "", append = append, file = log_file)
}
send_and_receive <- function(process, message) {
# send the message
json_msg <- jsonlite::toJSON(message, auto_unbox = TRUE)
log_cat_client(c("FROM CLIENT: ", json_msg))
process$write_input(paste0(json_msg, "\n"))
# poll for response
output <- NULL
attempts <- 0
max_attempts <- 20
while (length(output) == 0 && attempts < max_attempts) {
Sys.sleep(0.2)
output <- process$read_output_lines()
attempts <- attempts + 1
}
if (!is.null(output) && length(output) > 0) {
log_cat_client(c("FROM SERVER: ", output[1]))
return(fromJSON(output[1]))
}
log_cat_client(c("ALERT: No response received after ", attempts, " attempts"))
return(NULL)
}
# step 1: Initialize the MCP connection
initialize_request <- list(
jsonrpc = "2.0",
id = 1,
method = "initialize",
params = list(
protocolVersion = "2024-11-05",
capabilities = list(
tools = list(
listChanged = FALSE
)
),
clientInfo = list(
name = "MCP Test Client",
version = "0.1.0"
)
)
)
init_response <- send_and_receive(r_process, initialize_request)
# step 2: Send initialized notification
# For some reason, if I send this, the buffer gets tied up and the following
# tools/list isn't appropriately responded to.
# Don't expect a response here, so no `receive()`
# initialized_notification <- list(
# jsonrpc = "2.0",
# method = "notifications/initialized"
# )
#
# r_process$write_input(jsonlite::toJSON(initialized_notification, auto_unbox = TRUE))
# step 3: request the list of tools
tools_request <- list(
jsonrpc = "2.0",
id = 2,
method = "tools/list"
)
tools_response <- send_and_receive(r_process, tools_request)
# step 4: call a tool
platform_request <- list(
jsonrpc = "2.0",
id = 3,
method = "tools/call",
params = list(
name = "btw_tool_session_platform_info"
)
)
platform_response <- send_and_receive(r_process, platform_request)
# clean up
r_process$kill()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment