Skip to contents

mcp_server() runs a Model Context Protocol server over standard input and output. It exposes tools created with mcplite::tool() so MCP clients can discover and call R functions. Compatible ellmer::tool() objects can also be supplied when users already use ellmer, but ellmer is not required for ordinary mcplite tools.

Usage

mcp_server(tools, instructions = NULL)

Arguments

tools

Tool definitions to expose. Supply one mcplite::tool() object or a list of tool definitions. Compatible ellmer::tool() objects are accepted when supplied directly.

instructions

Optional server instructions to advertise to clients that negotiate a protocol version that supports them.

Value

mcp_server() is called for its side effect of serving MCP requests. It blocks the current R process until standard input closes.

Details

mcplite supports the lifecycle, ping, tools/list, and tools/call subset for protocol versions 2024-11-05, 2025-06-18, and 2025-11-25. Tools may return ordinary R values for legacy text conversion or opt into native content and structured output with tool_result(). Structured output, output schemas, audio, resource links, and per-content metadata require MCP 2025-06-18 or later. Text, images, embedded resources, annotations, and result metadata also work with 2024-11-05.

The server does not implement JSON-RPC batching, HTTP transports, sessions, prompts, resource listing or reading, sampling, elicitation, roots, tasks, progress notifications, or server-initiated requests. Embedded resource blocks are self-contained, and resource links do not make their URIs readable through mcplite.

Supply tool definitions directly. For client-launched workflows, put the complete server setup in a script that defines or sources tools and ends with mcplite::mcp_server(actual_tool_or_list), then launch that script with Rscript --vanilla /absolute/path/to/server.R.

OpenTelemetry tracing

mcplite automatically creates one OpenTelemetry server span for every parsed MCP request or notification that passes JSON-RPC envelope validation. This includes initialization and notifications, ping, tool discovery and calls, and valid unknown methods. Blank input, JSON parse failures, and malformed JSON-RPC envelopes do not create MCP operation spans.

Tool authors do not need to call otel::start_local_active_span() for the MCP operation or tool invocation. The server span remains active while tool code runs, so optional tool-authored spans can become children without being required. mcplite does not create a redundant automatic tool-execution child span.

Provider and exporter configuration belongs to the standard otel and otelsdk environment variables and APIs. mcplite does not add telemetry arguments, choose an exporter, or configure a provider. With no exporter configured, tracing is an effective no-op and MCP behavior is unchanged. A safe stderr configuration is OTEL_R_TRACES_EXPORTER=stderr Rscript --vanilla /absolute/path/to/server.R; a remote exporter such as OTLP is also suitable.

Do not use a stdout or console exporter with a stdio MCP server. Standard output is reserved exclusively for MCP protocol messages, so telemetry written there will corrupt the protocol stream.

Remote W3C parent context may be supplied in params._meta.traceparent, with optional params._meta.tracestate. Malformed propagation data is ignored, and _meta is not passed to tool functions. By default, spans contain selected low-cardinality operation metadata; raw requests and responses, tool arguments and results, _meta, trace headers, and condition messages are not recorded as span attributes.

Examples

if (identical(Sys.getenv("MCPLITE_CAN_BLOCK_PROCESS"), "true")) {
  add_numbers <- tool(
    function(x, y) {
      x + y
    },
    name = "add_numbers",
    description = "Add two numbers and return the result.",
    arguments = list(
      x = type_number("First number."),
      y = type_number("Second number.")
    )
  )

  mcp_server(list(add_numbers))
}