relative-interpreter-mcp
# Relative — MCP Interpreter
An [MCP](https://modelcontextprotocol.io) server that lets an LLM (Claude Code,
Claude Desktop, any MCP host) act as a third **interpreter** for the
[Relative](https://github.com/calwtr/relative) service — alongside
`relative-interpreter-list` and `relative-interpreter-graph`, which are browser
UIs for a human. This one exposes a model as tools instead of buttons.
See [`DESIGN.md`](./DESIGN.md) for why it is shaped the way it is.
## Run
```sh
npm install
RELATIVE_SERVICE_URL=http://localhost:4000/api npm start
```
Needs a running `relative` service (see that repo's `README.md`).
`RELATIVE_SERVICE_URL` defaults to `http://localhost:4000/api`.
Register it as a local stdio server. For Claude Code, in `.mcp.json`:
```json
{
"mcpServers": {
"relative": {
"command": "npx",
"args": ["tsx", "/path/to/relative-interpreter-mcp/src/main.ts"],
"env": { "RELATIVE_SERVICE_URL": "http://localhost:4000/api" }
}
}
}
```
## What it gives the model
**Reads return a compact outline, not JSON** — names as identifiers, links as
arrows, submodels summarised to a line:
```
Model "Switch Circuit" · 4 nodes, 3 links, 1 view · rev 0
Scope: (root)
Nodes:
battery const boolean = true out out:boolean
switch var boolean = false in in:boolean out out:boolean
circuit fn python runtimes/python/examples/circuit.py [onUpdate] in powered:boolean,closed:boolean out lit:boolean
bulb var boolean = false in in:boolean out out:boolean
Links:
battery.out -> circuit.powered [power flow] battery powers circuit
switch.out -> circuit.closed [power flow] switch closes circuit
circuit.lit -> bulb.in [power flow] circuit lights bulb
Views:
power flow (3 links)
```
**One `edit_model` tool takes many steps**, applied as a single undoable
operation via the service's `/batch` endpoint, with later steps able to
reference what earlier ones create:
```jsonc
{ "steps": [
{ "action": "addValueNode", "input": { "name": "Switch", "mutability": "variable",
"initialValue": { "type": "boolean", "value": false } } },
{ "action": "addValueNode", "input": { "name": "Bulb", "mutability": "variable",
"initialValue": { "type": "boolean", "value": false } } },
{ "action": "addView", "input": { "name": "Power" } },
{ "action": "addLinkWithEndpoints", "input": { "name": "sw-to-bulb",
"endpointA": "Switch.out", "endpointB": "Bulb.in",
"direction": "forward", "views": ["Power"] } }
] }
```
**References are names, and bad ones are refused.** The service's state layer
is total, so a mutation aimed at something that does not exist silently
succeeds; every reference is resolved and checked here first:
```
Step 1 (updateNode): No node "NoSuchNode" in this scope.
Available: Switch#4e64975c, Bulb#159d3b8a
```
Names are not unique in Relative, so an ambiguous one is an error offering
`name#uuidprefix` handles — the same handles reads print.
**Staleness is reported, not assumed.** The server consumes the service's SSE
stream, pushes `resources/updated` to subscribed hosts, and prefixes any read
whose revision moved since the caller last saw it:
```
[changed outside this conversation since you last looked: rev 3 -> 4,
views 0->1. The view below is current.]
```
## Tools
| Group | Tools |
|---|---|
| Navigation | `list_models`, `select_model`, `create_model`, `import_model`, `delete_model`, `get_scope`, `enter_submodel`, `exit_submodel` |
| Read | `get_model`, `get_element`, `get_validation`, `get_script_source` |
| Edit | `edit_model`, `link_external_submodel` |
| Execution & history | `run_node`, `undo`, `redo`, `list_snapshots`, `save_snapshot`, `restore_snapshot` |
Resources: `relative://models`, `relative://models/{id}` (subscribable).
TDQS
Scored across 20 tools
Each tool targets a distinct resource and operation: scope management (get_scope, enter_submodel, exit_submodel), model inspection at different granularities (get_model, get_element, get_script_source), model lifecycle (create, select, import, delete, list), editing and execution (edit_model, run_node), validation, snapshots, and undo/redo. No overlapping purposes.
All tools follow a consistent verb_noun snake_case pattern, with plural nouns for list operations (list_models, list_snapshots) and clear imperative verbs. The only exceptions are undo and redo, which are universally accepted single verbs.
With 20 tools, the set is on the heavier side but remains justified by the complexity of a model interpreter. Each tool has a clear role, and no redundant or trivial tools are present.
The core workflow is well-covered: model lifecycle, editing, navigation, validation, execution, and snapshots. Minor gaps exist—such as missing export_model and delete_snapshot—but agents can work around these with existing operations.