通过一个函数调用,为您的Plumber API添加模型上下文协议(MCP)支持。
模型上下文协议(MCP)是一种标准协议,使AI助手(如Claude、ChatGPT等)能够与外部工具和服务进行交互。通过在您的Plumber API中添加MCP支持,您可以使您的R函数可用作:
# 从GitHub安装
remotes::install_github("armish/plumber2mcp")
此包需要:
library(plumber)
library(plumber2mcp)
# 创建并运行具有MCP支持的Plumber API,通过HTTP
pr("plumber.R") %>%
pr_mcp(transport = "http") %>%
pr_run(port = 8000)
您的API现在有:
http://localhost:8000/的常规HTTP端点http://localhost:8000/mcp的MCP服务器library(plumber)
library(plumber2mcp)
# 创建并运行具有原生标准IO传输的Plumber API
pr("plumber.R") %>%
pr_mcp(transport = "stdio")
与mcp-cli或其他MCP客户端一起使用:
server_config.json文件:{
"mcpServers": {
"plumber2mcp": {
"command": "Rscript",
"args": ["-e", "plumber::pr('api.R') %>% plumber2mcp::pr_mcp(transport='stdio')"],
"cwd": "."
}
}
}
mcp-cli servers # 应该显示您的服务器为“就绪”
mcp-cli tools # 列出可用工具
mcp-cli cmd --tool GET__echo --tool-args '{"msg": "Hello!"}' # 调用一个工具
pr_mcp()函数会自动:
plumber2mcp通过分析您的roxygen注释和函数签名,自动为您的API端点生成丰富的JSON模式和详细文档。这一功能借鉴了FastAPI-MCP,使得您的R API对AI助手更加易用。
当您使用roxygen注释记录您的端点时,plumber2mcp会创建全面的工具描述:
#* 计算数值数据的统计操作
#*
#* 此端点执行向量数字的各种统计计算。
#* 支持多种操作,并处理缺失值。
#*
#* @param numbers 数值向量,用于计算统计数据
#* @param operation 要执行的统计操作:"mean"、"median"、"sum"、"sd"(默认:"mean")
#* @param na_rm:bool 是否移除NA值的逻辑值(默认:TRUE)
#* @param digits:int 结果的小数位数(默认:2)
#* @return 包含计算结果和元数据的列表
#* @post /calculate
function(numbers, operation = "mean", na_rm = TRUE, digits = 2) {
# 将输入转换为数值
if (is.character(numbers)) {
numbers <- as.numeric(strsplit(numbers, ",")[[1]])
} else {
numbers <- as.numeric(numbers)
}
result <- switch(operation,
"mean" = mean(numbers, na.rm = na_rm),
"median" = median(numbers, na.rm = na_rm),
"sum" = sum(numbers, na.rm = na_rm),
"sd" = sd(numbers, na.rm = na_rm),
stop("未知操作:", operation)
)
list(
result = round(result, digits),
operation = operation,
count = length(numbers[!is.na(numbers)]),
input_length = length(numbers)
)
}
这会创建一个MCP工具,具有:
增强的描述:
计算数值数据的统计操作
此端点执行向量数字的各种统计计算。
支持多种操作,并处理缺失值。
参数:
- numbers (字符串):数值向量,用于计算统计数据
- operation (字符串) [默认:mean]:要执行的统计操作:"mean"、"median"、"sum"、"sd"
- na_rm (布尔值) [默认:TRUE]:是否移除NA值的逻辑值
- digits (整数) [默认:2]:结果的小数位数
HTTP方法:POST
路径:/calculate
输入模式:
{
"type": "object",
"properties": {
"numbers": {
"type": "string",
"description": "数值向量,用于计算统计数据"
},
"operation": {
"type": "string",
"description": "要执行的统计操作:\"mean\"、\"median\"、\"sum\"、\"sd\"",
"default": "mean"
},
"na_rm": {
"type": "boolean",
"description": "是否移除NA值的逻辑值",
"default": true
},
"digits": {
"type": "integer",
"description": "结果的小数位数",
"default": 2
}
},
"required": ["numbers"]
}
输出模式:
{
"type": "object",
"description": "结构化的响应对象",
"properties": {
"result": {
"type": "number",
"description": "响应字段:result"
},
"operation": {
"type": "string",
"description": "响应字段:operation"
},
"count": {
"type": "number",
"description": "响应字段:count"
},
"input_length": {
"type": "number",
"description": "响应字段:input_length"
}
}
}
智能类型映射:自动将R类型映射到JSON Schema类型:
logical → booleaninteger → integernumeric/double → numbercharacter → string:bool、:int、:array默认值检测:从函数签名中提取默认值并包含在模式中
必需参数 vs 可选参数:自动确定哪些参数是必需的,基于它们是否有默认值
输出模式生成:分析您的函数返回语句以自动生成响应模式
丰富的参数文档:从roxygen @param标签中提取参数描述
有了增强的模式,AI助手可以:
没有增强的模式:
用户:"你能帮我使用这个API计算一些数字的平均值吗?"
AI:"我能看到有一个calculate端点,但我不确定它需要哪些参数……"
有了增强的模式:
用户:"你能帮我使用这个API计算一些数字的平均值吗?"
AI:"我能看到您有一个calculate端点,它可以执行统计操作!
它需要一个'numbers'参数(必需),以及可选的'operation'(默认为'mean')、
'na_rm'(默认为TRUE)和'digits'(默认为2)。
让我为您调用它:
POST /calculate with {"numbers": "1,2,3,4,5"}
这将返回一个包含结果、所用操作、有效数字数量和输入长度的对象。"
为了充分利用增强的模式生成:
@param标签:bool、:int、:array注解以提高清晰度一旦应用了pr_mcp(),您的API会公开:
GET /mcp - 服务器信息和能力POST /mcp/messages - JSON-RPC消息处理器,用于MCP协议给定一个简单的Plumber API:
#* 回显输入
#*
#* 简单的端点,回显发送给它的任何消息
#*
#* @param msg:string 要回显的消息(默认:"Hello World")
#* @get /echo
function(msg = "Hello World") {
list(message = paste("Echo:", msg))
}
#* 将两个数字相加
#*
#* 对两个数值执行算术加法
#*
#* @param a:number 要相加的第一个数字
#* @param b:number 要相加的第二个数字
#* @param precision:int 结果的小数位数(默认:2)
#* @post /add
function(a, b, precision = 2) {
result <- as.numeric(a) + as.numeric(b)
list(
result = round(result, precision),
operation = "addition",
inputs = c(a, b)
)
}
这些端点成为具有完整模式的丰富MCP工具:
GET__echo - 智能默认处理的回显消息POST__add - 具有可配置精度和结构化输出的加法增强的文档为AI助手提供了关于参数类型、默认值、描述和预期响应格式的详细信息。
提示是AI助手可以发现并使用的可重用模板。它们为常见任务和工作流程提供结构化指导。
MCP中的提示是预定义的消息模板,它们:
# 不带参数的简单提示
pr %>%
pr_mcp(transport = "stdio") %>%
pr_mcp_prompt(
name = "r-help",
description = "获取R编程的帮助",
func = function() {
paste(
"我需要R编程的帮助。",
"请提供最佳实践和常见模式的指导。",
sep = "\n"
)
}
)
# 带参数的提示
pr %>%
pr_mcp(transport = "stdio") %>%
pr_mcp_prompt(
name = "analyze-dataset",
description = "为R数据集生成综合分析计划",
arguments = list(
list(
name = "dataset",
description = "要分析的R数据集名称",
required = TRUE
),
list(
name = "focus",
description = "要关注的具体方面",
required = FALSE
)
),
func = function(dataset, focus = "general") {
sprintf(
paste(
"请分析R中的%s数据集。",
"关注:%s",
"",
"提供:",
"1. 总结统计",
"2. 数据质量评估",
"3. 关键见解",
sep = "\n"
),
dataset, focus
)
}
)
# 多轮对话提示
pr %>%
pr_mcp(transport = "stdio") %>%
pr_mcp_prompt(
name = "code-review",
description = "审查R代码的质量和最佳实践",
arguments = list(
list(name = "code", description = "要审查的R代码", required = TRUE)
),
func = function(code) {
list(
list(
role = "user",
content = list(
type = "text",
text = paste("请审查这段R代码:", code, sep = "\n\n")
)
),
list(
role = "assistant",
content = list(
type = "text",
text = "我会检查您的代码的正确性、性能和风格。"
)
),
list(
role = "user",
content = list(
type = "text",
text = "请提供具体的改进建议。"
)
)
)
}
)
您的提示函数可以返回几种格式的消息:
func = function() "Hello World"
func = function() {
list(
role = "user",
content = list(type = "text", text = "您的消息")
)
}
func = function() {
list(
list(role = "user", content = list(type = "text", text = "第一条消息")),
list(role = "assistant", content = list(type = "text", text = "第二条消息"))
)
}
工作流程指导
pr_mcp_prompt(
pr,
name = "data-pipeline",
description = "构建数据处理管道的指南",
arguments = list(
list(name = "data_type", description = "要处理的数据类型", required = TRUE)
),
func = function(data_type) {
sprintf("为%s数据创建数据处理管道……", data_type)
}
)
代码生成模板
pr_mcp_prompt(
pr,
name = "create-endpoint",
description = "创建新Plumber端点的模板",
func = function() {
paste(
"生成具有以下内容的Plumber端点:",
"1. 正确的roxygen文档",
"2. 输入验证",
"3. 错误处理",
"4. 示例用法",
sep = "\n"
)
}
)
领域特定协助
pr_mcp_prompt(
pr,
name = "statistical-test",
description = "选择并实现适当的统计测试",
arguments = list(
list(name = "research_question", description = "研究问题", required = TRUE)
),
func = function(research_question) {
sprintf(
paste(
"研究问题:%s",
"",
"请帮助我:",
"1. 选择适当的统计测试",
"2. 检查假设",
"3. 在R中实现",
"4. 解释结果",
sep = "\n"
),
research_question
)
}
)
library(plumber)
library(plumber2mcp)
pr("api.R") %>%
pr_mcp(transport = "stdio") %>%
# 添加分析提示
pr_mcp_prompt(
name = "analyze",
description = "分析来自API的数据",
func = function() {
"引导我通过分析此API提供的数据。"
}
) %>%
# 添加故障排除提示
pr_mcp_prompt(
name = "troubleshoot",
description = "帮助解决API问题",
arguments = list(
list(name = "issue", description = "问题描述", required = TRUE)
),
func = function(issue) {
sprintf("我在API中遇到这个问题:%s\n\n如何解决它?", issue)
}
)
资源允许AI助手从您的R环境中读取内容,例如文档、数据描述或分析结果。
# 创建具有资源的Plumber API
pr(...) %>%
pr_mcp(transport = "stdio") %>%
# 添加提供数据集信息的资源
pr_mcp_resource(
uri = "/data/iris-summary",
func = function() {
paste(
"数据集:iris",
paste("维度:", paste(dim(iris), collapse = " x ")),
"",
capture.output(summary(iris)),
sep = "\n"
)
},
name = "I