├── .gitignore ├── docs ├── logo.png ├── favicon.ico ├── favicon-96x96.png ├── apple-touch-icon.png ├── reference │ ├── figures │ │ └── logo.png │ ├── new_client_http.html │ ├── new_client_io.html │ ├── new_mcp.html │ ├── response_file.html │ ├── response_item.html │ ├── response_text.html │ ├── response_audio.html │ ├── response_error.html │ ├── response_image.html │ ├── response_resource.html │ ├── response_video.html │ ├── JSONRPC_PARSE_ERROR.html │ ├── get_name.html │ ├── tools_list.html │ ├── roxy_tag_parse.roxy_tag_mcp.html │ ├── prompts_list.html │ ├── resources_list.html │ ├── validate_request.html │ ├── process_mcp_block.html │ ├── serve_io.html │ ├── generate_property_code.html │ ├── roxy_tag_parse.roxy_tag_type.html │ ├── initialize.html │ └── from_json.html ├── web-app-manifest-192x192.png ├── web-app-manifest-512x512.png ├── deps │ ├── font-awesome-6.5.2 │ │ └── webfonts │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-v4compatibility.ttf │ │ │ └── fa-v4compatibility.woff2 │ ├── headroom-0.11.0 │ │ ├── jQuery.headroom.min.js │ │ └── headroom.min.js │ ├── data-deps.txt │ └── bootstrap-toc-1.0.1 │ │ └── bootstrap-toc.min.js ├── pkgdown.yml ├── site.webmanifest ├── katex-auto.js ├── link.svg ├── extra.css ├── lightswitch.js ├── articles │ └── index.html ├── 404.html ├── pkgdown.js ├── authors.html └── sitemap.xml ├── pkgdown ├── mcpr.png ├── _pkgdown.yml ├── favicon │ ├── favicon.ico │ ├── favicon-96x96.png │ ├── apple-touch-icon.png │ ├── web-app-manifest-192x192.png │ ├── web-app-manifest-512x512.png │ └── site.webmanifest └── extra.css ├── man ├── figures │ └── logo.png ├── get_name.Rd ├── tools_list.Rd ├── prompts_list.Rd ├── resources_list.Rd ├── roxy_tag_parse.roxy_tag_mcp.Rd ├── JSONRPC_PARSE_ERROR.Rd ├── initialize.Rd ├── serve_io.Rd ├── validate_request.Rd ├── from_json.Rd ├── process_mcp_block.Rd ├── to_json.Rd ├── roxy_tag_parse.roxy_tag_type.Rd ├── read.Rd ├── generate_property_code.Rd ├── process_request.Rd ├── create_ellmer_type.Rd ├── process_batch.Rd ├── add_capability.Rd ├── generate_tool_code.Rd ├── create_response.Rd ├── generate_handler_code.Rd ├── mcp_roclet.Rd ├── parse_request.Rd ├── generate_mcp_server.Rd ├── create_ellmer_types.Rd ├── register_mcpr_tools.Rd ├── convert_ellmer_types_to_mcpr.Rd ├── build_param_info.Rd ├── tools_call.Rd ├── prompts_get.Rd ├── roclet_output.roclet_mcp.Rd ├── create_error.Rd ├── properties.Rd ├── resources_read.Rd ├── roclet_process.roclet_mcp.Rd ├── serve_http.Rd ├── create_ellmer_handler.Rd ├── write.Rd ├── convert_ellmer_type_to_mcpr_property.Rd ├── roxy_tag_rd.roxy_tag_mcp.Rd ├── roxy_tag_rd.roxy_tag_type.Rd ├── new_property.Rd ├── client.Rd ├── property_boolean.Rd ├── property_enum.Rd ├── schema.Rd ├── mcpr_to_ellmer_tools.Rd ├── new_resource.Rd ├── new_server.Rd ├── new_tool.Rd ├── new_prompt.Rd ├── mcpr_clients_to_ellmer_tools.Rd ├── property_array.Rd ├── property_object.Rd ├── property_string.Rd ├── property_number.Rd ├── ellmer_to_mcpr_tool.Rd └── response.Rd ├── R ├── utils.R ├── io.R ├── client.R ├── http.R ├── request.R └── response.R ├── .Rbuildignore ├── makefile ├── examples ├── calculator │ ├── client.R │ └── server.R └── ellmer │ ├── client.R │ └── server.R ├── DESCRIPTION ├── NEWS.md ├── _pkgdown.yml ├── NAMESPACE └── vignettes ├── get-started.Rmd ├── client-usage.Rmd └── client-integration.Rmd /.gitignore: -------------------------------------------------------------------------------- 1 | .claude/ 2 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /pkgdown/mcpr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/mcpr.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /pkgdown/_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://mcpr.opifex.org 2 | template: 3 | bootstrap: 5 4 | 5 | -------------------------------------------------------------------------------- /docs/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/favicon-96x96.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | generate_id <- function() { 2 | trunc(as.numeric(Sys.time()) * 1000000) # microseconds 3 | } 4 | -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/reference/figures/logo.png -------------------------------------------------------------------------------- /docs/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /docs/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/favicon/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/pkgdown/favicon/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^makefile$ 2 | ^LICENSE\.md$ 3 | ^test\.R$ 4 | ^_pkgdown\.yml$ 5 | ^docs$ 6 | ^pkgdown$ 7 | ^examples$ 8 | ^\.github$ 9 | ^\.claude$ 10 | -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devOpifex/mcpr/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | default: install 2 | 3 | document: 4 | R -s -e "devtools::document()" 5 | 6 | check: document 7 | R -s -e "devtools::check(document = FALSE)" 8 | 9 | install: check 10 | R -s -e "devtools::install()" 11 | 12 | site: document 13 | R -s -e "pkgdown::build_site()" 14 | -------------------------------------------------------------------------------- /docs/reference/new_client_http.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/new_client_io.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/new_mcp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_item.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_audio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_image.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_resource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/response_video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /man/get_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/client.R 3 | \name{get_name} 4 | \alias{get_name} 5 | \title{Get the name of a client} 6 | \usage{ 7 | get_name(x) 8 | } 9 | \arguments{ 10 | \item{x}{A client object} 11 | } 12 | \value{ 13 | The name of the client 14 | } 15 | \description{ 16 | Get the name of a client 17 | } 18 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.3 2 | pkgdown: 2.1.2 3 | pkgdown_sha: ~ 4 | articles: 5 | client-integration: client-integration.html 6 | client-usage: client-usage.html 7 | get-started: get-started.html 8 | practical-examples: practical-examples.html 9 | last_built: 2025-06-20T08:07Z 10 | urls: 11 | reference: https://mcpr.opifex.org/reference 12 | article: https://mcpr.opifex.org/articles 13 | -------------------------------------------------------------------------------- /man/tools_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tools_list} 4 | \alias{tools_list} 5 | \title{List all available tools} 6 | \usage{ 7 | tools_list(mcp) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | } 12 | \value{ 13 | A list containing all available tools 14 | } 15 | \description{ 16 | List all available tools 17 | } 18 | -------------------------------------------------------------------------------- /man/prompts_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{prompts_list} 4 | \alias{prompts_list} 5 | \title{List all available prompts} 6 | \usage{ 7 | prompts_list(mcp) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | } 12 | \value{ 13 | A list containing all available prompts 14 | } 15 | \description{ 16 | List all available prompts 17 | } 18 | -------------------------------------------------------------------------------- /man/resources_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{resources_list} 4 | \alias{resources_list} 5 | \title{List all available resources} 6 | \usage{ 7 | resources_list(mcp) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | } 12 | \value{ 13 | A list containing all available resources 14 | } 15 | \description{ 16 | List all available resources 17 | } 18 | -------------------------------------------------------------------------------- /man/roxy_tag_parse.roxy_tag_mcp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roxy_tag_parse.roxy_tag_mcp} 4 | \alias{roxy_tag_parse.roxy_tag_mcp} 5 | \title{Parse @mcp tag} 6 | \usage{ 7 | \method{roxy_tag_parse}{roxy_tag_mcp}(x) 8 | } 9 | \arguments{ 10 | \item{x}{A roxy_tag object} 11 | } 12 | \description{ 13 | Parses @mcp tags to extract tool name and description. 14 | } 15 | -------------------------------------------------------------------------------- /man/JSONRPC_PARSE_ERROR.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \docType{data} 4 | \name{JSONRPC_PARSE_ERROR} 5 | \alias{JSONRPC_PARSE_ERROR} 6 | \title{JSON-RPC 2.0 Standard Error Codes} 7 | \format{ 8 | An object of class \code{numeric} of length 1. 9 | } 10 | \usage{ 11 | JSONRPC_PARSE_ERROR 12 | } 13 | \description{ 14 | JSON-RPC 2.0 Standard Error Codes 15 | } 16 | \keyword{internal} 17 | -------------------------------------------------------------------------------- /man/initialize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{initialize} 4 | \alias{initialize} 5 | \title{Initialize the server with protocol information} 6 | \usage{ 7 | initialize(mcp) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | } 12 | \value{ 13 | A list containing protocol version, server info, and capabilities 14 | } 15 | \description{ 16 | Initialize the server with protocol information 17 | } 18 | -------------------------------------------------------------------------------- /examples/calculator/client.R: -------------------------------------------------------------------------------- 1 | devtools::load_all() 2 | 3 | client <- new_client_io( 4 | "Rscript", 5 | "/home/john/Opifex/Packages/mcpr/examples/calculator/server.R", 6 | name = "calculator", 7 | version = "1.0.0" 8 | ) 9 | 10 | #client <- new_client_http( 11 | # "http://localhost:3000/mcp", 12 | # name = "calculator", 13 | # version = "1.0.0" 14 | #) 15 | 16 | res <- initialize(client) 17 | 18 | print(res) 19 | 20 | res <- tools_list(client) 21 | 22 | print(res) 23 | -------------------------------------------------------------------------------- /man/serve_io.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/io.R 3 | \name{serve_io} 4 | \alias{serve_io} 5 | \title{Serve an MCP server using stdin/stdout} 6 | \usage{ 7 | serve_io(mcp) 8 | } 9 | \arguments{ 10 | \item{mcp}{An MCP server object created with new_server()} 11 | } 12 | \value{ 13 | Nothing, runs indefinitely in normal mode, or the response in test mode 14 | } 15 | \description{ 16 | Serve an MCP server using stdin/stdout 17 | } 18 | -------------------------------------------------------------------------------- /man/validate_request.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{validate_request} 4 | \alias{validate_request} 5 | \title{Validate a JSON-RPC 2.0 request} 6 | \usage{ 7 | validate_request(request) 8 | } 9 | \arguments{ 10 | \item{request}{Parsed request object} 11 | } 12 | \value{ 13 | NULL if valid, error response if invalid 14 | } 15 | \description{ 16 | Validate a JSON-RPC 2.0 request 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/from_json.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{from_json} 4 | \alias{from_json} 5 | \title{Parse JSON to an R object} 6 | \usage{ 7 | from_json(json, ...) 8 | } 9 | \arguments{ 10 | \item{json}{JSON string to parse} 11 | 12 | \item{...}{Additional arguments passed to yyjsonr::read_json_str} 13 | } 14 | \value{ 15 | R object 16 | } 17 | \description{ 18 | Parse JSON to an R object 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/process_mcp_block.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{process_mcp_block} 4 | \alias{process_mcp_block} 5 | \title{Process a single block with @mcp tag} 6 | \usage{ 7 | process_mcp_block(block) 8 | } 9 | \arguments{ 10 | \item{block}{A roxy_block object} 11 | } 12 | \value{ 13 | A list with tool information or NULL 14 | } 15 | \description{ 16 | Process a single block with @mcp tag 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/to_json.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{to_json} 4 | \alias{to_json} 5 | \title{Convert an R object to JSON} 6 | \usage{ 7 | to_json(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{R object to convert to JSON} 11 | 12 | \item{...}{Additional arguments passed to yyjsonr::write_json_str} 13 | } 14 | \value{ 15 | JSON string 16 | } 17 | \description{ 18 | Convert an R object to JSON 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/roxy_tag_parse.roxy_tag_type.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roxy_tag_parse.roxy_tag_type} 4 | \alias{roxy_tag_parse.roxy_tag_type} 5 | \title{Parse @type tag} 6 | \usage{ 7 | \method{roxy_tag_parse}{roxy_tag_type}(x) 8 | } 9 | \arguments{ 10 | \item{x}{A roxy_tag object} 11 | } 12 | \description{ 13 | Parses @type tags to extract parameter type information. 14 | Format: @type param_name type enum_values 15 | } 16 | -------------------------------------------------------------------------------- /man/read.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/request.R 3 | \name{read} 4 | \alias{read} 5 | \title{Read a JSON-RPC response from a client provider} 6 | \usage{ 7 | read(x, timeout = 60 * 1000) 8 | } 9 | \arguments{ 10 | \item{x}{A client provider} 11 | 12 | \item{timeout}{Timeout in milliseconds for reading the response} 13 | } 14 | \value{ 15 | The response 16 | } 17 | \description{ 18 | Read a JSON-RPC response from a client provider 19 | } 20 | -------------------------------------------------------------------------------- /man/generate_property_code.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{generate_property_code} 4 | \alias{generate_property_code} 5 | \title{Generate property code for a parameter} 6 | \usage{ 7 | generate_property_code(param) 8 | } 9 | \arguments{ 10 | \item{param}{Parameter information} 11 | } 12 | \value{ 13 | Character string with property code 14 | } 15 | \description{ 16 | Generate property code for a parameter 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/process_request.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{process_request} 4 | \alias{process_request} 5 | \title{Process a JSON-RPC 2.0 request} 6 | \usage{ 7 | process_request(request, mcp) 8 | } 9 | \arguments{ 10 | \item{request}{Parsed request object} 11 | 12 | \item{mcp}{MCP server object} 13 | } 14 | \value{ 15 | Response object or NULL for notifications 16 | } 17 | \description{ 18 | Process a JSON-RPC 2.0 request 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /docs/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /man/create_ellmer_type.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{create_ellmer_type} 4 | \alias{create_ellmer_type} 5 | \title{Create an ellmer type function for a specific MCP property} 6 | \usage{ 7 | create_ellmer_type(prop) 8 | } 9 | \arguments{ 10 | \item{prop}{The MCP property} 11 | } 12 | \value{ 13 | An ellmer type function call 14 | } 15 | \description{ 16 | Create an ellmer type function for a specific MCP property 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/process_batch.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{process_batch} 4 | \alias{process_batch} 5 | \title{Process batch JSON-RPC 2.0 requests} 6 | \usage{ 7 | process_batch(batch_requests, mcp) 8 | } 9 | \arguments{ 10 | \item{batch_requests}{List of request objects} 11 | 12 | \item{mcp}{MCP server object} 13 | } 14 | \value{ 15 | List of response objects 16 | } 17 | \description{ 18 | Process batch JSON-RPC 2.0 requests 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/add_capability.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcp.R 3 | \name{add_capability} 4 | \alias{add_capability} 5 | \title{Add a capability to an MCP object} 6 | \usage{ 7 | add_capability(mcp, capability) 8 | } 9 | \arguments{ 10 | \item{mcp}{An MCP server object} 11 | 12 | \item{capability}{A tool, resource, or prompt capability object} 13 | } 14 | \value{ 15 | The MCP object with the capability added 16 | } 17 | \description{ 18 | Add a capability to an MCP object 19 | } 20 | -------------------------------------------------------------------------------- /man/generate_tool_code.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{generate_tool_code} 4 | \alias{generate_tool_code} 5 | \title{Generate R code for a single tool} 6 | \usage{ 7 | generate_tool_code(tool, index) 8 | } 9 | \arguments{ 10 | \item{tool}{Tool information list} 11 | 12 | \item{index}{Tool index for naming} 13 | } 14 | \value{ 15 | Character vector of R code lines 16 | } 17 | \description{ 18 | Generate R code for a single tool 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/create_response.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{create_response} 4 | \alias{create_response} 5 | \title{Create a JSON-RPC 2.0 success response} 6 | \usage{ 7 | create_response(result, id = NULL) 8 | } 9 | \arguments{ 10 | \item{result}{Result data} 11 | 12 | \item{id}{Request identifier} 13 | } 14 | \value{ 15 | A structured JSON-RPC 2.0 success response 16 | } 17 | \description{ 18 | Create a JSON-RPC 2.0 success response 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/generate_handler_code.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{generate_handler_code} 4 | \alias{generate_handler_code} 5 | \title{Generate handler code that calls the original function} 6 | \usage{ 7 | generate_handler_code(tool) 8 | } 9 | \arguments{ 10 | \item{tool}{Tool information} 11 | } 12 | \value{ 13 | Character vector of handler code lines 14 | } 15 | \description{ 16 | Generate handler code that calls the original function 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/mcp_roclet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{mcp_roclet} 4 | \alias{mcp_roclet} 5 | \title{MCP Roclet for Generating MCP Servers} 6 | \usage{ 7 | mcp_roclet() 8 | } 9 | \description{ 10 | This roclet automatically generates MCP (Model Context Protocol) servers 11 | from R functions annotated with @mcp tags. 12 | } 13 | \examples{ 14 | \dontrun{ 15 | # Use the roclet in roxygenise 16 | roxygen2::roxygenise(roclets = c("rd", "mcpr::mcp_roclet")) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /man/parse_request.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{parse_request} 4 | \alias{parse_request} 5 | \title{Parse and process a JSON-RPC 2.0 request} 6 | \usage{ 7 | parse_request(json_text, mcp) 8 | } 9 | \arguments{ 10 | \item{json_text}{JSON request text} 11 | 12 | \item{mcp}{MCP server object} 13 | } 14 | \value{ 15 | JSON response text or NULL for notifications 16 | } 17 | \description{ 18 | Parse and process a JSON-RPC 2.0 request 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/generate_mcp_server.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{generate_mcp_server} 4 | \alias{generate_mcp_server} 5 | \title{Generate MCP server R code} 6 | \usage{ 7 | generate_mcp_server(tools, base_path) 8 | } 9 | \arguments{ 10 | \item{tools}{List of tool information} 11 | 12 | \item{base_path}{Base path for the package} 13 | } 14 | \value{ 15 | Character vector of R code lines 16 | } 17 | \description{ 18 | Generate MCP server R code 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /pkgdown/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /man/create_ellmer_types.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{create_ellmer_types} 4 | \alias{create_ellmer_types} 5 | \title{Create ellmer type functions from MCP schema properties} 6 | \usage{ 7 | create_ellmer_types(schema) 8 | } 9 | \arguments{ 10 | \item{schema}{The MCP schema object} 11 | } 12 | \value{ 13 | A list of ellmer type function calls for each property 14 | } 15 | \description{ 16 | Create ellmer type functions from MCP schema properties 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/register_mcpr_tools.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{register_mcpr_tools} 4 | \alias{register_mcpr_tools} 5 | \title{Register MCPR tools with an ellmer chat} 6 | \usage{ 7 | register_mcpr_tools(chat, client) 8 | } 9 | \arguments{ 10 | \item{chat}{An ellmer chat object} 11 | 12 | \item{client}{An mcpr client object} 13 | } 14 | \value{ 15 | The chat object (invisibly) 16 | } 17 | \description{ 18 | This function registers tools from an MCPR client with an ellmer chat instance. 19 | } 20 | -------------------------------------------------------------------------------- /man/convert_ellmer_types_to_mcpr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ellmer-to-mcpr.R 3 | \name{convert_ellmer_types_to_mcpr} 4 | \alias{convert_ellmer_types_to_mcpr} 5 | \title{Convert ellmer TypeObject to mcpr schema} 6 | \usage{ 7 | convert_ellmer_types_to_mcpr(type_object) 8 | } 9 | \arguments{ 10 | \item{type_object}{An ellmer TypeObject containing the function arguments} 11 | } 12 | \value{ 13 | An mcpr schema object 14 | } 15 | \description{ 16 | Convert ellmer TypeObject to mcpr schema 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/build_param_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{build_param_info} 4 | \alias{build_param_info} 5 | \title{Build parameter information from @param and @type tags} 6 | \usage{ 7 | build_param_info(param_tags, type_tags = list()) 8 | } 9 | \arguments{ 10 | \item{param_tags}{List of @param tags} 11 | 12 | \item{type_tags}{List of @type tags} 13 | } 14 | \value{ 15 | List of parameter information 16 | } 17 | \description{ 18 | Build parameter information from @param and @type tags 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/tools_call.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tools_call} 4 | \alias{tools_call} 5 | \title{Call a tool with the given parameters} 6 | \usage{ 7 | tools_call(mcp, params, id = NULL) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | 12 | \item{params}{Parameters for the tool call} 13 | 14 | \item{id}{Optional request ID for response tracking} 15 | } 16 | \value{ 17 | A response object with the tool call results or an error 18 | } 19 | \description{ 20 | Call a tool with the given parameters 21 | } 22 | -------------------------------------------------------------------------------- /man/prompts_get.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{prompts_get} 4 | \alias{prompts_get} 5 | \title{Get a prompt with the given parameters} 6 | \usage{ 7 | prompts_get(mcp, params, id = NULL) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | 12 | \item{params}{Parameters for the prompt request} 13 | 14 | \item{id}{Optional request ID for response tracking} 15 | } 16 | \value{ 17 | A response object with the prompt results or an error 18 | } 19 | \description{ 20 | Get a prompt with the given parameters 21 | } 22 | -------------------------------------------------------------------------------- /man/roclet_output.roclet_mcp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roclet_output.roclet_mcp} 4 | \alias{roclet_output.roclet_mcp} 5 | \title{Generate MCP server output} 6 | \usage{ 7 | \method{roclet_output}{roclet_mcp}(x, results, base_path, ...) 8 | } 9 | \arguments{ 10 | \item{x}{MCP roclet object} 11 | 12 | \item{results}{List of processed tools} 13 | 14 | \item{base_path}{Base path} 15 | 16 | \item{...}{Additional arguments} 17 | } 18 | \value{ 19 | NULL (invisible) 20 | } 21 | \description{ 22 | Generate MCP server output 23 | } 24 | -------------------------------------------------------------------------------- /man/create_error.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/jsonrpc.R 3 | \name{create_error} 4 | \alias{create_error} 5 | \title{Create a JSON-RPC 2.0 error response} 6 | \usage{ 7 | create_error(code, message, data = NULL, id = NULL) 8 | } 9 | \arguments{ 10 | \item{code}{Error code} 11 | 12 | \item{message}{Error message} 13 | 14 | \item{data}{Optional error data} 15 | 16 | \item{id}{Request identifier} 17 | } 18 | \value{ 19 | A structured JSON-RPC 2.0 error response 20 | } 21 | \description{ 22 | Create a JSON-RPC 2.0 error response 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/properties.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{properties} 4 | \alias{properties} 5 | \title{Create a new properties list} 6 | \usage{ 7 | properties(...) 8 | } 9 | \arguments{ 10 | \item{...}{Property objects} 11 | } 12 | \value{ 13 | A list of property objects 14 | } 15 | \description{ 16 | Create a new properties list 17 | } 18 | \examples{ 19 | properties <- properties( 20 | property_string("Name", "The name of the user", required = TRUE), 21 | property_number("Age", "The age of the user in years", minimum = 0) 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /man/resources_read.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{resources_read} 4 | \alias{resources_read} 5 | \title{Read a resource with the given parameters} 6 | \usage{ 7 | resources_read(mcp, params, id = NULL) 8 | } 9 | \arguments{ 10 | \item{mcp}{A server object} 11 | 12 | \item{params}{Parameters for the resource read} 13 | 14 | \item{id}{Optional request ID for response tracking} 15 | } 16 | \value{ 17 | A response object with the resource read results or an error 18 | } 19 | \description{ 20 | Read a resource with the given parameters 21 | } 22 | -------------------------------------------------------------------------------- /man/roclet_process.roclet_mcp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roclet_process.roclet_mcp} 4 | \alias{roclet_process.roclet_mcp} 5 | \title{Process blocks for MCP roclet} 6 | \usage{ 7 | \method{roclet_process}{roclet_mcp}(x, blocks, env, base_path) 8 | } 9 | \arguments{ 10 | \item{x}{MCP roclet object} 11 | 12 | \item{blocks}{List of roxy_block objects} 13 | 14 | \item{env}{Environment} 15 | 16 | \item{base_path}{Base path} 17 | } 18 | \value{ 19 | List of processed MCP tools 20 | } 21 | \description{ 22 | Process blocks for MCP roclet 23 | } 24 | -------------------------------------------------------------------------------- /man/serve_http.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/http.R 3 | \name{serve_http} 4 | \alias{serve_http} 5 | \title{Serve an MCP server over HTTP using ambiorix} 6 | \usage{ 7 | serve_http(mcp, port = Sys.getenv("SHINY_PORT", 3000), path = "/mcp") 8 | } 9 | \arguments{ 10 | \item{mcp}{An MCP server object} 11 | 12 | \item{port}{Port to listen on, defaults to 3000} 13 | 14 | \item{path}{Path to serve the MCP endpoint, defaults to "/mcp"} 15 | } 16 | \value{ 17 | Invisible, runs indefinitely 18 | } 19 | \description{ 20 | Serve an MCP server over HTTP using ambiorix 21 | } 22 | -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/jQuery.headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(a){a&&(a.fn.headroom=function(b){return this.each(function(){var c=a(this),d=c.data("headroom"),e="object"==typeof b&&b;e=a.extend(!0,{},Headroom.options,e),d||(d=new Headroom(this,e),d.init(),c.data("headroom",d)),"string"==typeof b&&(d[b](),"destroy"===b&&c.removeData("headroom"))})},a("[data-headroom]").each(function(){var b=a(this);b.headroom(b.data())}))}(window.Zepto||window.jQuery); -------------------------------------------------------------------------------- /man/create_ellmer_handler.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{create_ellmer_handler} 4 | \alias{create_ellmer_handler} 5 | \title{Create an ellmer handler function for an MCP tool} 6 | \usage{ 7 | create_ellmer_handler(client, tool_name, input_schema) 8 | } 9 | \arguments{ 10 | \item{client}{The mcpr client} 11 | 12 | \item{tool_name}{The name of the MCP tool} 13 | 14 | \item{input_schema}{The tool's input schema} 15 | } 16 | \value{ 17 | A function that can be used as an ellmer tool handler 18 | } 19 | \description{ 20 | Create an ellmer handler function for an MCP tool 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /docs/katex-auto.js: -------------------------------------------------------------------------------- 1 | // https://github.com/jgm/pandoc/blob/29fa97ab96b8e2d62d48326e1b949a71dc41f47a/src/Text/Pandoc/Writers/HTML.hs#L332-L345 2 | document.addEventListener("DOMContentLoaded", function () { 3 | var mathElements = document.getElementsByClassName("math"); 4 | var macros = []; 5 | for (var i = 0; i < mathElements.length; i++) { 6 | var texText = mathElements[i].firstChild; 7 | if (mathElements[i].tagName == "SPAN") { 8 | katex.render(texText.data, mathElements[i], { 9 | displayMode: mathElements[i].classList.contains("display"), 10 | throwOnError: false, 11 | macros: macros, 12 | fleqn: false 13 | }); 14 | }}}); 15 | -------------------------------------------------------------------------------- /man/write.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/request.R 3 | \name{write} 4 | \alias{write} 5 | \title{Write a JSON-RPC request to a client provider} 6 | \usage{ 7 | write(x, method, params = NULL, id = generate_id(), timeout = 5000) 8 | } 9 | \arguments{ 10 | \item{x}{A client provider} 11 | 12 | \item{method}{The method to call} 13 | 14 | \item{params}{The parameters to pass to the method} 15 | 16 | \item{id}{The id of the request} 17 | 18 | \item{timeout}{Timeout in milliseconds for reading the response} 19 | } 20 | \value{ 21 | The client provider 22 | } 23 | \description{ 24 | Write a JSON-RPC request to a client provider 25 | } 26 | -------------------------------------------------------------------------------- /man/convert_ellmer_type_to_mcpr_property.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ellmer-to-mcpr.R 3 | \name{convert_ellmer_type_to_mcpr_property} 4 | \alias{convert_ellmer_type_to_mcpr_property} 5 | \title{Convert a single ellmer type to an mcpr property} 6 | \usage{ 7 | convert_ellmer_type_to_mcpr_property(ellmer_type, prop_name) 8 | } 9 | \arguments{ 10 | \item{ellmer_type}{An ellmer Type object (TypeBasic, TypeArray, etc.)} 11 | 12 | \item{prop_name}{The name of the property (for better error messages)} 13 | } 14 | \value{ 15 | An mcpr property object 16 | } 17 | \description{ 18 | Convert a single ellmer type to an mcpr property 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/roxy_tag_rd.roxy_tag_mcp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roxy_tag_rd.roxy_tag_mcp} 4 | \alias{roxy_tag_rd.roxy_tag_mcp} 5 | \title{Roxygen2 tag for @mcp 6 | This function is called by Roxygen2 to generate documentation for the @mcp tag} 7 | \usage{ 8 | \method{roxy_tag_rd}{roxy_tag_mcp}(x, base_path, env) 9 | } 10 | \arguments{ 11 | \item{x}{Roxygen2 tag object} 12 | 13 | \item{base_path}{Base path for the package} 14 | 15 | \item{env}{Environment} 16 | } 17 | \value{ 18 | NULL (invisible) 19 | } 20 | \description{ 21 | Roxygen2 tag for @mcp 22 | This function is called by Roxygen2 to generate documentation for the @mcp tag 23 | } 24 | -------------------------------------------------------------------------------- /man/roxy_tag_rd.roxy_tag_type.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roxy_tag_rd.roxy_tag_type} 4 | \alias{roxy_tag_rd.roxy_tag_type} 5 | \title{Roxygen2 tag handler for @type 6 | This function is called by Roxygen2 to generate documentation for the @type} 7 | \usage{ 8 | \method{roxy_tag_rd}{roxy_tag_type}(x, base_path, env) 9 | } 10 | \arguments{ 11 | \item{x}{Roxygen2 tag object} 12 | 13 | \item{base_path}{Base path for the package} 14 | 15 | \item{env}{Environment} 16 | } 17 | \value{ 18 | NULL (invisible) 19 | } 20 | \description{ 21 | Roxygen2 tag handler for @type 22 | This function is called by Roxygen2 to generate documentation for the @type 23 | } 24 | -------------------------------------------------------------------------------- /man/new_property.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{new_property} 4 | \alias{new_property} 5 | \title{Create a new property} 6 | \usage{ 7 | new_property(type, title, description, required = FALSE, ...) 8 | } 9 | \arguments{ 10 | \item{type}{Type of the property} 11 | 12 | \item{title}{Short title for the property} 13 | 14 | \item{description}{Longer description of the property} 15 | 16 | \item{required}{Whether the property is required} 17 | 18 | \item{...}{Additional attributes for the property} 19 | } 20 | \value{ 21 | A property object with the specified attributes 22 | } 23 | \description{ 24 | Create a new property 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/client.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/client.R 3 | \name{client} 4 | \alias{client} 5 | \alias{new_client_io} 6 | \alias{new_client_http} 7 | \title{Create a new mcp IO} 8 | \usage{ 9 | new_client_io(command, args = character(), name, version = "1.0.0") 10 | 11 | new_client_http(endpoint, name, version = "1.0.0") 12 | } 13 | \arguments{ 14 | \item{command}{The command to run} 15 | 16 | \item{args}{Arguments to pass to the command} 17 | 18 | \item{name}{The name of the client} 19 | 20 | \item{version}{The version of the client} 21 | 22 | \item{endpoint}{The endpoint to connect to} 23 | } 24 | \value{ 25 | A new mcp client 26 | } 27 | \description{ 28 | Create a new mcp IO 29 | } 30 | -------------------------------------------------------------------------------- /man/property_boolean.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_boolean} 4 | \alias{property_boolean} 5 | \title{Create a boolean property definition} 6 | \usage{ 7 | property_boolean(title, description, required = FALSE) 8 | } 9 | \arguments{ 10 | \item{title}{Short title for the property} 11 | 12 | \item{description}{Longer description of the property} 13 | 14 | \item{required}{Whether the property is required} 15 | } 16 | \value{ 17 | A boolean property object 18 | } 19 | \description{ 20 | Create a boolean property definition 21 | } 22 | \examples{ 23 | active_prop <- property_boolean( 24 | "Active status", 25 | "Whether the user account is active", 26 | required = TRUE 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /man/property_enum.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_enum} 4 | \alias{property_enum} 5 | \title{Create an enum property with predefined values} 6 | \usage{ 7 | property_enum(title, description, values, required = FALSE) 8 | } 9 | \arguments{ 10 | \item{title}{Short title for the property} 11 | 12 | \item{description}{Longer description of the property} 13 | 14 | \item{values}{Character vector of allowed values} 15 | 16 | \item{required}{Whether the property is required} 17 | } 18 | \value{ 19 | An enum property object 20 | } 21 | \description{ 22 | Create an enum property with predefined values 23 | } 24 | \examples{ 25 | status_prop <- property_enum( 26 | "Status", 27 | "User account status", 28 | values = c("active", "pending", "suspended"), 29 | required = TRUE 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /examples/ellmer/client.R: -------------------------------------------------------------------------------- 1 | devtools::load_all() 2 | 3 | # Create an MCPR client connected to the calculator server 4 | client <- new_client_io( 5 | "Rscript", 6 | "/home/john/Opifex/Packages/mcpr/examples/ellmer/server.R", 7 | name = "calculator", 8 | version = "1.0.0" 9 | ) 10 | 11 | Sys.sleep(1) 12 | 13 | res <- tools_call( 14 | client, 15 | params = list( 16 | name = "math_calculator", 17 | arguments = list( 18 | operation = "add", 19 | a = 5, 20 | b = 3 21 | ) 22 | ), 23 | id = 42 24 | ) 25 | 26 | # Create a Claude chat session with ellmer 27 | chat <- ellmer::chat_anthropic() 28 | 29 | ## Convert MCPR tools to ellmer tools and register them with the chat 30 | chat <- register_mcpr_tools(chat, client) 31 | 32 | ## Try using the tools in a chat 33 | chat$chat( 34 | "What is the current time in the US/Eastern timezone?", 35 | ) 36 | -------------------------------------------------------------------------------- /man/schema.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{schema} 4 | \alias{schema} 5 | \title{Create a new input schema} 6 | \usage{ 7 | schema(properties, type = "object", additional_properties = FALSE) 8 | } 9 | \arguments{ 10 | \item{properties}{List of property definitions created with properties()} 11 | 12 | \item{type}{Type of the schema (default: "object")} 13 | 14 | \item{additional_properties}{Whether additional properties are allowed} 15 | } 16 | \value{ 17 | A list representing a JSON Schema object 18 | } 19 | \description{ 20 | Create a new input schema 21 | } 22 | \examples{ 23 | schema <- schema( 24 | properties = properties( 25 | name = property_string("User name", "The name of the user", required = TRUE), 26 | age = property_number("User age", "The age of the user in years", minimum = 0) 27 | ) 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /docs/deps/data-deps.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /man/mcpr_to_ellmer_tools.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{mcpr_to_ellmer_tools} 4 | \alias{mcpr_to_ellmer_tools} 5 | \title{Convert MCPR tools to ellmer tools} 6 | \usage{ 7 | mcpr_to_ellmer_tools(client) 8 | } 9 | \arguments{ 10 | \item{client}{An mcpr client object} 11 | } 12 | \value{ 13 | A list of ellmer-compatible tool functions 14 | } 15 | \description{ 16 | This function converts tools from an MCPR client to a format compatible 17 | with the ellmer package. It retrieves all available tools from the client 18 | and creates wrapper functions that call these tools through the MCPR protocol. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # Create an MCPR client 23 | client <- new_client_io("path/to/server") 24 | 25 | # Convert its tools to ellmer format 26 | ellmer_tools <- mcpr_to_ellmer_tools(client) 27 | 28 | # Use with ellmer 29 | chat <- ellmer::chat_claude() 30 | chat$set_tools(ellmer_tools) 31 | } 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /man/new_resource.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcp.R 3 | \name{new_resource} 4 | \alias{new_resource} 5 | \title{Create a new resource} 6 | \usage{ 7 | new_resource(name, description, uri, mime_type = NULL, handler) 8 | } 9 | \arguments{ 10 | \item{name}{Name of the resource} 11 | 12 | \item{description}{Description of the resource} 13 | 14 | \item{uri}{URI of the resource} 15 | 16 | \item{mime_type}{MIME type of the resource (optional)} 17 | 18 | \item{handler}{Function to handle the resource request} 19 | } 20 | \value{ 21 | A new resource capability 22 | } 23 | \description{ 24 | Create a new resource 25 | } 26 | \examples{ 27 | resource <- new_resource( 28 | name = "My Resource", 29 | description = "This is a description", 30 | uri = "https://example.com/resource", 31 | mime_type = "text/plain", 32 | handler = function(params) { 33 | # Process the resource request 34 | return(list(content = "Resource content")) 35 | } 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /man/new_server.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcp.R 3 | \name{new_server} 4 | \alias{new_server} 5 | \alias{new_mcp} 6 | \title{Create a new MCP object} 7 | \usage{ 8 | new_server( 9 | name, 10 | description, 11 | version, 12 | tools = list(), 13 | resources = list(), 14 | prompts = list() 15 | ) 16 | 17 | new_mcp(...) 18 | } 19 | \arguments{ 20 | \item{name}{Name of the MCP server} 21 | 22 | \item{description}{Description of the MCP server} 23 | 24 | \item{version}{Version of the MCP server} 25 | 26 | \item{tools}{List of tools (optional)} 27 | 28 | \item{resources}{List of resources (optional)} 29 | 30 | \item{prompts}{List of prompts (optional)} 31 | 32 | \item{...}{Forwarded to \code{\link[=new_server]{new_server()}}} 33 | } 34 | \value{ 35 | A new MCP object 36 | } 37 | \description{ 38 | Create a new MCP object 39 | } 40 | \examples{ 41 | mcp <- new_server( 42 | name = "My MCP", 43 | description = "This is a description", 44 | version = "1.0.0" 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /man/new_tool.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcp.R 3 | \name{new_tool} 4 | \alias{new_tool} 5 | \title{Create a new tool} 6 | \usage{ 7 | new_tool(name, description, input_schema, handler) 8 | } 9 | \arguments{ 10 | \item{name}{Name of the tool} 11 | 12 | \item{description}{Description of the tool} 13 | 14 | \item{input_schema}{Input schema for the tool (must be a schema object)} 15 | 16 | \item{handler}{Function to handle the tool execution} 17 | } 18 | \value{ 19 | A new tool capability 20 | } 21 | \description{ 22 | Create a new tool 23 | } 24 | \examples{ 25 | tool <- new_tool( 26 | name = "My Tool", 27 | description = "This is a description", 28 | input_schema = schema( 29 | properties = list( 30 | input1 = property_string("Input 1", "Description of input 1"), 31 | input2 = property_number("Input 2", "Description of input 2") 32 | ) 33 | ), 34 | handler = function(input) { 35 | # Process the input here 36 | return(input) 37 | } 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /R/io.R: -------------------------------------------------------------------------------- 1 | #' Serve an MCP server using stdin/stdout 2 | #' 3 | #' @param mcp An MCP server object created with new_server() 4 | #' @type mcp object 5 | #' 6 | #' @return Nothing, runs indefinitely in normal mode, or the response in test mode 7 | #' @mcp start_mcp_server_io Start an MCP server using stdin/stdout transport 8 | #' @export 9 | serve_io <- function( 10 | mcp 11 | ) { 12 | # Validate MCP object 13 | if (missing(mcp)) { 14 | stop("An MCP server object is required") 15 | } 16 | 17 | if (!inherits(mcp, "server")) { 18 | stop("mcp must be an MCP server object") 19 | } 20 | 21 | # Main request-response loop 22 | while (TRUE) { 23 | # Read a line from input connection 24 | line <- readLines("stdin", n = 1, warn = FALSE) 25 | 26 | # Exit on EOF (Ctrl+D or end of file) 27 | if (length(line) == 0) break 28 | 29 | # Process the request through JSON-RPC 30 | response <- parse_request(line, mcp) 31 | 32 | if (!length(response)) { 33 | next 34 | } 35 | 36 | send(response, stdout()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /man/new_prompt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcp.R 3 | \name{new_prompt} 4 | \alias{new_prompt} 5 | \title{Create a new prompt} 6 | \usage{ 7 | new_prompt(name, description, arguments = list(), handler) 8 | } 9 | \arguments{ 10 | \item{name}{Name of the prompt} 11 | 12 | \item{description}{Description of the prompt} 13 | 14 | \item{arguments}{List of arguments for the prompt} 15 | 16 | \item{handler}{Function to handle the prompt execution} 17 | } 18 | \value{ 19 | A new prompt capability 20 | } 21 | \description{ 22 | Create a new prompt 23 | } 24 | \examples{ 25 | prompt <- new_prompt( 26 | name = "My Prompt", 27 | description = "This is a description", 28 | arguments = list( 29 | input1 = list( 30 | type = "string", 31 | description = "Input 1" 32 | ), 33 | input2 = list( 34 | type = "number", 35 | description = "Input 2" 36 | ) 37 | ), 38 | handler = function(params) { 39 | # Process the prompt request 40 | return(list(text = "Generated text from prompt")) 41 | } 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /man/mcpr_clients_to_ellmer_tools.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mcpr-to-ellmer.R 3 | \name{mcpr_clients_to_ellmer_tools} 4 | \alias{mcpr_clients_to_ellmer_tools} 5 | \title{Convert multiple MCPR clients to ellmer tools} 6 | \usage{ 7 | mcpr_clients_to_ellmer_tools(...) 8 | } 9 | \arguments{ 10 | \item{...}{One or more mcpr client objects} 11 | } 12 | \value{ 13 | A list of ellmer-compatible tool functions from all clients 14 | } 15 | \description{ 16 | This function converts tools from multiple MCPR clients to a format compatible 17 | with the ellmer package. It's useful when you want to combine tools from 18 | multiple MCP servers into a single ellmer session. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # Create multiple MCPR clients 23 | client1 <- new_client_io("path/to/server1") 24 | client2 <- new_client_io("path/to/server2") 25 | 26 | # Convert all tools 27 | ellmer_tools <- mcpr_clients_to_ellmer_tools(client1, client2) 28 | 29 | # Use with ellmer 30 | chat <- ellmer::chat_claude() 31 | chat$set_tools(ellmer_tools) 32 | } 33 | } 34 | \keyword{internal} 35 | -------------------------------------------------------------------------------- /man/property_array.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_array} 4 | \alias{property_array} 5 | \title{Create an array property definition} 6 | \usage{ 7 | property_array( 8 | title, 9 | description, 10 | items, 11 | required = FALSE, 12 | min_items = NULL, 13 | max_items = NULL, 14 | unique_items = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{title}{Short title for the property} 19 | 20 | \item{description}{Longer description of the property} 21 | 22 | \item{items}{Schema for the items in the array} 23 | 24 | \item{required}{Whether the property is required} 25 | 26 | \item{min_items}{Optional minimum number of items} 27 | 28 | \item{max_items}{Optional maximum number of items} 29 | 30 | \item{unique_items}{Logical indicating if items must be unique} 31 | } 32 | \value{ 33 | An array property object 34 | } 35 | \description{ 36 | Create an array property definition 37 | } 38 | \examples{ 39 | tags_prop <- property_array( 40 | "Tags", 41 | "List of tags for the user", 42 | items = property_string("Tag", "A user tag"), 43 | unique_items = TRUE 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /man/property_object.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_object} 4 | \alias{property_object} 5 | \title{Create an object property definition} 6 | \usage{ 7 | property_object( 8 | title, 9 | description, 10 | properties, 11 | required = FALSE, 12 | additional_properties = FALSE 13 | ) 14 | } 15 | \arguments{ 16 | \item{title}{Short title for the property} 17 | 18 | \item{description}{Longer description of the property} 19 | 20 | \item{properties}{List of property definitions for this object} 21 | 22 | \item{required}{Whether the property is required} 23 | 24 | \item{additional_properties}{Logical indicating if additional properties are allowed} 25 | } 26 | \value{ 27 | An object property object 28 | } 29 | \description{ 30 | Create an object property definition 31 | } 32 | \examples{ 33 | address_prop <- property_object( 34 | "Address", 35 | "User's address information", 36 | properties = list( 37 | street = property_string("Street", "Street address", required = TRUE), 38 | city = property_string("City", "City name", required = TRUE), 39 | country = property_string("Country", "Country name") 40 | ) 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /man/property_string.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_string} 4 | \alias{property_string} 5 | \title{Create a string property definition} 6 | \usage{ 7 | property_string( 8 | title, 9 | description, 10 | required = FALSE, 11 | enum = NULL, 12 | pattern = NULL, 13 | min_length = NULL, 14 | max_length = NULL, 15 | format = NULL 16 | ) 17 | } 18 | \arguments{ 19 | \item{title}{Short title for the property} 20 | 21 | \item{description}{Longer description of the property} 22 | 23 | \item{required}{Whether the property is required} 24 | 25 | \item{enum}{Optional character vector of allowed values} 26 | 27 | \item{pattern}{Optional regex pattern the string must match} 28 | 29 | \item{min_length}{Optional minimum length} 30 | 31 | \item{max_length}{Optional maximum length} 32 | 33 | \item{format}{Optional format constraint} 34 | } 35 | \value{ 36 | A string property object 37 | } 38 | \description{ 39 | Create a string property definition 40 | } 41 | \examples{ 42 | name_prop <- property_string( 43 | "User name", 44 | "The name of the user", 45 | required = TRUE, 46 | min_length = 2, 47 | max_length = 50 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: mcpr 2 | Title: Model Context Protocol for R 3 | Version: 0.0.2.9000 4 | Authors@R: 5 | c( 6 | person(given = "John", 7 | family = "Coene", 8 | role = c("aut", "cre"), 9 | email = "jcoenep@gmail.com"), 10 | person(family = "Opifex", 11 | role = c("cph", "fnd"), 12 | email = "john@opifex.org") 13 | ) 14 | Description: Create, run, and connect to Model Context Protocol (MCP) servers, and clients in R. The package 15 | provides a framework for implementing MCP-compatible servers with tools, 16 | resources, and prompts capabilities, as well as client functionality to interact with 17 | MCP servers. It includes a JSON-RPC 2.0 implementation for communication between 18 | clients and servers. 19 | License: GPL (>= 2) 20 | Depends: R (>= 4.1.0) 21 | Encoding: UTF-8 22 | Roxygen: list(markdown = TRUE, roclets = c("collate", "rd", "namespace", "mcpr::mcp_roclet")) 23 | RoxygenNote: 7.3.2 24 | Imports: 25 | yyjsonr 26 | Suggests: 27 | ambiorix, 28 | processx, 29 | knitr, 30 | rmarkdown, 31 | httr2, 32 | ellmer, 33 | roxygen2 34 | URL: https://mcpr.opifex.org/, https://github.com/devOpifex/mcpr 35 | VignetteBuilder: knitr 36 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # mcpr 0.0.2 2 | 3 | - Added support for `ellmer::tool` 4 | - Added MCP roclet for automatic server generation: 5 | - New `@mcp` tag for marking functions as MCP tools 6 | - New `@type` tag for specifying parameter types (string, number, boolean, array, object, enum) 7 | - `mcp_roclet()` function integrates with roxygen2 to generate complete MCP servers 8 | - Automatically creates `inst/mcp_server.R` with tool definitions and handlers 9 | - Supports all standard JSON Schema types and enum values 10 | 11 | # mcpr 0.0.1 12 | 13 | ## Major Changes 14 | 15 | - Added comprehensive client support for interacting with MCP servers: 16 | - `new_client()` for creating client connections to both local process and HTTP servers 17 | - `initialize()` for initializing client connections 18 | - `tools_list()` and `tools_call()` for discovering and using server tools 19 | - `prompts_list()` and `prompts_get()` for working with server prompts 20 | - `resources_list()` and `resources_read()` for accessing server resources 21 | - Renamed `new_mcp()` (deprecated) to `new_server()` for clarity 22 | - Added example implementations for both server and client 23 | - Added client usage vignette 24 | - Fix major issue with `serve_http()` 25 | 26 | # mcpr 0.0.0 27 | 28 | * Initial CRAN submission. 29 | -------------------------------------------------------------------------------- /man/property_number.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/input-schema.R 3 | \name{property_number} 4 | \alias{property_number} 5 | \title{Create a number property definition} 6 | \usage{ 7 | property_number( 8 | title, 9 | description, 10 | required = FALSE, 11 | minimum = NULL, 12 | maximum = NULL, 13 | exclusive_minimum = NULL, 14 | exclusive_maximum = NULL, 15 | multiple_of = NULL, 16 | integer = FALSE 17 | ) 18 | } 19 | \arguments{ 20 | \item{title}{Short title for the property} 21 | 22 | \item{description}{Longer description of the property} 23 | 24 | \item{required}{Whether the property is required} 25 | 26 | \item{minimum}{Optional minimum value} 27 | 28 | \item{maximum}{Optional maximum value} 29 | 30 | \item{exclusive_minimum}{Whether minimum is exclusive} 31 | 32 | \item{exclusive_maximum}{Whether maximum is exclusive} 33 | 34 | \item{multiple_of}{Optional value the number must be a multiple of} 35 | 36 | \item{integer}{Whether the number should be an integer} 37 | } 38 | \value{ 39 | A number property object 40 | } 41 | \description{ 42 | Create a number property definition 43 | } 44 | \examples{ 45 | age_prop <- property_number( 46 | "User age", 47 | "The age of the user in years", 48 | required = TRUE, 49 | minimum = 0, 50 | integer = TRUE 51 | ) 52 | } 53 | -------------------------------------------------------------------------------- /examples/calculator/server.R: -------------------------------------------------------------------------------- 1 | devtools::load_all() 2 | 3 | # Create a calculator tool 4 | calculator <- new_tool( 5 | name = "math_calculator", 6 | description = "Performs basic arithmetic operations", 7 | input_schema = schema( 8 | properties = properties( 9 | operation = property_enum( 10 | "Operation", 11 | "Math operation to perform", 12 | values = c("add", "subtract", "multiply", "divide"), 13 | required = TRUE 14 | ), 15 | a = property_number("First number", "First operand", required = TRUE), 16 | b = property_number("Second number", "Second operand", required = TRUE) 17 | ) 18 | ), 19 | handler = function(params) { 20 | result <- switch( 21 | params$operation, 22 | "add" = params$a + params$b, 23 | "subtract" = params$a - params$b, 24 | "multiply" = params$a * params$b, 25 | "divide" = params$a / params$b 26 | ) 27 | response_text(result) 28 | } 29 | ) 30 | 31 | # Create an MCP server and add the calculator tool 32 | mcp <- new_server( 33 | name = "R Calculator Server", 34 | description = "A simple calculator server implemented in R", 35 | version = "1.0.0" 36 | ) 37 | 38 | mcp <- add_capability(mcp, calculator) 39 | 40 | # Start the server (listening on stdin/stdout) 41 | serve_io(mcp) 42 | #serve_http(mcp, path = "/mcp") 43 | -------------------------------------------------------------------------------- /man/ellmer_to_mcpr_tool.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ellmer-to-mcpr.R 3 | \name{ellmer_to_mcpr_tool} 4 | \alias{ellmer_to_mcpr_tool} 5 | \title{Convert ellmer tools to mcpr tools} 6 | \usage{ 7 | ellmer_to_mcpr_tool(ellmer_tool) 8 | } 9 | \arguments{ 10 | \item{ellmer_tool}{An ellmer ToolDef object created with \code{ellmer::tool()}} 11 | } 12 | \value{ 13 | An mcpr tool object compatible with \code{new_tool()} 14 | } 15 | \description{ 16 | This function converts tools from the ellmer package to a format compatible 17 | with the mcpr package. It takes an ellmer ToolDef object and creates an 18 | mcpr tool object with the appropriate input schema and handler function. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # Create an ellmer tool 23 | ellmer_rnorm <- ellmer::tool( 24 | rnorm, 25 | "Generate random normal numbers", 26 | n = ellmer::type_integer("Number of observations"), 27 | mean = ellmer::type_number("Mean value", required = FALSE), 28 | sd = ellmer::type_number("Standard deviation", required = FALSE) 29 | ) 30 | 31 | # Convert to mcpr format 32 | mcpr_tool <- ellmer_to_mcpr_tool(ellmer_rnorm) 33 | 34 | # Add to an mcpr server 35 | server <- new_server("MyServer", "Test server", "1.0.0") 36 | add_capability(server, mcpr_tool) 37 | } 38 | 39 | } 40 | \seealso{ 41 | \code{\link[=new_tool]{new_tool()}}, \code{\link[ellmer:tool]{ellmer::tool()}}, \code{\link[=add_capability]{add_capability()}} 42 | } 43 | -------------------------------------------------------------------------------- /examples/ellmer/server.R: -------------------------------------------------------------------------------- 1 | devtools::load_all() 2 | 3 | # Create a calculator tool 4 | calculator <- new_tool( 5 | name = "math_calculator", 6 | description = "Performs basic arithmetic operations", 7 | input_schema = schema( 8 | properties = properties( 9 | operation = property_enum( 10 | "Operation", 11 | "Math operation to perform", 12 | values = c("add", "subtract", "multiply", "divide"), 13 | required = TRUE 14 | ), 15 | a = property_number("First number", "First operand", required = TRUE), 16 | b = property_number("Second number", "Second operand", required = TRUE) 17 | ) 18 | ), 19 | handler = function(params) { 20 | result <- switch( 21 | params$operation, 22 | "add" = params$a + params$b, 23 | "subtract" = params$a - params$b, 24 | "multiply" = params$a * params$b, 25 | "divide" = params$a / params$b 26 | ) 27 | response_text( 28 | sprintf("The result from the R calculator is %s", result) 29 | ) 30 | } 31 | ) 32 | 33 | current_time <- ellmer::tool( 34 | \(tz = "UTC") { 35 | format(Sys.time(), tz = tz, usetz = TRUE) 36 | }, 37 | "Gets the current time in the given time zone.", 38 | tz = ellmer::type_string( 39 | "The time zone to get the current time in. Defaults to `\"UTC\"`.", 40 | required = FALSE 41 | ) 42 | ) 43 | 44 | # Create an MCP server and add the calculator tool 45 | mcp <- new_server( 46 | name = "R Calculator Server", 47 | description = "A simple calculator server implemented in R", 48 | version = "1.0.0" 49 | ) 50 | 51 | mcp <- add_capability(mcp, calculator) 52 | mcp <- add_capability(mcp, current_time) 53 | 54 | # Start the server (listening on stdin/stdout) 55 | serve_io(mcp) 56 | #serve_http(mcp, path = "/mcp") 57 | -------------------------------------------------------------------------------- /man/response.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/response.R 3 | \name{response} 4 | \alias{response} 5 | \alias{response_text} 6 | \alias{response_image} 7 | \alias{response_audio} 8 | \alias{response_video} 9 | \alias{response_file} 10 | \alias{response_resource} 11 | \alias{response_error} 12 | \alias{response_item} 13 | \title{Create a response object} 14 | \usage{ 15 | response_text(text) 16 | 17 | response_image(image, mime_type = "image/png") 18 | 19 | response_audio(audio, mime_type = "audio/mpeg") 20 | 21 | response_video(video, mime_type = "video/mp4") 22 | 23 | response_file(file, mime_type = "application/octet-stream") 24 | 25 | response_resource(resource) 26 | 27 | response_error(text) 28 | 29 | response_item( 30 | ..., 31 | type = c("text", "image", "audio", "video", "file", "resource") 32 | ) 33 | 34 | response(..., is_error = FALSE) 35 | } 36 | \arguments{ 37 | \item{text}{Text content for the response} 38 | 39 | \item{image}{Image content} 40 | 41 | \item{mime_type}{Mime type of the content} 42 | 43 | \item{audio}{Audio content} 44 | 45 | \item{video}{Video content} 46 | 47 | \item{file}{File content} 48 | 49 | \item{resource}{Resource content} 50 | 51 | \item{...}{Mutliple \code{response} objects or passed to \code{ggplot2::ggsave}} 52 | 53 | \item{type}{Type of the content} 54 | 55 | \item{is_error}{Whether the response is an error} 56 | } 57 | \value{ 58 | A response object 59 | } 60 | \description{ 61 | Create a response object 62 | } 63 | \details{ 64 | Use \code{response_item} to create a custom response item. 65 | } 66 | \examples{ 67 | response( 68 | response_text("Hello, world!"), 69 | response_image(system.file("extdata/logo.png", package = "mcpr")), 70 | response_audio(system.file("extdata/sound.mp3", package = "mcpr")), 71 | response_video(system.file("extdata/video.mp4", package = "mcpr")), 72 | response_file(system.file("extdata/file.txt", package = "mcpr")), 73 | response_resource(system.file("extdata/resource.json", package = "mcpr")) 74 | ) 75 | 76 | } 77 | -------------------------------------------------------------------------------- /docs/deps/bootstrap-toc-1.0.1/bootstrap-toc.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | !function(a){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){return a(e).text().trim().replace(/\'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,64).replace(/^-+|-+$/gm,"").toLowerCase()||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(0')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('');n.attr("href","#"+e),n.text(t);var r=a("
  • ");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1 8 | Core functions for creating and managing MCP server objects 9 | contents: 10 | - new_mcp 11 | - add_capability 12 | - register_mcpr_tools 13 | 14 | - title: "Capability Creation" 15 | desc: > 16 | Functions for creating different types of capabilities 17 | contents: 18 | - new_tool 19 | - new_resource 20 | - new_prompt 21 | 22 | - title: "Schema and Properties" 23 | desc: > 24 | Functions for defining input schemas and properties 25 | contents: 26 | - schema 27 | - properties 28 | - property_string 29 | - property_number 30 | - property_boolean 31 | - property_array 32 | - property_object 33 | - property_enum 34 | - new_property 35 | 36 | - title: "Server Functions" 37 | desc: > 38 | Functions for serving MCP implementations 39 | contents: 40 | - serve_io 41 | - serve_http 42 | - get_name 43 | 44 | - title: "Client Functions" 45 | desc: > 46 | Functions for connecting to and interacting with MCP servers 47 | contents: 48 | - new_client_io 49 | - new_client_http 50 | - initialize 51 | - tools_list 52 | - tools_call 53 | - prompts_list 54 | - prompts_get 55 | - resources_list 56 | - resources_read 57 | - read 58 | - write 59 | 60 | - title: "Response Functions" 61 | desc: > 62 | Functions for creating various response types 63 | contents: 64 | - response 65 | - matches("^response_") 66 | 67 | - title: "Roxygen2 Extension" 68 | desc: > 69 | Functions for extending roxygen2 with MCP server generation 70 | contents: 71 | - mcp_roclet 72 | - roxy_tag_parse.roxy_tag_mcp 73 | - roxy_tag_parse.roxy_tag_type 74 | - roclet_process.roclet_mcp 75 | - roxy_tag_rd.roxy_tag_mcp 76 | - roxy_tag_rd.roxy_tag_type 77 | - roclet_output.roclet_mcp 78 | 79 | - title: "Ellmer Integration" 80 | desc: > 81 | Functions for integrating with the Ellmer package 82 | contents: 83 | - register_mcpr_tools 84 | - ellmer_to_mcpr_tool 85 | 86 | -------------------------------------------------------------------------------- /R/client.R: -------------------------------------------------------------------------------- 1 | #' Create a new mcp IO 2 | #' 3 | #' @param endpoint The endpoint to connect to 4 | #' @param command The command to run 5 | #' @param args Arguments to pass to the command 6 | #' @param name The name of the client 7 | #' @param version The version of the client 8 | #' 9 | #' @return A new mcp client 10 | #' @export 11 | #' @name client 12 | new_client_io <- function( 13 | command, 14 | args = character(), 15 | name, 16 | version = "1.0.0" 17 | ) { 18 | stopifnot(is.character(command), length(command) == 1) 19 | stopifnot(!missing(name), is.character(name), length(name) == 1) 20 | 21 | if (!requireNamespace("processx", quietly = TRUE)) { 22 | stop("The processx package is required to use the io client") 23 | } 24 | 25 | p <- processx::process$new( 26 | command = command, 27 | args = args, 28 | stdin = "|", 29 | stdout = "|" 30 | ) 31 | 32 | new_client( 33 | p, 34 | name = name, 35 | version = version, 36 | type = "io" 37 | ) 38 | } 39 | 40 | #' @rdname client 41 | new_client_http <- function( 42 | endpoint, 43 | name, 44 | version = "1.0.0" 45 | ) { 46 | stopifnot(is.character(endpoint), length(endpoint) == 1) 47 | stopifnot(!missing(name), is.character(name), length(name) == 1) 48 | 49 | if (!requireNamespace("httr2", quietly = TRUE)) { 50 | stop("The httr2 package is required to use the http client") 51 | } 52 | 53 | r <- httr2::request(endpoint) |> 54 | httr2::req_method("POST") 55 | 56 | new_client( 57 | r, 58 | name = name, 59 | version = version, 60 | type = "http" 61 | ) 62 | } 63 | 64 | new_client <- function(obj, name, version, type = c("io", "http")) { 65 | type <- match.arg(type) 66 | cls <- sprintf("client_%s", type) 67 | 68 | structure( 69 | obj, 70 | name = name, 71 | version = version, 72 | class = c(cls, "client", class(obj)) 73 | ) 74 | } 75 | 76 | #' Get the name of a client 77 | #' 78 | #' @param x A client object 79 | #' 80 | #' @return The name of the client 81 | #' @export 82 | get_name <- function(x) UseMethod("get_name") 83 | 84 | #' @export 85 | get_name.client <- function(x) { 86 | attr(x, "name") 87 | } 88 | 89 | #' @export 90 | get_name.server <- function(x) { 91 | attr(x, "name") 92 | } 93 | -------------------------------------------------------------------------------- /docs/extra.css: -------------------------------------------------------------------------------- 1 | /* mcpr theme based on logo colors */ 2 | 3 | :root { 4 | --mcpr-dark-blue: #1a3c5e; 5 | --mcpr-mid-blue: #195b7f; 6 | --mcpr-teal: #19b8bf; 7 | --mcpr-light-teal: #72d6d9; 8 | --mcpr-very-light-teal: #e5f7f7; 9 | } 10 | 11 | /* Navbar styling */ 12 | .navbar { 13 | background-color: var(--mcpr-dark-blue); 14 | border-bottom: 3px solid var(--mcpr-teal); 15 | } 16 | 17 | .navbar-dark .navbar-nav .nav-link { 18 | color: rgba(255, 255, 255, 0.85); 19 | } 20 | 21 | .navbar-dark .navbar-nav .active > .nav-link { 22 | color: var(--mcpr-light-teal); 23 | } 24 | 25 | .navbar-dark .navbar-nav .nav-link:hover, 26 | .navbar-dark .navbar-nav .nav-link:focus { 27 | color: var(--mcpr-light-teal); 28 | } 29 | 30 | /* Headings */ 31 | h1, h2, h3, h4, h5, h6 { 32 | color: var(--mcpr-dark-blue); 33 | } 34 | 35 | /* Links */ 36 | a { 37 | color: var(--mcpr-mid-blue); 38 | } 39 | 40 | a:hover, a:focus { 41 | color: var(--mcpr-teal); 42 | } 43 | 44 | /* Code blocks */ 45 | pre, code { 46 | background-color: var(--mcpr-very-light-teal); 47 | border-color: var(--mcpr-light-teal); 48 | } 49 | 50 | /* Buttons */ 51 | .btn-primary { 52 | background-color: var(--mcpr-mid-blue); 53 | border-color: var(--mcpr-mid-blue); 54 | } 55 | 56 | .btn-primary:hover, .btn-primary:focus { 57 | background-color: var(--mcpr-dark-blue); 58 | border-color: var(--mcpr-dark-blue); 59 | } 60 | 61 | /* Sidebar navigation */ 62 | .nav-pills .nav-link.active { 63 | background-color: var(--mcpr-mid-blue); 64 | } 65 | 66 | /* Footer */ 67 | footer { 68 | border-top: 1px solid var(--mcpr-light-teal); 69 | background-color: var(--mcpr-very-light-teal); 70 | } 71 | 72 | /* Table styling */ 73 | table { 74 | border-collapse: collapse; 75 | } 76 | 77 | thead { 78 | background-color: var(--mcpr-very-light-teal); 79 | } 80 | 81 | th { 82 | color: var(--mcpr-dark-blue); 83 | } 84 | 85 | tr:hover { 86 | background-color: var(--mcpr-very-light-teal); 87 | } 88 | 89 | /* Syntax highlighting tweaks */ 90 | .fl { 91 | color: var(--mcpr-mid-blue); 92 | } 93 | 94 | .fu { 95 | color: var(--mcpr-dark-blue); 96 | } 97 | 98 | .st { 99 | color: var(--mcpr-teal); 100 | } -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | /* mcpr theme based on logo colors */ 2 | 3 | :root { 4 | --mcpr-dark-blue: #1a3c5e; 5 | --mcpr-mid-blue: #195b7f; 6 | --mcpr-teal: #19b8bf; 7 | --mcpr-light-teal: #72d6d9; 8 | --mcpr-very-light-teal: #e5f7f7; 9 | } 10 | 11 | /* Navbar styling */ 12 | .navbar { 13 | background-color: var(--mcpr-dark-blue); 14 | border-bottom: 3px solid var(--mcpr-teal); 15 | } 16 | 17 | .navbar-dark .navbar-nav .nav-link { 18 | color: rgba(255, 255, 255, 0.85); 19 | } 20 | 21 | .navbar-dark .navbar-nav .active > .nav-link { 22 | color: var(--mcpr-light-teal); 23 | } 24 | 25 | .navbar-dark .navbar-nav .nav-link:hover, 26 | .navbar-dark .navbar-nav .nav-link:focus { 27 | color: var(--mcpr-light-teal); 28 | } 29 | 30 | /* Headings */ 31 | h1, h2, h3, h4, h5, h6 { 32 | color: var(--mcpr-dark-blue); 33 | } 34 | 35 | /* Links */ 36 | a { 37 | color: var(--mcpr-mid-blue); 38 | } 39 | 40 | a:hover, a:focus { 41 | color: var(--mcpr-teal); 42 | } 43 | 44 | /* Code blocks */ 45 | pre, code { 46 | background-color: var(--mcpr-very-light-teal); 47 | border-color: var(--mcpr-light-teal); 48 | } 49 | 50 | /* Buttons */ 51 | .btn-primary { 52 | background-color: var(--mcpr-mid-blue); 53 | border-color: var(--mcpr-mid-blue); 54 | } 55 | 56 | .btn-primary:hover, .btn-primary:focus { 57 | background-color: var(--mcpr-dark-blue); 58 | border-color: var(--mcpr-dark-blue); 59 | } 60 | 61 | /* Sidebar navigation */ 62 | .nav-pills .nav-link.active { 63 | background-color: var(--mcpr-mid-blue); 64 | } 65 | 66 | /* Footer */ 67 | footer { 68 | border-top: 1px solid var(--mcpr-light-teal); 69 | background-color: var(--mcpr-very-light-teal); 70 | } 71 | 72 | /* Table styling */ 73 | table { 74 | border-collapse: collapse; 75 | } 76 | 77 | thead { 78 | background-color: var(--mcpr-very-light-teal); 79 | } 80 | 81 | th { 82 | color: var(--mcpr-dark-blue); 83 | } 84 | 85 | tr:hover { 86 | background-color: var(--mcpr-very-light-teal); 87 | } 88 | 89 | /* Syntax highlighting tweaks */ 90 | .fl { 91 | color: var(--mcpr-mid-blue); 92 | } 93 | 94 | .fu { 95 | color: var(--mcpr-dark-blue); 96 | } 97 | 98 | .st { 99 | color: var(--mcpr-teal); 100 | } -------------------------------------------------------------------------------- /R/http.R: -------------------------------------------------------------------------------- 1 | #' Serve an MCP server over HTTP using ambiorix 2 | #' 3 | #' @param mcp An MCP server object 4 | #' @param port Port to listen on, defaults to 3000 5 | #' @param path Path to serve the MCP endpoint, defaults to "/mcp" 6 | #' 7 | #' @return Invisible, runs indefinitely 8 | #' @export 9 | serve_http <- function( 10 | mcp, 11 | port = Sys.getenv("SHINY_PORT", 3000), 12 | path = "/mcp" 13 | ) { 14 | # Validate MCP object 15 | if (missing(mcp)) { 16 | stop("An MCP server object is required") 17 | } 18 | 19 | if (!inherits(mcp, "server")) { 20 | stop("mcp must be an MCP server object") 21 | } 22 | 23 | # Check if ambiorix is installed 24 | if (!requireNamespace("ambiorix", quietly = TRUE)) { 25 | stop( 26 | "The 'ambiorix' package is required for HTTP transport. Please install it with install.packages('ambiorix')" 27 | ) 28 | } 29 | 30 | port <- as.integer(port) 31 | 32 | # Create a new ambiorix app 33 | app <- ambiorix::Ambiorix$new() 34 | 35 | # Add CORS headers middleware 36 | app$use(function(req, res) { 37 | res$set_header("Access-Control-Allow-Origin", "*") 38 | res$set_header("Access-Control-Allow-Methods", "POST, OPTIONS") 39 | res$set_header("Access-Control-Allow-Headers", "Content-Type") 40 | }) 41 | 42 | # Define MCP endpoint 43 | app$post(path, function(req, res) { 44 | # Get request body 45 | body <- ambiorix::parse_json(req) |> 46 | yyjsonr::write_json_str(opts = list(auto_unbox = TRUE)) 47 | 48 | # Process the request through JSON-RPC 49 | response <- tryCatch( 50 | parse_request(body, mcp), 51 | error = function(e) { 52 | create_error( 53 | JSONRPC_PARSE_ERROR, 54 | paste("Parse error:", e$message) 55 | ) 56 | } 57 | ) 58 | 59 | if (is.null(response)) { 60 | # For notifications, return an empty success response 61 | res$set_status(204) # No Content 62 | res$send("") 63 | return() 64 | } 65 | 66 | # Set content type and send response 67 | res$set_header("Content-Type", "application/json") 68 | 69 | # Handle different response types 70 | if ( 71 | inherits(response, "jsonrpc_response") || 72 | inherits(response, "jsonrpc_error") 73 | ) { 74 | res$send(to_json(response)) 75 | } else { 76 | # It's already JSON from a batch request 77 | res$send(response) 78 | } 79 | }) 80 | 81 | # Start the server 82 | app$start(port = port) 83 | 84 | invisible() 85 | } 86 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(add_capability,"ellmer::ToolDef") 4 | S3method(add_capability,prompt) 5 | S3method(add_capability,resource) 6 | S3method(add_capability,tool) 7 | S3method(get_name,client) 8 | S3method(get_name,server) 9 | S3method(initialize,client) 10 | S3method(initialize,server) 11 | S3method(prompts_get,client) 12 | S3method(prompts_get,server) 13 | S3method(prompts_list,client) 14 | S3method(prompts_list,server) 15 | S3method(read,client_io) 16 | S3method(resources_list,client) 17 | S3method(resources_list,server) 18 | S3method(resources_read,client) 19 | S3method(resources_read,server) 20 | S3method(response_force,default) 21 | S3method(response_force,error) 22 | S3method(response_force,response) 23 | S3method(response_force,response_item) 24 | S3method(roclet_output,roclet_mcp) 25 | S3method(roclet_process,roclet_mcp) 26 | S3method(roxy_tag_parse,roxy_tag_mcp) 27 | S3method(roxy_tag_parse,roxy_tag_type) 28 | S3method(roxy_tag_rd,roxy_tag_mcp) 29 | S3method(roxy_tag_rd,roxy_tag_type) 30 | S3method(send,jsonrpc_error) 31 | S3method(send,jsonrpc_response) 32 | S3method(tools_call,client) 33 | S3method(tools_call,server) 34 | S3method(tools_list,client) 35 | S3method(tools_list,server) 36 | S3method(write,client_http) 37 | S3method(write,client_io) 38 | export(add_capability) 39 | export(ellmer_to_mcpr_tool) 40 | export(get_name) 41 | export(initialize) 42 | export(mcp_roclet) 43 | export(new_client_io) 44 | export(new_mcp) 45 | export(new_prompt) 46 | export(new_resource) 47 | export(new_server) 48 | export(new_tool) 49 | export(prompts_get) 50 | export(prompts_list) 51 | export(properties) 52 | export(property_array) 53 | export(property_boolean) 54 | export(property_enum) 55 | export(property_number) 56 | export(property_object) 57 | export(property_string) 58 | export(read) 59 | export(register_mcpr_tools) 60 | export(resources_list) 61 | export(resources_read) 62 | export(response) 63 | export(response_audio) 64 | export(response_error) 65 | export(response_file) 66 | export(response_image) 67 | export(response_item) 68 | export(response_resource) 69 | export(response_text) 70 | export(response_video) 71 | export(schema) 72 | export(serve_http) 73 | export(serve_io) 74 | export(tools_call) 75 | export(tools_list) 76 | export(write) 77 | importFrom(roxygen2,block_get_tag_value) 78 | importFrom(roxygen2,block_get_tags) 79 | importFrom(roxygen2,roclet) 80 | importFrom(roxygen2,roclet_output) 81 | importFrom(roxygen2,roclet_process) 82 | importFrom(roxygen2,roxy_tag_parse) 83 | importFrom(roxygen2,roxy_tag_rd) 84 | importFrom(roxygen2,roxy_tag_warning) 85 | -------------------------------------------------------------------------------- /docs/lightswitch.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) 4 | * Copyright 2011-2023 The Bootstrap Authors 5 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 6 | * Updates for {pkgdown} by the {bslib} authors, also licensed under CC-BY-3.0. 7 | */ 8 | 9 | const getStoredTheme = () => localStorage.getItem('theme') 10 | const setStoredTheme = theme => localStorage.setItem('theme', theme) 11 | 12 | const getPreferredTheme = () => { 13 | const storedTheme = getStoredTheme() 14 | if (storedTheme) { 15 | return storedTheme 16 | } 17 | 18 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 19 | } 20 | 21 | const setTheme = theme => { 22 | if (theme === 'auto') { 23 | document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) 24 | } else { 25 | document.documentElement.setAttribute('data-bs-theme', theme) 26 | } 27 | } 28 | 29 | function bsSetupThemeToggle () { 30 | 'use strict' 31 | 32 | const showActiveTheme = (theme, focus = false) => { 33 | var activeLabel, activeIcon; 34 | 35 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 36 | const buttonTheme = element.getAttribute('data-bs-theme-value') 37 | const isActive = buttonTheme == theme 38 | 39 | element.classList.toggle('active', isActive) 40 | element.setAttribute('aria-pressed', isActive) 41 | 42 | if (isActive) { 43 | activeLabel = element.textContent; 44 | activeIcon = element.querySelector('span').classList.value; 45 | } 46 | }) 47 | 48 | const themeSwitcher = document.querySelector('#dropdown-lightswitch') 49 | if (!themeSwitcher) { 50 | return 51 | } 52 | 53 | themeSwitcher.setAttribute('aria-label', activeLabel) 54 | themeSwitcher.querySelector('span').classList.value = activeIcon; 55 | 56 | if (focus) { 57 | themeSwitcher.focus() 58 | } 59 | } 60 | 61 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 62 | const storedTheme = getStoredTheme() 63 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 64 | setTheme(getPreferredTheme()) 65 | } 66 | }) 67 | 68 | window.addEventListener('DOMContentLoaded', () => { 69 | showActiveTheme(getPreferredTheme()) 70 | 71 | document 72 | .querySelectorAll('[data-bs-theme-value]') 73 | .forEach(toggle => { 74 | toggle.addEventListener('click', () => { 75 | const theme = toggle.getAttribute('data-bs-theme-value') 76 | setTheme(theme) 77 | setStoredTheme(theme) 78 | showActiveTheme(theme, true) 79 | }) 80 | }) 81 | }) 82 | } 83 | 84 | setTheme(getPreferredTheme()); 85 | bsSetupThemeToggle(); 86 | -------------------------------------------------------------------------------- /vignettes/get-started.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started with mcpr" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Getting Started with mcpr} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(mcpr) 19 | ``` 20 | 21 | ## Introduction 22 | 23 | The `mcpr` package allows you to create Model Context Protocol (MCP) servers in R. This vignette will guide you through building a very simple MCP server with a basic addition tool. 24 | 25 | ## Creating a Simple MCP Server 26 | 27 | Let's create a simple MCP server that can add two numbers: 28 | 29 | ```{r} 30 | # Create a new MCP server 31 | mcp_server <- new_server( 32 | name = "Simple Adder", 33 | description = "A basic MCP server that adds two numbers", 34 | version = "1.0.0" 35 | ) 36 | 37 | # Create a simple addition tool 38 | add_tool <- new_tool( 39 | name = "add", 40 | description = "Adds two numbers together", 41 | input_schema = schema( 42 | properties = list( 43 | a = property_number("First number", "First number to add", required = TRUE), 44 | b = property_number("Second number", "Second number to add", required = TRUE) 45 | ) 46 | ), 47 | handler = function(input) { 48 | result <- input$a + input$b 49 | response_text(paste("The sum is:", result)) 50 | } 51 | ) 52 | 53 | # Add the tool to the server 54 | mcp_server <- add_capability(mcp_server, add_tool) 55 | ``` 56 | 57 | ## Using Standard Input/Output 58 | 59 | The simplest way to interact with your MCP server is through standard input/output using the `serve_io` function: 60 | 61 | ```{r, eval=FALSE} 62 | # Start the server using standard input/output 63 | serve_io(mcp_server) 64 | ``` 65 | 66 | When you run `serve_io(mcp_server)`, your R session will wait for input in JSON-RPC 2.0 format. You can then communicate with your server by sending JSON-RPC requests. 67 | 68 | ## Testing the Server 69 | 70 | To test your server, you can run the above code in an R script and interact with it using the command line. For example: 71 | 72 | 1. Save the code in a file named `mcp_adder.R` 73 | 2. Run it from the command line: `Rscript mcp_adder.R` 74 | 3. Send a JSON-RPC request to standard input: 75 | 76 | ```json 77 | {"jsonrpc": "2.0", "id": 123, "method": "tools/call", "params": {"name": "add", "arguments": {"a": 15, "b": 27}}} 78 | ``` 79 | 80 | The server will respond with: 81 | 82 | ```json 83 | {"jsonrpc": "2.0", "id": 123, "result": {"content": [{"type": "text", "text": "The sum is: 42"}]}} 84 | ``` 85 | 86 | ## Next Steps 87 | 88 | Once you're comfortable with the basics, you can: 89 | 90 | 1. Add more complex tools with different operations 91 | 2. Create resources to serve data 92 | 3. Implement prompts for text generation 93 | 94 | See the other vignettes and function documentation for more details on these advanced features. 95 | -------------------------------------------------------------------------------- /R/request.R: -------------------------------------------------------------------------------- 1 | #' Write a JSON-RPC request to a client provider 2 | #' 3 | #' @param x A client provider 4 | #' @param method The method to call 5 | #' @param params The parameters to pass to the method 6 | #' @param id The id of the request 7 | #' @param timeout Timeout in milliseconds for reading the response 8 | #' 9 | #' @return The client provider 10 | #' @export 11 | write <- function(x, method, params = NULL, id = generate_id(), timeout = 5000) 12 | UseMethod("write") 13 | 14 | #' @method write client_io 15 | #' @export 16 | write.client_io <- function( 17 | x, 18 | method, 19 | params = NULL, 20 | id = generate_id(), 21 | timeout = 5000 22 | ) { 23 | # Check if process is alive before writing 24 | if (!x$is_alive()) { 25 | stop("client process is not alive") 26 | } 27 | 28 | # Create and write the request with proper newline 29 | r <- rpc_request(method, params, id) 30 | x$write_input(sprintf("%s\n", r)) 31 | 32 | # Read the response with the specified timeout 33 | read(x, timeout) 34 | } 35 | 36 | #' @method write client_http 37 | #' @export 38 | write.client_http <- function( 39 | x, 40 | method, 41 | params = NULL, 42 | id = generate_id(), 43 | timeout = 5000 44 | ) { 45 | r <- rpc_request(method, params, id, convert = FALSE) 46 | 47 | x |> 48 | httr2::req_timeout(timeout) |> 49 | httr2::req_body_json(r) |> 50 | httr2::req_perform() |> 51 | httr2::resp_body_json() 52 | } 53 | 54 | #' Read a JSON-RPC response from a client provider 55 | #' 56 | #' @param x A client provider 57 | #' @param timeout Timeout in milliseconds for reading the response 58 | #' 59 | #' @return The response 60 | #' @export 61 | read <- function(x, timeout = 60 * 1000) UseMethod("read") 62 | 63 | #' @method read client_io 64 | #' @export 65 | read.client_io <- function(x, timeout = 60 * 1000) { 66 | # Check if process is alive before reading 67 | if (!x$is_alive()) { 68 | stop("client process is not alive") 69 | } 70 | 71 | # Use poll_io with timeout to wait for response 72 | poll_result <- x$poll_io(timeout) 73 | 74 | # Check if we have data to read 75 | if (poll_result["output"] == "ready") { 76 | # Read the output when it's ready 77 | 78 | res <- tryCatch( 79 | { 80 | res <- x$read_output() 81 | from_json(res) 82 | }, 83 | error = function(e) { 84 | warning("Invalid JSON response: ", e$message) 85 | NULL 86 | } 87 | ) 88 | 89 | return(res) 90 | } 91 | 92 | if (poll_result["output"] == "timeout") { 93 | warning("Timeout waiting for client response") 94 | return(NULL) 95 | } 96 | # Process closed the connection or other issue 97 | warning("client connection closed or error") 98 | return(NULL) 99 | } 100 | 101 | rpc_request <- function( 102 | method, 103 | params = NULL, 104 | id = generate_id(), 105 | convert = TRUE 106 | ) { 107 | r <- list( 108 | jsonrpc = "2.0", 109 | method = method, 110 | params = params, 111 | id = id 112 | ) 113 | 114 | r <- Filter(Negate(is.null), r) 115 | 116 | if (!convert) return(r) 117 | 118 | to_json(r) 119 | } 120 | -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.11.0 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t,n){n=n||{},Object.assign(this,o.options,n),this.classes=Object.assign({},o.options.classes,n.classes),this.elem=t,this.tolerance=function(t){return t===Object(t)?t:{down:t,up:t}}(this.tolerance),this.initialised=!1,this.frozen=!1}return o.prototype={constructor:o,init:function(){return o.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},o.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},o.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),o}); -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | Articles • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    39 | 40 |
    41 |

    All vignettes

    42 |
    43 | 44 |
    Integrating mcpr with MCP Clients
    45 |
    46 |
    Using the MCP Client
    47 |
    48 |
    Getting Started with mcpr
    49 |
    50 |
    Practical MCP Examples with R
    51 |
    52 |
    53 |
    54 | 55 | 56 |
    59 | 60 | 63 | 64 |
    65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /R/response.R: -------------------------------------------------------------------------------- 1 | #' Create a response object 2 | #' 3 | #' @param text Text content for the response 4 | #' @type text string 5 | #' @param image Image content 6 | #' @param audio Audio content 7 | #' @param video Video content 8 | #' @param file File content 9 | #' @param type Type of the content 10 | #' @param resource Resource content 11 | #' @param is_error Whether the response is an error 12 | #' @param mime_type Mime type of the content 13 | #' @param ... Mutliple `response` objects or passed to `ggplot2::ggsave` 14 | #' 15 | #' @details Use `response_item` to create a custom response item. 16 | #' 17 | #' @examples 18 | #' response( 19 | #' response_text("Hello, world!"), 20 | #' response_image(system.file("extdata/logo.png", package = "mcpr")), 21 | #' response_audio(system.file("extdata/sound.mp3", package = "mcpr")), 22 | #' response_video(system.file("extdata/video.mp4", package = "mcpr")), 23 | #' response_file(system.file("extdata/file.txt", package = "mcpr")), 24 | #' response_resource(system.file("extdata/resource.json", package = "mcpr")) 25 | #' ) 26 | #' 27 | #' @name response 28 | #' @return A response object 29 | #' @mcp create_text_response Create a text response for MCP tool handlers 30 | #' @export 31 | response_text <- function(text) { 32 | if (missing(text)) { 33 | stop("'text' argument is required") 34 | } 35 | response_item(text = as.character(text), type = "text") 36 | } 37 | 38 | #' @rdname response 39 | #' @export 40 | response_image <- function(image, mime_type = "image/png") { 41 | if (missing(image)) { 42 | stop("'image' argument is required") 43 | } 44 | if (!is.character(mime_type)) { 45 | stop("'mime_type' must be a character string") 46 | } 47 | response_item(data = image, type = "image", mimeType = mime_type) 48 | } 49 | 50 | #' @rdname response 51 | #' @export 52 | response_audio <- function(audio, mime_type = "audio/mpeg") { 53 | if (missing(audio)) { 54 | stop("'audio' argument is required") 55 | } 56 | if (!is.character(mime_type)) { 57 | stop("'mime_type' must be a character string") 58 | } 59 | response_item(data = audio, type = "audio", mimeType = mime_type) 60 | } 61 | 62 | #' @rdname response 63 | #' @export 64 | response_video <- function(video, mime_type = "video/mp4") { 65 | if (missing(video)) { 66 | stop("'video' argument is required") 67 | } 68 | if (!is.character(mime_type)) { 69 | stop("'mime_type' must be a character string") 70 | } 71 | response_item(data = video, type = "video", mimeType = mime_type) 72 | } 73 | 74 | #' @rdname response 75 | #' @export 76 | response_file <- function(file, mime_type = "application/octet-stream") { 77 | if (missing(file)) { 78 | stop("'file' argument is required") 79 | } 80 | if (!is.character(mime_type)) { 81 | stop("'mime_type' must be a character string") 82 | } 83 | response_item(data = file, type = "file", mimeType = mime_type) 84 | } 85 | 86 | #' @rdname response 87 | #' @export 88 | response_resource <- function(resource) { 89 | if (missing(resource)) { 90 | stop("'resource' argument is required") 91 | } 92 | response_item(resource = resource, type = "resource") 93 | } 94 | 95 | #' @rdname response 96 | #' @export 97 | response_error <- function(text) { 98 | if (missing(text)) { 99 | stop("'text' argument is required") 100 | } 101 | response_item(text = as.character(text), type = "text", isError = TRUE) 102 | } 103 | 104 | #' @rdname response 105 | #' @export 106 | response_item <- function( 107 | ..., 108 | type = c("text", "image", "audio", "video", "file", "resource") 109 | ) { 110 | if (length(list(...)) == 0) { 111 | stop("At least one parameter must be provided") 112 | } 113 | 114 | if (length(type) > 1) { 115 | stop("Only one type can be specified") 116 | } 117 | 118 | # no mathc.arg to allow custom types 119 | type <- type[1] 120 | 121 | structure( 122 | list( 123 | type = type, 124 | ... 125 | ), 126 | class = c( 127 | "response_item", 128 | sprintf("response_item_%s", type), 129 | "list" 130 | ) 131 | ) 132 | } 133 | 134 | #' @rdname response 135 | #' @export 136 | response <- function( 137 | ..., 138 | is_error = FALSE 139 | ) { 140 | content <- list(...) 141 | 142 | if (length(content) == 0) { 143 | stop("At least one response item must be provided") 144 | } 145 | 146 | if (!is.logical(is_error)) { 147 | stop("'is_error' must be a logical value") 148 | } 149 | 150 | structure( 151 | list( 152 | content = content, 153 | isError = is_error 154 | ), 155 | class = c( 156 | "response", 157 | "list" 158 | ) 159 | ) 160 | } 161 | 162 | response_force <- function(x) UseMethod("response_force") 163 | 164 | #' @export 165 | #' @method response_force default 166 | response_force.default <- function(x) { 167 | response( 168 | response_text(as.character(x)) 169 | ) 170 | } 171 | 172 | #' @export 173 | #' @method response_force response 174 | response_force.response <- function(x) { 175 | x 176 | } 177 | 178 | #' @export 179 | #' @method response_force response_item 180 | response_force.response_item <- function(x) { 181 | response(x) 182 | } 183 | 184 | #' @export 185 | #' @method response_force error 186 | response_force.error <- function(x) { 187 | response( 188 | response_error(x$message) 189 | ) 190 | } 191 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • mcpr 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Skip to contents 24 | 25 | 26 |
    62 |
    63 |
    67 | 68 | Content not found. Please use links in the navbar. 69 | 70 |
    71 |
    72 | 73 | 74 |
    77 | 78 | 81 | 82 |
    83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('nav.navbar').headroom(); 6 | 7 | Toc.init({ 8 | $nav: $("#toc"), 9 | $scope: $("main h2, main h3, main h4, main h5, main h6") 10 | }); 11 | 12 | if ($('#toc').length) { 13 | $('body').scrollspy({ 14 | target: '#toc', 15 | offset: $("nav.navbar").outerHeight() + 1 16 | }); 17 | } 18 | 19 | // Activate popovers 20 | $('[data-bs-toggle="popover"]').popover({ 21 | container: 'body', 22 | html: true, 23 | trigger: 'focus', 24 | placement: "top", 25 | sanitize: false, 26 | }); 27 | 28 | $('[data-bs-toggle="tooltip"]').tooltip(); 29 | 30 | /* Clipboard --------------------------*/ 31 | 32 | function changeTooltipMessage(element, msg) { 33 | var tooltipOriginalTitle=element.getAttribute('data-bs-original-title'); 34 | element.setAttribute('data-bs-original-title', msg); 35 | $(element).tooltip('show'); 36 | element.setAttribute('data-bs-original-title', tooltipOriginalTitle); 37 | } 38 | 39 | if(ClipboardJS.isSupported()) { 40 | $(document).ready(function() { 41 | var copyButton = ""; 42 | 43 | $("div.sourceCode").addClass("hasCopyButton"); 44 | 45 | // Insert copy buttons: 46 | $(copyButton).prependTo(".hasCopyButton"); 47 | 48 | // Initialize tooltips: 49 | $('.btn-copy-ex').tooltip({container: 'body'}); 50 | 51 | // Initialize clipboard: 52 | var clipboard = new ClipboardJS('[data-clipboard-copy]', { 53 | text: function(trigger) { 54 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 55 | } 56 | }); 57 | 58 | clipboard.on('success', function(e) { 59 | changeTooltipMessage(e.trigger, 'Copied!'); 60 | e.clearSelection(); 61 | }); 62 | 63 | clipboard.on('error', function(e) { 64 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 65 | }); 66 | 67 | }); 68 | } 69 | 70 | /* Search marking --------------------------*/ 71 | var url = new URL(window.location.href); 72 | var toMark = url.searchParams.get("q"); 73 | var mark = new Mark("main#main"); 74 | if (toMark) { 75 | mark.mark(toMark, { 76 | accuracy: { 77 | value: "complementary", 78 | limiters: [",", ".", ":", "/"], 79 | } 80 | }); 81 | } 82 | 83 | /* Search --------------------------*/ 84 | /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ 85 | // Initialise search index on focus 86 | var fuse; 87 | $("#search-input").focus(async function(e) { 88 | if (fuse) { 89 | return; 90 | } 91 | 92 | $(e.target).addClass("loading"); 93 | var response = await fetch($("#search-input").data("search-index")); 94 | var data = await response.json(); 95 | 96 | var options = { 97 | keys: ["what", "text", "code"], 98 | ignoreLocation: true, 99 | threshold: 0.1, 100 | includeMatches: true, 101 | includeScore: true, 102 | }; 103 | fuse = new Fuse(data, options); 104 | 105 | $(e.target).removeClass("loading"); 106 | }); 107 | 108 | // Use algolia autocomplete 109 | var options = { 110 | autoselect: true, 111 | debug: true, 112 | hint: false, 113 | minLength: 2, 114 | }; 115 | var q; 116 | async function searchFuse(query, callback) { 117 | await fuse; 118 | 119 | var items; 120 | if (!fuse) { 121 | items = []; 122 | } else { 123 | q = query; 124 | var results = fuse.search(query, { limit: 20 }); 125 | items = results 126 | .filter((x) => x.score <= 0.75) 127 | .map((x) => x.item); 128 | if (items.length === 0) { 129 | items = [{dir:"Sorry 😿",previous_headings:"",title:"No results found.",what:"No results found.",path:window.location.href}]; 130 | } 131 | } 132 | callback(items); 133 | } 134 | $("#search-input").autocomplete(options, [ 135 | { 136 | name: "content", 137 | source: searchFuse, 138 | templates: { 139 | suggestion: (s) => { 140 | if (s.title == s.what) { 141 | return `${s.dir} >
    ${s.title}
    `; 142 | } else if (s.previous_headings == "") { 143 | return `${s.dir} >
    ${s.title}
    > ${s.what}`; 144 | } else { 145 | return `${s.dir} >
    ${s.title}
    > ${s.previous_headings} > ${s.what}`; 146 | } 147 | }, 148 | }, 149 | }, 150 | ]).on('autocomplete:selected', function(event, s) { 151 | window.location.href = s.path + "?q=" + q + "#" + s.id; 152 | }); 153 | }); 154 | })(window.jQuery || window.$) 155 | 156 | document.addEventListener('keydown', function(event) { 157 | // Check if the pressed key is '/' 158 | if (event.key === '/') { 159 | event.preventDefault(); // Prevent any default action associated with the '/' key 160 | document.getElementById('search-input').focus(); // Set focus to the search input 161 | } 162 | }); 163 | -------------------------------------------------------------------------------- /vignettes/client-usage.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Using the MCP Client" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Using the MCP Client} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>", 14 | eval = FALSE 15 | ) 16 | ``` 17 | 18 | ```{r setup} 19 | library(mcpr) 20 | ``` 21 | 22 | ## Introduction 23 | 24 | The `mcpr` package allows you to not only create Model Context Protocol (MCP) servers in R but also connect to existing MCP servers as a client. This vignette will guide you through using the MCP client to interact with servers. 25 | 26 | ## Creating an MCP Client 27 | 28 | The client functionality allows you to connect to any MCP server, whether it's running locally as a separate process, or remotely via HTTP. Here's how to create a client: 29 | 30 | ### Connecting to a Local Server Process 31 | 32 | You can connect to a server running as a separate process. This is useful for testing or when you need to communicate with a local MCP implementation: 33 | 34 | ```{r} 35 | # Create a client that connects to a local process 36 | client <- new_client( 37 | "Rscript", # Command to run 38 | "path/to/your/server.R", # Path to the server script 39 | name = "calculator", # Optional name for the server 40 | version = "1.0.0" # Optional version 41 | ) 42 | ``` 43 | 44 | ### Connecting to an HTTP Server 45 | 46 | You can also connect to an MCP server running over HTTP: 47 | 48 | ```{r} 49 | # Create a client that connects to an HTTP server 50 | http_client <- new_client("Rscript", "path/to/your/server.R") 51 | ``` 52 | 53 | ## Basic Client Operations 54 | 55 | Once you have created a client, you can interact with the server using the various client methods: 56 | 57 | ### Initializing the Connection 58 | 59 | It's good practice to initialize the connection first: 60 | 61 | ```{r} 62 | # Initialize the connection 63 | res <- initialize(client) 64 | print(res) 65 | ``` 66 | 67 | ### Listing Available Tools 68 | 69 | You can list all the tools that the server provides: 70 | 71 | ```{r} 72 | # Get a list of available tools 73 | tools <- tools_list(client) 74 | print(tools) 75 | ``` 76 | 77 | ### Calling a Tool 78 | 79 | Once you know what tools are available, you can call them with specific parameters: 80 | 81 | ```{r} 82 | # Call the math_calculator tool 83 | result <- tools_call( 84 | client, 85 | list( 86 | name = "math_calculator", 87 | params = list( 88 | name = "add", 89 | arguments = list( 90 | a = 10, 91 | b = 5 92 | ) 93 | ) 94 | ) 95 | ) 96 | print(result) 97 | ``` 98 | 99 | ### Working with Prompts 100 | 101 | If the server has prompts available, you can list and use them: 102 | 103 | ```{r} 104 | # List available prompts 105 | prompts <- prompts_list(client) 106 | print(prompts) 107 | 108 | # Get a specific prompt 109 | prompt <- prompts_get(client, "example-prompt") 110 | print(prompt) 111 | ``` 112 | 113 | ### Working with Resources 114 | 115 | You can also access resources provided by the server: 116 | 117 | ```{r} 118 | # List available resources 119 | resources <- resources_list(client) 120 | print(resources) 121 | 122 | # Read a specific resource 123 | resource_content <- resources_read(client, "example-resource") 124 | print(resource_content) 125 | ``` 126 | 127 | ## Complete Example 128 | 129 | Here's a complete example that demonstrates connecting to a calculator server and performing operations: 130 | 131 | ```{r} 132 | # Create a client 133 | client <- new_client( 134 | "Rscript", 135 | system.file("examples/calculator/server.R", package = "mcpr"), 136 | name = "calculator", 137 | version = "1.0.0" 138 | ) 139 | 140 | # Initialize the connection 141 | initialize(client) 142 | 143 | # List available tools 144 | tools <- tools_list(client) 145 | print(tools) 146 | 147 | # Call the math_calculator tool with different operations 148 | add_result <- tools_call( 149 | client, 150 | name = "math_calculator", 151 | params = list( 152 | operation = "add", 153 | a = 10, 154 | b = 5 155 | ) 156 | ) 157 | print(add_result) 158 | 159 | multiply_result <- tools_call( 160 | client, 161 | name = "math_calculator", 162 | params = list( 163 | operation = "multiply", 164 | a = 10, 165 | b = 5 166 | ) 167 | ) 168 | print(multiply_result) 169 | ``` 170 | 171 | ## Practical Use Cases 172 | 173 | MCP clients can be used in various scenarios: 174 | 175 | 1. **Integration with External AI Services**: Connect to AI models or services that expose an MCP interface 176 | 2. **Microservices Architecture**: Communicate between different R services using the MCP protocol 177 | 3. **Testing MCP Servers**: Verify that your MCP server implementations work correctly 178 | 4. **Building UI Applications**: Create user interfaces that interact with MCP servers to provide functionality 179 | 180 | ## Conclusion 181 | 182 | The MCP client functionality in the `mcpr` package provides a flexible way to interact with MCP servers from R. Whether you're building applications that consume AI capabilities or creating distributed systems that communicate via MCP, the client interface makes it easy to work with the protocol. 183 | 184 | For more advanced usage, check the function documentation and other vignettes. 185 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    39 | 40 |
    41 |

    Authors

    42 | 43 |
    • 44 |

      John Coene. Author, maintainer. 45 |

      46 |
    • 47 |
    • 48 |

      Opifex. Copyright holder, funder. 49 |

      50 |
    • 51 |
    52 | 53 |
    54 |

    Citation

    55 |

    Source: DESCRIPTION

    56 | 57 |

    Coene J (2025). 58 | mcpr: Model Context Protocol for R. 59 | R package version 0.0.2.9000, https://mcpr.opifex.org/. 60 |

    61 |
    @Manual{,
    62 |   title = {mcpr: Model Context Protocol for R},
    63 |   author = {John Coene},
    64 |   year = {2025},
    65 |   note = {R package version 0.0.2.9000},
    66 |   url = {https://mcpr.opifex.org/},
    67 | }
    68 |
    69 | 70 |
    72 | 73 | 74 |
    77 | 78 | 81 | 82 |
    83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | https://mcpr.opifex.org/404.html 3 | https://mcpr.opifex.org/LICENSE.html 4 | https://mcpr.opifex.org/articles/client-integration.html 5 | https://mcpr.opifex.org/articles/client-usage.html 6 | https://mcpr.opifex.org/articles/get-started.html 7 | https://mcpr.opifex.org/articles/index.html 8 | https://mcpr.opifex.org/articles/practical-examples.html 9 | https://mcpr.opifex.org/authors.html 10 | https://mcpr.opifex.org/index.html 11 | https://mcpr.opifex.org/news/index.html 12 | https://mcpr.opifex.org/reference/JSONRPC_PARSE_ERROR.html 13 | https://mcpr.opifex.org/reference/add_capability.html 14 | https://mcpr.opifex.org/reference/build_param_info.html 15 | https://mcpr.opifex.org/reference/client.html 16 | https://mcpr.opifex.org/reference/convert_ellmer_type_to_mcpr_property.html 17 | https://mcpr.opifex.org/reference/convert_ellmer_types_to_mcpr.html 18 | https://mcpr.opifex.org/reference/create_ellmer_handler.html 19 | https://mcpr.opifex.org/reference/create_ellmer_type.html 20 | https://mcpr.opifex.org/reference/create_ellmer_types.html 21 | https://mcpr.opifex.org/reference/create_error.html 22 | https://mcpr.opifex.org/reference/create_response.html 23 | https://mcpr.opifex.org/reference/ellmer_to_mcpr_tool.html 24 | https://mcpr.opifex.org/reference/extract_mcp_result.html 25 | https://mcpr.opifex.org/reference/from_json.html 26 | https://mcpr.opifex.org/reference/generate_handler_code.html 27 | https://mcpr.opifex.org/reference/generate_mcp_server.html 28 | https://mcpr.opifex.org/reference/generate_property_code.html 29 | https://mcpr.opifex.org/reference/generate_tool_code.html 30 | https://mcpr.opifex.org/reference/get_name.html 31 | https://mcpr.opifex.org/reference/index.html 32 | https://mcpr.opifex.org/reference/initialize.html 33 | https://mcpr.opifex.org/reference/mcp_roclet.html 34 | https://mcpr.opifex.org/reference/mcpr_clients_to_ellmer_tools.html 35 | https://mcpr.opifex.org/reference/mcpr_to_ellmer_tools.html 36 | https://mcpr.opifex.org/reference/new_client.html 37 | https://mcpr.opifex.org/reference/new_prompt.html 38 | https://mcpr.opifex.org/reference/new_property.html 39 | https://mcpr.opifex.org/reference/new_resource.html 40 | https://mcpr.opifex.org/reference/new_server.html 41 | https://mcpr.opifex.org/reference/new_tool.html 42 | https://mcpr.opifex.org/reference/parse_request.html 43 | https://mcpr.opifex.org/reference/process_batch.html 44 | https://mcpr.opifex.org/reference/process_mcp_block.html 45 | https://mcpr.opifex.org/reference/process_request.html 46 | https://mcpr.opifex.org/reference/prompts_get.html 47 | https://mcpr.opifex.org/reference/prompts_list.html 48 | https://mcpr.opifex.org/reference/properties.html 49 | https://mcpr.opifex.org/reference/property_array.html 50 | https://mcpr.opifex.org/reference/property_boolean.html 51 | https://mcpr.opifex.org/reference/property_enum.html 52 | https://mcpr.opifex.org/reference/property_number.html 53 | https://mcpr.opifex.org/reference/property_object.html 54 | https://mcpr.opifex.org/reference/property_string.html 55 | https://mcpr.opifex.org/reference/read.html 56 | https://mcpr.opifex.org/reference/register_mcpr_tools.html 57 | https://mcpr.opifex.org/reference/resources_list.html 58 | https://mcpr.opifex.org/reference/resources_read.html 59 | https://mcpr.opifex.org/reference/response.html 60 | https://mcpr.opifex.org/reference/roclet_output.roclet_mcp.html 61 | https://mcpr.opifex.org/reference/roclet_process.roclet_mcp.html 62 | https://mcpr.opifex.org/reference/roxy_tag_parse.roxy_tag_mcp.html 63 | https://mcpr.opifex.org/reference/roxy_tag_parse.roxy_tag_type.html 64 | https://mcpr.opifex.org/reference/roxy_tag_rd.roxy_tag_mcp.html 65 | https://mcpr.opifex.org/reference/roxy_tag_rd.roxy_tag_type.html 66 | https://mcpr.opifex.org/reference/schema.html 67 | https://mcpr.opifex.org/reference/serve_http.html 68 | https://mcpr.opifex.org/reference/serve_io.html 69 | https://mcpr.opifex.org/reference/to_json.html 70 | https://mcpr.opifex.org/reference/tools_call.html 71 | https://mcpr.opifex.org/reference/tools_list.html 72 | https://mcpr.opifex.org/reference/validate_request.html 73 | https://mcpr.opifex.org/reference/write.html 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/reference/JSONRPC_PARSE_ERROR.html: -------------------------------------------------------------------------------- 1 | 2 | JSON-RPC 2.0 Standard Error Codes — JSONRPC_PARSE_ERROR • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    JSON-RPC 2.0 Standard Error Codes

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    JSONRPC_PARSE_ERROR
    49 |
    50 | 51 |
    52 |

    Format

    53 |

    An object of class numeric of length 1.

    54 |
    55 | 56 |
    58 | 59 | 60 |
    63 | 64 | 67 | 68 |
    69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /vignettes/client-integration.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Integrating mcpr with MCP Clients" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Integrating mcpr with MCP Clients} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(mcpr) 19 | ``` 20 | 21 | ## Introduction 22 | 23 | The Model Context Protocol (MCP) allows you to register custom tools with various AI clients. This vignette demonstrates how to create a simple MCP server with `mcpr` and register it with popular clients including Claude Code, Cursor, OpenAI GPTs, and LangChain. 24 | 25 | ## Creating a Simple Math Calculator Server 26 | 27 | Let's create a simple MCP server with a basic calculator tool: 28 | 29 | ```r 30 | # Create a new MCP server 31 | math_server <- new_server( 32 | name = "r-calculator", 33 | description = "A simple calculator that performs basic arithmetic operations", 34 | version = "1.0.0" 35 | ) 36 | 37 | # Create a calculator tool 38 | calculator <- new_tool( 39 | name = "math_calculator", 40 | description = "Performs basic arithmetic operations", 41 | input_schema = schema( 42 | properties = properties( 43 | operation = property_enum( 44 | "Operation", 45 | "Math operation to perform", 46 | enum = c("add", "subtract", "multiply", "divide"), 47 | required = TRUE 48 | ), 49 | a = property_number("First number", "First operand", required = TRUE), 50 | b = property_number("Second number", "Second operand", required = TRUE) 51 | ) 52 | ), 53 | handler = function(input) { 54 | result <- switch(input$operation, 55 | "add" = input$a + input$b, 56 | "subtract" = input$a - input$b, 57 | "multiply" = input$a * input$b, 58 | "divide" = input$a / input$b 59 | ) 60 | response_text(paste("Result:", result)) 61 | } 62 | ) 63 | 64 | # Add the tool to the server 65 | math_server <- add_capability(math_server, calculator) 66 | ``` 67 | 68 | Save this code to a file, for example `calculator_server.R`, and add code to serve it at the end: 69 | 70 | ```r 71 | # At the end of calculator_server.R, add: 72 | serve_io(math_server) 73 | ``` 74 | 75 | ## Registering with MCP Clients 76 | 77 | ### Claude Code 78 | 79 | Claude Code supports registering MCP tools using the `claude mcp` command: 80 | 81 | ```bash 82 | # Register the MCP server 83 | claude mcp add r-calculator -- Rscript /path/to/calculator_server.R 84 | 85 | # List registered MCP servers 86 | claude mcp list 87 | 88 | # Use the registered tool 89 | claude "Add 2 to 40" 90 | ``` 91 | 92 | Claude will automatically discover and use the registered MCP server's capabilities. 93 | 94 | ### Cursor 95 | 96 | Cursor supports registering MCP tools via its configuration: 97 | 98 | 1. Open Cursor settings 99 | 2. Navigate to the "Tools" section 100 | 3. Add a new tool with: 101 | - Name: r-calculator 102 | - Command: Rscript /path/to/calculator_server.R 103 | 4. Save the settings 104 | 105 | Now when you ask Cursor to perform calculations, it will have access to your MCP tool. 106 | 107 | ### OpenAI GPT 108 | 109 | For OpenAI GPTs, you'll need to run your MCP server over HTTP: 110 | 111 | ```r 112 | # Modify your calculator_server.R to use HTTP instead of IO 113 | serve_http(math_server, port = 8080) 114 | ``` 115 | 116 | Then register it with a custom GPT: 117 | 118 | 1. Create a custom GPT in the GPT Builder 119 | 2. In the "Configure" tab, add an "Action" 120 | 3. Set the Authentication to "None" 121 | 4. Set the API URL to your server (e.g., http://localhost:8080) 122 | 5. Import schema from URL: http://localhost:8080/openapi.json 123 | 6. Save your GPT 124 | 125 | Your custom GPT will now be able to use your MCP calculator. 126 | 127 | ### LangChain 128 | 129 | LangChain provides adapters specifically for MCP integration: 130 | 131 | ```python 132 | from langchain_mcp_adapters.client import MultiServerMCPClient 133 | from langchain.agents import create_tool_calling_agent 134 | from langchain_openai import ChatOpenAI 135 | 136 | # Connect to your R-based MCP server 137 | # You need to run your server with serve_http for this approach 138 | mcp_client = MultiServerMCPClient( 139 | servers=[{"url": "http://localhost:8080"}] 140 | ) 141 | 142 | # Get tools from the MCP server 143 | tools = mcp_client.get_tools() 144 | 145 | # Create a LangChain agent with the MCP tools 146 | llm = ChatOpenAI(model="gpt-4o") 147 | agent = create_tool_calling_agent(llm, tools) 148 | 149 | # Use the agent 150 | response = agent.invoke({"input": "What is 10 multiplied by 5?"}) 151 | print(response["output"]) 152 | ``` 153 | 154 | Alternatively, you can use the process-based approach: 155 | 156 | ```python 157 | from langchain_mcp_adapters.client import MultiServerMCPClient 158 | from langchain.agents import create_tool_calling_agent 159 | from langchain_openai import ChatOpenAI 160 | 161 | # Connect to your R-based MCP server using process 162 | mcp_client = MultiServerMCPClient( 163 | servers=[{"command": ["Rscript", "/path/to/calculator_server.R"]}] 164 | ) 165 | 166 | # The rest is the same as above 167 | tools = mcp_client.get_tools() 168 | llm = ChatOpenAI(model="gpt-4o") 169 | agent = create_tool_calling_agent(llm, tools) 170 | ``` 171 | 172 | ## Conclusion 173 | 174 | With `mcpr`, you can create MCP servers that register seamlessly with various AI clients. This enables AI tools to leverage R's statistical and data processing capabilities. 175 | 176 | For more advanced usage, consider: 177 | 178 | 1. Adding multiple tools to your server 179 | 2. Creating resources to serve data 180 | 3. Implementing prompts for text generation 181 | 4. Handling more complex data types in your tools 182 | 183 | See the other vignettes and function documentation for more details on these advanced features. 184 | -------------------------------------------------------------------------------- /docs/reference/get_name.html: -------------------------------------------------------------------------------- 1 | 2 | Get the name of a client — get_name • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Get the name of a client

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    get_name(x)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    x
    56 |

    A client object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    The name of the client

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/tools_list.html: -------------------------------------------------------------------------------- 1 | 2 | List all available tools — tools_list • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    List all available tools

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    tools_list(mcp)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    mcp
    56 |

    A server object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    A list containing all available tools

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/roxy_tag_parse.roxy_tag_mcp.html: -------------------------------------------------------------------------------- 1 | 2 | Parse @mcp tag — roxy_tag_parse.roxy_tag_mcp • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Parses @mcp tags to extract tool name and description.

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    # S3 method for class 'roxy_tag_mcp'
    49 | roxy_tag_parse(x)
    50 |
    51 | 52 |
    53 |

    Arguments

    54 | 55 | 56 |
    x
    57 |

    A roxy_tag object

    58 | 59 |
    60 | 61 |
    63 | 64 | 65 |
    68 | 69 | 72 | 73 |
    74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/reference/prompts_list.html: -------------------------------------------------------------------------------- 1 | 2 | List all available prompts — prompts_list • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    List all available prompts

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    prompts_list(mcp)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    mcp
    56 |

    A server object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    A list containing all available prompts

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/resources_list.html: -------------------------------------------------------------------------------- 1 | 2 | List all available resources — resources_list • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    List all available resources

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    resources_list(mcp)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    mcp
    56 |

    A server object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    A list containing all available resources

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/validate_request.html: -------------------------------------------------------------------------------- 1 | 2 | Validate a JSON-RPC 2.0 request — validate_request • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Validate a JSON-RPC 2.0 request

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    validate_request(request)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    request
    56 |

    Parsed request object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    NULL if valid, error response if invalid

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/process_mcp_block.html: -------------------------------------------------------------------------------- 1 | 2 | Process a single block with @mcp tag — process_mcp_block • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Process a single block with @mcp tag

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    process_mcp_block(block)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    block
    56 |

    A roxy_block object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    A list with tool information or NULL

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/serve_io.html: -------------------------------------------------------------------------------- 1 | 2 | Serve an MCP server using stdin/stdout — serve_io • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Serve an MCP server using stdin/stdout

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    serve_io(mcp)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    mcp
    56 |

    An MCP server object created with new_server()

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    Nothing, runs indefinitely in normal mode, or the response in test mode

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/generate_property_code.html: -------------------------------------------------------------------------------- 1 | 2 | Generate property code for a parameter — generate_property_code • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Generate property code for a parameter

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    generate_property_code(param)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    param
    56 |

    Parameter information

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    Character string with property code

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/roxy_tag_parse.roxy_tag_type.html: -------------------------------------------------------------------------------- 1 | 2 | Parse @type tag — roxy_tag_parse.roxy_tag_type • mcpr 5 | Skip to contents 6 | 7 | 8 |
    37 |
    38 |
    43 | 44 |
    45 |

    Parses @type tags to extract parameter type information. 46 | Format: @type param_name type enum_values

    47 |
    48 | 49 |
    50 |

    Usage

    51 |
    # S3 method for class 'roxy_tag_type'
    52 | roxy_tag_parse(x)
    53 |
    54 | 55 |
    56 |

    Arguments

    57 | 58 | 59 |
    x
    60 |

    A roxy_tag object

    61 | 62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/initialize.html: -------------------------------------------------------------------------------- 1 | 2 | Initialize the server with protocol information — initialize • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Initialize the server with protocol information

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    initialize(mcp)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    mcp
    56 |

    A server object

    57 | 58 |
    59 |
    60 |

    Value

    61 |

    A list containing protocol version, server info, and capabilities

    62 |
    63 | 64 |
    66 | 67 | 68 |
    71 | 72 | 75 | 76 |
    77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/reference/from_json.html: -------------------------------------------------------------------------------- 1 | 2 | Parse JSON to an R object — from_json • mcpr 3 | Skip to contents 4 | 5 | 6 |
    35 |
    36 |
    41 | 42 |
    43 |

    Parse JSON to an R object

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    from_json(json, ...)
    49 |
    50 | 51 |
    52 |

    Arguments

    53 | 54 | 55 |
    json
    56 |

    JSON string to parse

    57 | 58 | 59 |
    ...
    60 |

    Additional arguments passed to yyjsonr::read_json_str

    61 | 62 |
    63 |
    64 |

    Value

    65 |

    R object

    66 |
    67 | 68 |
    70 | 71 | 72 |
    81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | --------------------------------------------------------------------------------