Skip to content

MCP resource as a dataset source

When to use this

  • Existing MCP servers you already have. If you maintain a team runbook server, a docs server, or any other MCP-compatible server, wiring it as a dataset source lets your flow reuse it without wrapping it in a custom tool.
  • MCP beats HTTP dataset when the content lives behind a server that already speaks the MCP resources/read protocol — you avoid a round-trip auth layer and get URI-addressed access for free.
  • MCP beats a custom tool when you want to keep the data-access logic in a language- or framework-agnostic server that other clients (Claude Code, Cursor) can also connect to.

Setup: mcp.json

Create mcp.json next to experience.yaml. The shape is identical to Claude Desktop and Cursor — if you already have an mcp.json for those tools you can copy it here unchanged.

json
{
  "servers": {
    "runbooks": {
      "command": "node",
      "args": ["./mcp-servers/runbooks.mjs"],
      "env": { "RUNBOOKS_DIR": "./data" }
    },
    "company-docs": {
      "command": "uvx",
      "args": ["@example/mcp-company-docs"]
    }
  }
}

The top-level keys (runbooks, company-docs) are the server names referenced by dataset nodes. command + args is the stdio spawn command; env is merged into the child process environment.

The dataset node

Reference a server by name and provide an MCP resource URI:

yaml
nodes:
  - id: load_runbooks
    kind: dataset
    source:
      type: mcp-resource
      server: 'runbooks'
      uri: 'runbooks://incident-response/payments'
    writes: [runbooks]

server must match a key in mcp.json. uri is passed verbatim to the server's resources/read RPC. The runbooks state field will contain the normalized rows (see below).

How rows are normalized

The dispatcher converts whatever the server returns into a uniform array of objects:

Server responseRows written to state
JSON arraySpread as-is — each element becomes one row
JSON objectWrapped in a 1-element array: [{ ...object }]
Plain text[{ text: "<the text>" }]
Blob (base64)[{ blob: "<base64>", mimeType: "<type>" }]

Downstream nodes receive a consistent array regardless of server response format. An agent node reading runbooks can always iterate over $.runbooks as an array.

When the server fails

The dispatcher emits one of five error messages. Each appears in the event log (oe inspect) and causes the node to enter the failed state unless the node declares on_error:

  • mcp.json not found — no mcp.json exists next to experience.yaml. Fix: create the file at the experience root.
  • unknown server "<name>" — the server: value in the dataset node does not match any key in mcp.json. Fix: check spelling; keys are case-sensitive.
  • spawn failure: <details> — the command could not be launched (not on PATH, permission denied, missing runtime). Fix: verify the command runs outside OE; check env entries.
  • init failure: <details> — the server process started but did not complete the MCP initialization handshake. Fix: inspect the server's stderr output with DEBUG=oe:mcp oe run.
  • read failure: <uri> — <details> — the server responded to init but returned an error for the specific resources/read call. Fix: confirm the URI is valid for that server; check server logs.

Variations

  • Multiple MCP servers in one flow. Declare both in mcp.json and add a separate kind: dataset node for each server. The runtime spawns each server process once and reuses the connection for all dataset nodes that reference it within the same run.
  • Paginated resources. MCP servers that return paginated resources currently require one dataset node per URI. Full pagination support (cursor-based iteration) is on the post-0.2 roadmap.
  • HTTP transport. Stdio is the only supported transport in 0.1.x. HTTP transport for remote MCP servers is planned for 0.2.x.

Limits in 0.1.x

Be aware of the following constraints in the current release:

  • Stdio only. There is no HTTP or WebSocket MCP transport. The command field is required; there is no url field yet.
  • No streaming resources. The resources/read call is a single request-response. MCP streaming resource subscriptions are not supported.
  • One URI per node. Each kind: dataset node reads one URI. To read multiple URIs from the same server, add multiple dataset nodes.

See also

Released under the MIT License.