Skip to main content
Glama
CalWtr

relative-interpreter-mcp

by CalWtr
README.md
# 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

B3.4/5.0

Scored across 20 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count4/5

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.

Completeness4/5

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.

Maintenance

ActivityMaintained
ResponsivenessSyncing