DataStep Studio for R Install
Documentation · version 0.10.3

Set up an agent

Claude Code, Codex, Cursor, Copilot or your own agent: the MCP server or the dsr command, and what each result says.

On this page
Agents
  1. Connect through MCP
  2. Connect through the command line
  3. The working method
  4. What a tool gives back
  5. Debugging live: a stop that waits
  6. Long runs, cancel, several sessions
  7. When something does not work
  8. Tests of this surface

An AI agent works in the same live R session as the person: through the dsr command, or through the MCP server bin/dsr-mcp.js that gives the same tools as typed MCP tools. The person sees every run, log and stop in the editor.

Below, <dsr> is the folder of DataStep Studio for R (the extension's folder, or a clone of this repository) and <project> is the R project. dsr doctor (or the MCP tool dsr_doctor) prints both paths and checks the machine.

Connect through MCP

The server speaks MCP over stdio. It works in the folder named by DSR_ROOT (else the folder it starts in). In the editor, DataStep R: Set Up Agent Tools writes .mcp.json and .vscode/mcp.json for the open project.

Claude Code (tried with Claude Code 2.1):

cd <project>
claude mcp add --scope project dsr -e DSR_ROOT=<project> -- node <dsr>/bin/dsr-mcp.js

It writes .mcp.json in the project; Claude Code asks once to approve it. Without --scope project it is for you only. The file it writes:

{
  "mcpServers": {
    "dsr": {
      "type": "stdio",
      "command": "node",
      "args": ["<dsr>/bin/dsr-mcp.js"],
      "env": { "DSR_ROOT": "<project>" }
    }
  }
}

Codex CLI (tried with codex-cli 0.159):

codex mcp add dsr --env DSR_ROOT=<project> -- node <dsr>/bin/dsr-mcp.js

It adds to ~/.codex/config.toml:

[mcp_servers.dsr]
command = "node"
args = ["<dsr>/bin/dsr-mcp.js"]

[mcp_servers.dsr.env]
DSR_ROOT = "<project>"

Cursor (tried with cursor-agent in round 1: cursor-agent mcp list-tools dsr listed the tools; there are 46 now): .cursor/mcp.json in the project, or ~/.cursor/mcp.json:

{
  "mcpServers": {
    "dsr": { "command": "node", "args": ["<dsr>/bin/dsr-mcp.js"], "env": { "DSR_ROOT": "<project>" } }
  }
}

VS Code (Copilot agent mode): .vscode/mcp.json, as Set Up Agent Tools writes it (VS Code's documented form; not tried with Copilot here):

{
  "servers": {
    "dsr": { "type": "stdio", "command": "node", "args": ["<dsr>/bin/dsr-mcp.js"], "env": { "DSR_ROOT": "<project>" } }
  }
}

Any other MCP client: the command is node <dsr>/bin/dsr-mcp.js with DSR_ROOT=<project>. Use one server per project, or one server and the root argument that every tool takes.

Connect through the command line

An agent with a shell needs no MCP: put <dsr>/bin on its PATH (the editor does this in its terminals) and let it read dsr guide once. dsr tools lists the tools, dsr help <tool> explains one.

The working method

dsr guide (MCP: dsr_guide) is the method on one page: the goal as a fact, look, lint, run, read the verdict, find the cause with the tools, the smallest fix, then batch and tests. dsr guide --full adds which tool answers which question. The MCP server's instructions carry the short form.

What a tool gives back

Every CLI tool takes --json and then prints one JSON object. Every MCP tool returns the same object as structuredContent (each tool declares it as its outputSchema) and the text in content.

Field
schema "dsr/1"
tool the tool's name (run, query, ...)
exit the exit code, below
ok exit is 0
verdict the verdict word: CLEAN, CHECK, ERROR, PRY (the run waits at a stop), STOPPED (a run ended at its stop), PASS, FAIL, MATCH, OK, RUNNING, REFUSED (format: the proof failed), ...
summary the verdict line, e.g. RESULT: ERROR | FIRST CAUSE: prog.R:5: n_obese == 2 is not TRUE
fix what to do next when dsr knows it (dsr start, an install command, dsr help run), else null
text what the tool printed, as a person reads it
truncated, more the text was cut; more is the call for the rest (dsr more --from 401)
data the tool's own result as data, e.g. run: events (each message with its line), workspace (new, changed, removed objects), suspicious (each message that matters with its rule, line, why, fix), at a stop live, reason, stop (the frame, its code, its objects); data: columns and rows (column -> values); query: rows as display text (hidden characters visible); complete: items (label, kind, detail), signature; format: per file its proof (tokens, comments, program, first difference); coverage: per file lines with n, never; test: per_file, details

Exit codes:

Code Meaning What the agent does
0 the tool did its work and it went well go on
1 the tool says it did not go well: RESULT: ERROR, TESTS FAIL, LINT: PROBLEMS, GATE FAIL, ... read the FIRST CAUSE
2 the call was wrong, or there is no session read fix (dsr start, dsr help <tool>)
3 still running after --timeout dsr wait --timeout 600, then dsr log; or dsr stop

In MCP, isError is true for 1 and 2. A call that still runs (3) is no error. dsr status answers 1 when no session runs (its fix is dsr start).

Debugging live: a stop that waits

dsr run <program> --stop-at FILE:LINE (repeat it; 'FILE:LINE if <condition>'; --stop-on-warning), a pry() in the program and a breakpoint of the editor stop the run and keep it alive: the answer is RESULT: PRY with where it stopped, and the session goes on answering (dsr pry ls, dsr pry eval, the data tools on @pry:<object>). Then:

Command (MCP dsr_pry command) What happens
dsr pry next [n] (next, frame: n) the next line of this frame (or of the frame it returns to)
dsr pry step the next line anywhere: into a function of the project this line calls
dsr pry finish the first line after this frame returns
dsr pry continue to the next stop, or to the end of the run with its verdict
dsr pry quit ends the run here: RESULT: STOPPED (a new dsr run, or dsr stop, does the same)
dsr pry break 'R/f.R:12 if x > 3' (target) one more stop
dsr pry watch 'x' (target) stop at the line after x changes; unwatch
dsr pry source <fn>, run <file.R>, pipe [line] a function's code with file:line; code run in the frame; the pipeline at the stop step by step on the frame's data

Each of next, step, finish, continue, quit answers at the next stop or at the end of the run, with the log since the last answer (in JSON: events; the final answer has sent, the number of events shown before). dsr run <program> --coverage, then dsr coverage [file]: which lines ran, how often, which never ran.

Long runs, cancel, several sessions

When something does not work

Tests of this surface

npm run test:cli (with DSR_TEST_LIB=<an R library with httpuv, evaluate, jsonlite, testthat>) runs the CLI contract and an MCP scenario over stdio: start, a program with a deliberate error, the log, a stop at the wrong line with pry, the fix, the tests, a cancel, the end. It needs no editor.