MCP Tool Reference

BondGraph MCP server

The BondGraph Studio MCP server lives at https://xn--lda.se/api/mcp. It is a JSON-RPC 2.0 endpoint that speaks the MCP Streamable HTTP transport. Every POST must include both headers:

Content-Type: application/json
Accept: application/json, text/event-stream

All ten tools below take JSON arguments and return a single text content item whose text field is a JSON string. The envelope is always:

{
  "jsonrpc": "2.0",
  "id": <your id>,
  "result": {
    "content": [
      { "type": "text", "text": "<JSON string — see each tool below>" }
    ]
  }
}

Decode the content[0].text field with JSON.parse (or jq -r '.result.content[0].text' on the command line) to get the structured payload shown in the response examples below.

Handshake

Every MCP host runs initialize and tools/list first:

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-06-18",
                 "capabilities":{},
                 "clientInfo":{"name":"curl","version":"1"}}}'

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

A complete round trip

The exchange below is the full, literal wire traffic for one tool call — request headers, request body, response headers and response body — so you can reproduce it byte for byte.

Request

POST /api/mcp HTTP/1.1
Host: xn--lda.se
Content-Type: application/json
Accept: application/json, text/event-stream

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": {
    "name": "validate_bgif",
    "arguments": {
      "bgif": { "bgifVersion": "1.0.0", "components": [], "systems": [] }
    }
  }
}

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: *

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"valid\":true,\"modelId\":\"empty\",\"modelName\":\"Untitled\",\"elementCount\":0,\"bondCount\":0,\"subsystemCount\":0}"
      }
    ]
  }
}

Decoded payload

{
  "valid": true,
  "modelId": "empty",
  "modelName": "Untitled",
  "elementCount": 0,
  "bondCount": 0,
  "subsystemCount": 0
}

Batching and notifications

The endpoint accepts a JSON array of requests and answers with an array of the responses that have an id. Requests without an id are notifications: they are executed and produce no response object. If a whole batch consists of notifications the server replies 202 Accepted with an empty body.

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '[{"jsonrpc":"2.0","id":1,"method":"ping"},
       {"jsonrpc":"2.0","id":2,"method":"tools/list"}]'

Error codes

Two different failure channels exist, and a correct client checks both.

1. Protocol errors — error instead of result

The request never reached a tool. The response carries no result field at all:

{
  "jsonrpc": "2.0",
  "id": 7,
  "error": {
    "code": -32602,
    "message": "Unknown tool: simulat"
  }
}
CodeHTTPMeaningHow to fix
-32700400Parse error — the body was not valid JSON.Check quoting/escaping; send Content-Type: application/json.
-32600200Invalid Request — no method field.Send a well-formed JSON-RPC 2.0 object.
-32601200Method not found — unsupported JSON-RPC method.Only initialize, notifications/initialized, ping, tools/list and tools/call exist.
-32602200Invalid params — params.name is not a known tool.Call tools/list and use an exact tool name.
-32000405Method not allowed — you used GET or DELETE.All MCP traffic is POST. OPTIONS returns 204 for CORS preflight.

2. Tool errors — result.isError

The tool ran and threw (bad BGIF, unreachable URL, a solver failure). This is HTTP 200 with a normal result, flagged with isError: true and a plain-text message rather than a JSON payload:

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "content": [
      { "type": "text", "text": "bond references unknown element id \"R7\"" }
    ],
    "isError": true
  }
}

A third, softer channel exists inside the payload itself: several tools (validate_bgif, validate_library, validate_scene, check_units) report expected, non-exceptional problems as {"valid": false, "error": "…"} or a warnings array in an otherwise successful result. Treat those as data, not failures.

Checklist for a robust client: non-2xx HTTP → transport problem; body.error → protocol problem; body.result.isError → tool threw; otherwise JSON.parse(body.result.content[0].text) and inspect valid / warnings.

Machine-readable schemas (type generation)

Every tool publishes a JSON Schema 2020-12 pair — request input and response output — in one self-contained bundle, together with the JSON-RPC envelope and the error-code table above:

curl -sS https://xn--lda.se/api/public/mcp-schema.json

Add ?tool=simulate to fetch a single tool (plus the shared $defs and error codes). Structured tools also return their outputSchema inline from tools/list, so MCP hosts that support structured output pick it up automatically.

{
  "tools": {
    "simulate": {
      "name": "simulate",
      "input":  { "type": "object", "required": ["bgif"], "properties": { … } },
      "output": { "type": "object", "required": ["status", "time", "variables", "meta"], … },
      "resultEncoding": "json",
      "resultPath": "result.content[0].text"
    }
  },
  "errorCodes": [ { "code": -32602, "name": "InvalidParams", "http": 200, … } ],
  "$defs": { "JsonRpcRequest": …, "JsonRpcResponse": …, "ToolResult": … }
}

resultEncoding tells a generator how to decode result.content[0].text: "json" for structured payloads, "text" for raw documents such as render_svg’s SVG. Generate types with any standard tool:

# TypeScript
curl -sS https://xn--lda.se/api/public/mcp-schema.json?tool=simulate \
  | npx json-schema-to-typescript > simulate.d.ts

# Python
curl -sS https://xn--lda.se/api/public/mcp-schema.json?tool=simulate \
  | datamodel-codegen --input-file-type jsonschema --output simulate.py

Minimal working client

About thirty lines is enough to talk to every tool on this page — no MCP SDK required.

TypeScript / JavaScript (fetch)

const ENDPOINT = "https://xn--lda.se/api/mcp";
let nextId = 1;

async function rpc(method: string, params?: unknown) {
  const res = await fetch(ENDPOINT, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json, text/event-stream",
    },
    body: JSON.stringify({ jsonrpc: "2.0", id: nextId++, method, params }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status} ${await res.text()}`);
  const body = await res.json();
  if (body.error) throw new Error(`${body.error.code}: ${body.error.message}`);
  return body.result;
}

/** Call a tool and return its decoded JSON payload. */
async function callTool(name: string, args: Record<string, unknown> = {}) {
  const result = await rpc("tools/call", { name, arguments: args });
  const text = result.content?.[0]?.text ?? "";
  if (result.isError) throw new Error(`${name} failed: ${text}`);
  try {
    return JSON.parse(text);
  } catch {
    return text; // render_svg and export_* return raw text, not JSON
  }
}

// --- usage -------------------------------------------------------------
await rpc("initialize", {
  protocolVersion: "2025-06-18",
  capabilities: {},
  clientInfo: { name: "my-client", version: "1.0.0" },
});

const { tools } = await rpc("tools/list");
console.log(tools.map((t: { name: string }) => t.name));

const { bgif } = await callTool("get_example", { name: "RLC Circuit" });
const run = await callTool("simulate", {
  bgif,
  config: { endTime: 5, stepSize: 0.01, solver: "bdf2" },
  format: "compact",
});
console.log(run.meta.sampleCount, Object.keys(run.variables));

Python (standard library only)

import json, itertools, urllib.request

ENDPOINT = "https://xn--lda.se/api/mcp"
_ids = itertools.count(1)

def rpc(method, params=None):
    payload = {"jsonrpc": "2.0", "id": next(_ids), "method": method}
    if params is not None:
        payload["params"] = params
    req = urllib.request.Request(
        ENDPOINT,
        data=json.dumps(payload).encode(),
        headers={
            "Content-Type": "application/json",
            "Accept": "application/json, text/event-stream",
        },
    )
    with urllib.request.urlopen(req) as res:
        body = json.load(res)
    if "error" in body:
        raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
    return body["result"]

def call_tool(name, **args):
    result = rpc("tools/call", {"name": name, "arguments": args})
    text = result["content"][0]["text"]
    if result.get("isError"):
        raise RuntimeError(f"{name} failed: {text}")
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return text

rpc("initialize", {"protocolVersion": "2025-06-18", "capabilities": {},
                   "clientInfo": {"name": "py", "version": "1.0.0"}})
print([t["name"] for t in rpc("tools/list")["tools"]])

model = call_tool("get_example", name="RLC Circuit")["bgif"]
run = call_tool("simulate", bgif=model,
                config={"endTime": 5, "stepSize": 0.01, "solver": "bdf2"},
                format="compact")
print(run["meta"]["sampleCount"], list(run["variables"]))

Existing MCP hosts

Claude Desktop, Cursor, Codex and other hosts only need the URL — the server is public and takes no authentication:

{
  "mcpServers": {
    "bondgraph": {
      "type": "http",
      "url": "https://xn--lda.se/api/mcp"
    }
  }
}

Simulation tools

simulate

Run a BGIF v1 model with the same solver the editor uses and return time-series results.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF v1 document, either bare ({bgifVersion,components,systems}) or the {bgif,layout} wrapper saved by the editor.
configobjectnoOptional overrides: startTime, endTime, stepSize, solver ("bdf1"|"bdf2"), tolerance.
format"full"|"compact"nocompact drops empty variable arrays from the response.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "simulate",
    "arguments": {
      "bgif": "<BGIF document or {bgif,layout} wrapper>",
      "config": {
        "endTime": 5,
        "stepSize": 0.01,
        "solver": "bdf2"
      },
      "format": "compact"
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":10,"method":"tools/call",
 "params":{"name":"simulate","arguments":{
       "bgif": {"bgifVersion":"1.0.0","components":[…],"systems":[…]},
       "config": {"endTime":5,"stepSize":0.01,"solver":"bdf2"},
       "format": "compact"
     }}}'

Example response (parsed content[0].text)

{
  "status": "ok",
  "error": null,
  "time": [0, 0.01, 0.02, …, 5.00],
  "variables": {
    "e_C1": [0, 0.0099, 0.0197, …],
    "f_I1": [0, 0.0001, 0.0004, …]
  },
  "meta": {
    "modelId": "rlc",
    "modelName": "RLC Circuit",
    "variableCount": 2,
    "sampleCount": 501,
    "config": {"startTime":0,"endTime":5,"stepSize":0.01,"solver":"bdf2"},
    "durationMs": 38
  }
}

validate_bgif

Parse a BGIF document and report whether it is structurally valid. Cheap; use before simulating large models.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF v1 document or {bgif,layout} wrapper.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "validate_bgif",
    "arguments": {
      "bgif": "<BGIF document or {bgif,layout} wrapper>"
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":11,"method":"tools/call",
 "params":{"name":"validate_bgif","arguments":{"bgif":{"bgifVersion":"1.0.0","components":[],"systems":[]}}}}'

Example response — valid

{
  "valid": true,
  "modelId": "empty",
  "modelName": "Untitled",
  "elementCount": 0,
  "bondCount": 0,
  "subsystemCount": 0
}

Example response — invalid

{
  "valid": false,
  "error": "bond references unknown element id \"R7\""
}

list_examples

List every built-in example model with its description, element count, and default simulation config.

Inputs

None — pass "arguments": {}.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_examples",
    "arguments": {}
  }
}

Example response

{
  "examples": [
    {
      "name": "RLC Circuit",
      "description": "Series RLC driven by a step voltage source.",
      "elementCount": 5,
      "defaultSimulation": {"startTime":0,"endTime":5,"stepSize":0.01,"solver":"bdf2"}
    },
    {
      "name": "DC Motor",
      "description": "Armature + rotor + load with gyrator coupling.",
      "elementCount": 8,
      "defaultSimulation": {"startTime":0,"endTime":2,"stepSize":0.001,"solver":"bdf2"}
    }
    /* … */
  ]
}

get_example

Return the full BGIF wrapper for a named example. Feed the bgif field straight into simulate.

Inputs

FieldTypeRequiredDescription
namestringyesExample name as returned by list_examples (case sensitive).

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_example",
    "arguments": {
      "name": "<example name>"
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":12,"method":"tools/call",
 "params":{"name":"get_example","arguments":{"name":"RLC Circuit"}}}'

Example response

{
  "name": "RLC Circuit",
  "bgif": {
    "bgif": {
      "bgifVersion": "1.0.0",
      "components": [ /* SubsystemDef objects */ ],
      "systems":    [ /* root system with elements + bonds */ ]
    },
    "layout": { /* canvas positions */ }
  },
  "defaultSimulation": {"startTime":0,"endTime":5,"stepSize":0.01,"solver":"bdf2"}
}

render_svg

Render a BGIF model as an SVG image styled exactly like the editor canvas.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF v1 document or {bgif,layout} wrapper.
theme"dark"|"light"noColor theme; defaults to dark.
widthnumbernoOutput width in px (optional; auto from layout).
heightnumbernoOutput height in px (optional).
paddingnumbernoPadding around the model in px, default 60.
showPortLabelsbooleannoShow port id labels on subsystem ports.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "render_svg",
    "arguments": {
      "bgif": "<BGIF document or {bgif,layout} wrapper>",
      "theme": "dark",
      "padding": 60,
      "showPortLabels": false
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":13,"method":"tools/call",
 "params":{"name":"render_svg","arguments":{
       "bgif": {"bgifVersion":"1.0.0","components":[…],"systems":[…]},
       "theme": "light"
     }}}'

Example response

The content[0].text field is raw SVG markup (<svg …>…</svg>) — extract it with jq -r '.result.content[0].text' > model.svg.

The same renderer is also exposed as a plain HTTP image endpoint at GET /api/public/render.svg?bgif=<urlencoded>(or POST with a JSON body for large models). Useful for <img src> embedding in markdown or docs.

Diagnostics, editing, calibration & symbolic export

These tools complement simulate and target three workflows: understanding a model (analyze_causality, check_units), changing it from an agent loop without resending the whole document (the model-editing primitives), and turning it into something else — a parameter sweep, a calibrated parameter set, a small-signal state-space model, a frequency response, or compilable Modelica source.

analyze_causality

Sequential Causality Assignment (SCAP). Returns per-bond causality, the chosen state variables, any algebraic loops, derivative-causality elements, an estimated DAE index, and an overall well-posedness verdict. validate_bgif accepts analyze:true to embed a condensed summary inline.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or { bgif, layout } wrapper.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":30,"method":"tools/call",
 "params":{"name":"analyze_causality","arguments":{"bgif":<BGIF>}}}'

check_units

Dimensional / domain type-check. Infers a physical domain (electrical, mechanical-translational, mechanical-rotational, fluid, thermal, magnetic, chemical) for every element and bond from labels, optional params.domain overrides, and optional <key>_unit strings (e.g. resistance_unit:"ohm", capacitance_unit:"J/K"). Reports per-bond effort/flow units, bond-domain conflicts, GY misuse, and parameter-unit mismatches. Advisory by default; pass strict:true to promote findings to errors.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or wrapper.
strictbooleannoWhen true, promote advisory findings to errors and flip ok to false.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":31,"method":"tools/call",
 "params":{"name":"check_units","arguments":{"bgif":<BGIF>,"strict":false}}}'

parameter_sweep

Cartesian product of parameter axes over the simulator. Each axis is values:[…] or range:{min,max,n,scale:"linear"|"log"}. reduce picks a per-output scalar (final | max | min | absmax | rms | mean) or "timeseries" returns full traces. Capped at maxRuns (default 200).

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or wrapper.
parametersobject[]yesArray of {elementId,key,values?|range?} axes.
outputsstring[]yesVariable names to record (e.g. q_C1, e_1_R1).
reducestringnofinal | max | min | absmax | rms | mean | "timeseries".
configobjectnoPartial SimulationConfig overrides.
maxRunsnumbernoSafety cap (default 200).

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":32,"method":"tools/call",
 "params":{"name":"parameter_sweep","arguments":{"bgif":<BGIF>,
       "parameters":[{"elementId":"r1","key":"resistance","range":{"min":50,"max":200,"n":4}}],
       "outputs":["q_C1"],
       "reduce":"final"}}}'

fit_parameters

Derivative-free Nelder-Mead calibration of free parameters to a target {t, series:{name:[…]}}. Supports per-series weights and per-parameter bounds. Returns fitted values and RMS residual.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or wrapper.
targetobjectyes{ t:number[], series:{ varName:number[] } } — observed trajectory.
parametersobject[]yesFree parameters: {elementId,key,initial?,min?,max?}.
weightsobjectnoOptional per-series weights.
configobjectnoSimulation config used for each candidate.
maxIterationsnumbernoOptimizer cap (default 200).

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":33,"method":"tools/call",
 "params":{"name":"fit_parameters","arguments":{"bgif":<BGIF>,
       "target":{"t":[0,0.1,0.2],"series":{"q_C1":[0,0.5,0.9]}},
       "parameters":[{"elementId":"r1","key":"resistance","initial":100,"min":1,"max":1000}]}}}'

linearize

Extract a small-signal state-space {A, B?, C?, D?} around an operating point. operatingPoint can be "auto" (settle the model via a short simulation), "initial", or a user-supplied {stateName:value} map. State variables are q_*/p_* (bond-graph displacements / momenta). Pass inputs:[{elementId,key}] (source parameters) for B/D and outputs:[varName] (any DAE variable) for C/D. Assumes DAE index ≤ 1 — use analyze_causality to check.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or wrapper.
operatingPoint"auto" | "initial" | objectnoWhere to linearize. Defaults to initial conditions.
inputsobject[]noSource parameters to use as inputs — produces B and D.
outputsstring[]noVariable names to use as outputs — produces C and D.
perturbationnumbernoFinite-difference step (default 1e-6).

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":34,"method":"tools/call",
 "params":{"name":"linearize","arguments":{"bgif":<BGIF>,
       "operatingPoint":"auto",
       "inputs":[{"elementId":"se1","key":"effort","label":"V_in"}],
       "outputs":["q_C1"]}}}'

analyze_frequency

Same inputs as linearize plus an optional frequencies field (rad/s — either a list or {start,stop,points,scale:"log"|"linear"}). Returns poles with damping ratio and natural frequency, a stable verdict, the spectral abscissa, and — when both inputs and outputs are supplied — Bode magnitude (dB) and phase (deg) at each frequency.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":35,"method":"tools/call",
 "params":{"name":"analyze_frequency","arguments":{"bgif":<BGIF>,
       "operatingPoint":"auto",
       "inputs":[{"elementId":"se1","key":"effort","label":"V_in"}],
       "outputs":["q_C1"],
       "frequencies":{"start":0.1,"stop":1000,"points":40,"scale":"log"}}}}'

export_equations

Symbolic equation export. form:'dae' returns a structured DAE — states with initials, algebraic vars, parameters with units, equations tagged source / junction-equal / junction-balance / constitutive / state-derivative. form:'ode' best-effort reduces to an explicit ODE by forward-substituting algebraic definitions and linearly solving single-unknown junction balances (so RC / RL / RLC-series reduce to plain der(q)=…); any irreducible loops are surfaced in unreducedAlgebraic. form:'modelica' emits compilable Modelica source — parameter docstrings, unit="…" attributes, start= on non-zero states, equations grouped by element, sanitized identifiers, and dialect→Modelica rewrites for PI, step, dead, **, log2, cbrt, round, and t→time. Subsystems are flattened automatically and names use the same alias resolution as the editor and simulator.

Inputs

FieldTypeRequiredDescription
bgifobjectyesBGIF document or wrapper.
form"dae" | "ode" | "modelica"noOutput shape. Default "dae".
modelNamestringnoOverride the Modelica model identifier (sanitized).

Example request — Modelica

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":36,"method":"tools/call",
 "params":{"name":"export_equations","arguments":{"bgif":<BGIF>,"form":"modelica","modelName":"MyModel"}}}'

Example response (excerpt) — Modelica

model MyModel
  // Auto-generated from BondGraph Studio.

  // ----- Parameters -----
  // R1
  parameter Real R_R1(unit="ohm") = 100.0 "resistance of R1";
  // C1
  parameter Real C_C1 = 0.001 "capacitance of C1";
  // V_in
  parameter Real E_V_in = 10.0 "effort source of V_in";

  // ----- State variables -----
  Real q_C1 "generalized displacement of C1";

  // ----- Algebraic variables (bond efforts and flows) -----
  Real e_V_in_1; Real f_V_in_1;
  Real e_1_R1;   Real f_1_R1;
  Real e_1_C1;   Real f_1_C1;

equation
  // V_in
  e_V_in_1 = E_V_in;
  // 1-junction 1
  f_1_R1 = f_V_in_1;
  f_1_C1 = f_V_in_1;
  0 = (-e_V_in_1) + e_1_R1 + e_1_C1;
  // R1
  e_1_R1 = R_R1 * f_1_R1;
  // C1
  der(q_C1) = f_1_C1;
  e_1_C1 = q_C1 / C_C1;
end MyModel;

Model-editing primitives

Round-trip editing tools — each takes a BGIF wrapper and returns the updated wrapper, so an agent can mutate a model across many turns without resending the whole document. Use apply_edits when you want several changes to land atomically (it rolls back on first failure).

FieldTypeRequiredDescription
add_elementtoolnoInsert a primitive (R/C/I/Se/Sf/TF/GY/0/1) or subsystem instance.
remove_elementtoolnoDelete an element and every bond touching it.
set_parametertoolnoChange a single params field on an element (including subsystem instance overrides).
rename_elementtoolnoChange an element's label — alias-resolved variable names follow.
connecttoolnoAdd a bond between two (element, port) pairs with an optional causal stroke.
disconnecttoolnoRemove a bond by id.
apply_editstoolnoRun an ordered list of the above as a transaction.

Example request — apply_edits

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":37,"method":"tools/call",
 "params":{"name":"apply_edits","arguments":{"bgif":<BGIF>,
       "edits":[
         {"op":"set_parameter","elementId":"r1","key":"resistance","value":220},
         {"op":"rename_element","elementId":"c1","label":"C_out"}
       ]}}}'

3D scene authoring tools

Geometry is a first-class artefact next to the bond graph: preview_scene and animate_scene render and play it back, while these four tools let an agent discover the primitive catalogue, author or repair a scene, check it, and write it out as URDF, MJCF or the native JSON scene format. Every one of them accepts the same geometry sources — a scene (URDF/MJCF XML or JSON), a bgif model with optional geometryHints, or a built-in example bundle.

list_scene_primitives

List the geometric primitives available to the scene editor with their shape, default size vector, size-field meaning and default colour.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":60,"method":"tools/call",
 "params":{"name":"list_scene_primitives","arguments":{}}}'

validate_scene

Structurally validate a scene: duplicate body/joint names, missing or cyclic parents, zero joint axes, inverted limits, empty or zero-sized geometry, meshes with no file reference.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":61,"method":"tools/call",
 "params":{"name":"validate_scene","arguments":{"example":"single_joint_arm"}}}'

edit_scene

Apply a batch of declarative edit operations and return the edited scene, per-operation results and fresh validation warnings. Omit every geometry source to build a scene from scratch.

Operations

FieldTypeRequiredDescription
set_scene_nameopnoRename the scene.
add_bodyopnoAdd a body: name?, parent?, primitive?.
remove_bodyopnoRemove a body and re-parent its children.
rename_bodyopnoRename a body (references follow).
update_bodyopnoPatch parent, pos, rpy, axis, jointName, jointType, limit, variable.
set_joint_typeopnofixed | revolute | prismatic, with sensible default limits.
add_geometryopnoAppend a primitive to a body.
remove_geometryopnoDrop geometry by index.
update_geometryopnoPatch shape, size, pos, rpy, color, mesh.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":62,"method":"tools/call",
 "params":{"name":"edit_scene","arguments":{"ops":[
         {"op":"set_scene_name","name":"crane"},
         {"op":"add_body","name":"base","primitive":"plate"},
         {"op":"add_body","name":"arm","parent":"base","primitive":"rod"},
         {"op":"set_joint_type","name":"arm","jointType":"revolute"},
         {"op":"update_body","name":"arm","patch":{"axis":[0,1,0],"jointName":"shoulder"}}
       ]}}}'

export_scene

Serialise a scene to URDF (ROS), MJCF (MuJoCo) or the native JSON scene format, returning { format, filename, content, warnings }.

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":63,"method":"tools/call",
 "params":{"name":"export_scene","arguments":{"example":"single_joint_arm","format":"urdf"}}}'

Library discovery & validation tools

Component libraries are bundled in the BGLIB v1 wire format. These five tools let an agent browse the libraries that ship with BondGraph Studio, fetch one a user linked, sanity-check a candidate file, and assemble a fresh library from raw components.

list_libraries

List the curated component libraries shipped with BondGraph Studio (Buildings & HVAC, Power & Energy, Automotive, Hydraulics, Data Center) with a per-component summary.

Inputs

None — pass "arguments": {}.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_libraries",
    "arguments": {}
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":20,"method":"tools/call",
 "params":{"name":"list_libraries","arguments":{}}}'

Example response

{
  "bglibVersion": "1.0.0",
  "libraries": [
    {
      "name": "Buildings & HVAC",
      "description": "Thermal zones, HVAC, building envelopes",
      "componentCount": 12,
      "components": [
        {
          "id": "thermal-zone",
          "name": "Thermal Zone",
          "group": "Buildings",
          "portCount": 2,
          "description": "Single-capacitance lumped zone with envelope loss."
        },
        /* … */
      ]
    },
    {
      "name": "Power & Energy",
      "description": "Generators, transmission, storage, loads",
      "componentCount": 9,
      "components": [ /* … */ ]
    }
    /* Automotive, Hydraulics, Data Center … */
  ]
}

get_library

Return the full BGLIB v1 document for a shipped library, ready to drop into the editor's Import Library → File dialog.

Inputs

FieldTypeRequiredDescription
namestringyesLibrary name from list_libraries (e.g. "Hydraulics").

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_library",
    "arguments": {
      "name": "<library name>"
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":21,"method":"tools/call",
 "params":{"name":"get_library","arguments":{"name":"Hydraulics"}}}'

Example response

{
  "bglibVersion": "1.0.0",
  "name": "Hydraulics",
  "version": "1.0.0",
  "author": "BondGraph Studio",
  "description": "Pumps, valves, cylinders, accumulators",
  "license": "MIT",
  "bgif": {
    "bgifVersion": "1.0.0",
    "components": [ /* SubsystemDef objects in BGIF form */ ],
    "systems": []
  }
}

validate_library

Parse a candidate BGLIB v1 document (or a legacy BGIF library) and report whether it is valid, the metadata, and the component count — or the exact parser error.

Inputs

FieldTypeRequiredDescription
libraryobjectyesA BGLIB v1 document, or a BGIF document / wrapper containing components.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "validate_library",
    "arguments": {
      "library": "<BGLIB v1 document or BGIF wrapper>"
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":22,"method":"tools/call",
 "params":{"name":"validate_library","arguments":{
       "library": {
         "bglibVersion": "1.0.0",
         "name": "Acme Pneumatics",
         "version": "0.3.1",
         "author": "Acme Engineering",
         "bgif": {"bgifVersion":"1.0.0","components":[…],"systems":[]}
       }
     }}}'

Example response — valid

{
  "valid": true,
  "legacy": false,
  "meta": {
    "name": "Acme Pneumatics",
    "version": "0.3.1",
    "author": "Acme Engineering",
    "description": null,
    "license": null,
    "homepage": null
  },
  "componentCount": 7
}

Example response — invalid

{
  "valid": false,
  "error": "BGLIB.bgif.components[2]: missing required field \"ports\""
}

Example response — legacy BGIF accepted

{
  "valid": true,
  "legacy": true,
  "meta": {
    "name": "imported.bgif",
    "version": "0.0.0",
    "author": null,
    "description": "Imported from legacy BGIF document",
    "license": null,
    "homepage": null
  },
  "componentCount": 4
}

fetch_library

Download a BGLIB v1 (or legacy BGIF) document from an HTTPS URL — GitHub raw, gist, S3, a personal site — and return its parsed metadata and component summary.

Inputs

FieldTypeRequiredDescription
urlstring (https://)yesHTTPS URL pointing to a .bglib.json / .bgif / .json file.
summarybooleannoIf true (default) return only metadata + component summary; if false also include the rebuilt BGLIB document.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "fetch_library",
    "arguments": {
      "url": "<https URL to .bglib.json or .bgif>",
      "summary": true
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":23,"method":"tools/call",
 "params":{"name":"fetch_library","arguments":{"url":"https://example.com/pumps.bglib.json"}}}'

Example response (summary)

{
  "meta": {
    "name": "Centrifugal Pumps",
    "version": "1.2.0",
    "author": "Jane Doe",
    "description": "Single- and multi-stage centrifugal pumps.",
    "license": "Apache-2.0",
    "homepage": "https://example.com/pumps"
  },
  "legacy": false,
  "componentCount": 5,
  "components": [
    {
      "id": "centrifugal-pump-1stage",
      "name": "Single-stage centrifugal pump",
      "group": "Pumps",
      "portCount": 2,
      "description": "Polynomial head curve, parameterised by rated flow + head."
    }
    /* … */
  ]
}

Example response (summary: false)

{
  "meta": { /* same as above */ },
  "legacy": false,
  "componentCount": 5,
  "components": [ /* same summary */ ],
  "document": {
    "bglibVersion": "1.0.0",
    "name": "Centrifugal Pumps",
    "version": "1.2.0",
    "author": "Jane Doe",
    "bgif": { "bgifVersion": "1.0.0", "components": [ /* full */ ], "systems": [] }
  }
}

Example response — fetch error

{
  "jsonrpc": "2.0",
  "id": 23,
  "error": {
    "code": -32000,
    "message": "fetch_library: HTTP 404 from https://example.com/pumps.bglib.json"
  }
}

build_library

Wrap one or more BGIF subsystem components into a fresh BGLIB v1 document with the given metadata. Use when an agent has authored components and wants to give the user a single shareable file.

Inputs

FieldTypeRequiredDescription
meta.namestringyesHuman-readable library name.
meta.versionstringnoSemver string; defaults to 1.0.0.
meta.authorstringnoAuthor / maintainer name.
meta.descriptionstringnoOne-line description.
meta.licensestringnoSPDX identifier, e.g. MIT.
meta.homepagestring (https://)noProject homepage.
componentsobject[]yesArray of BGIF SubsystemDef components.

JSON-RPC template (copyable)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "build_library",
    "arguments": {
      "meta": {
        "name": "<library name>",
        "version": "1.0.0",
        "author": "<author>",
        "license": "MIT"
      },
      "components": [
        "<SubsystemDef object 1>",
        "<SubsystemDef object 2>"
      ]
    }
  }
}

Example request

curl -sS https://xn--lda.se/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":24,"method":"tools/call",
 "params":{"name":"build_library","arguments":{
       "meta": {
         "name": "My Pumps",
         "version": "0.1.0",
         "author": "Me",
         "license": "MIT"
       },
       "components": [ /* SubsystemDef objects */ ]
     }}}'

Example response

{
  "bglibVersion": "1.0.0",
  "name": "My Pumps",
  "version": "0.1.0",
  "author": "Me",
  "license": "MIT",
  "bgif": {
    "bgifVersion": "1.0.0",
    "components": [ /* echoed back, normalised */ ],
    "systems": []
  }
}

Example BGLIB payload

Below is a complete, copyable BGLIB v1 document containing a single component — a Thermal Zone subsystem. You can paste this directly into the validate_library or build_library tools, or save it as a .bglib.json file and import it into the editor via Import Library → File.

{
  "bglibVersion": "1.0.0",
  "name": "Demo Building Library",
  "version": "1.0.0",
  "author": "BondGraph Studio",
  "description": "A minimal example library with one thermal-zone component.",
  "license": "MIT",
  "bgif": {
    "bgifVersion": "1.0.0",
    "components": [
      {
        "id": "bld_thermal_zone",
        "library": "Demo Building Library",
        "group": "Zones",
        "name": "Thermal Zone",
        "description": "Single-air-node thermal zone with lumped thermal capacitance. Ports: envelope (left), gains (right), adjacent (bottom).",
        "ports": [
          { "id": "env",  "side": "left",  "offset": 0.5 },
          { "id": "gain", "side": "right", "offset": 0.5 },
          { "id": "adj",  "side": "bottom", "offset": 0.5 }
        ],
        "svgIcon": "<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect x="15" y="20" width="70" height="60" rx="4" fill="none" stroke="oklch(0.78 0.13 200)" stroke-width="2"/><text x="50" y="50" text-anchor="middle" dominant-baseline="central" font-family="monospace" font-size="14" fill="oklch(0.78 0.13 200)" font-weight="600">T_z</text></svg>",
        "innerElements": [
          {
            "id": "j",
            "type": "0",
            "label": "0",
            "x": 200,
            "y": 160,
            "width": 50,
            "height": 50,
            "ports": [
              { "id": "p1", "side": "top",    "offset": 0.5 },
              { "id": "p2", "side": "right",  "offset": 0.5 },
              { "id": "p3", "side": "bottom", "offset": 0.5 },
              { "id": "p4", "side": "left",   "offset": 0.5 }
            ],
            "params": {}
          },
          {
            "id": "Cz",
            "type": "C",
            "label": "C_zone",
            "x": 200,
            "y": 60,
            "width": 80,
            "height": 50,
            "ports": [
              { "id": "p1", "side": "left",   "offset": 0.5 },
              { "id": "p2", "side": "right",  "offset": 0.5 },
              { "id": "p3", "side": "top",    "offset": 0.5 },
              { "id": "p4", "side": "bottom", "offset": 0.5 }
            ],
            "params": { "capacitance": 5000000, "q0": 90000000 }
          }
        ],
        "innerBonds": [
          {
            "id": "b1",
            "fromElementId": "j",
            "fromPortId": "p1",
            "toElementId": "Cz",
            "toPortId": "p4",
            "causalStroke": "none"
          }
        ],
        "portMap": {
          "env":  { "elementId": "j", "portId": "p4" },
          "gain": { "elementId": "j", "portId": "p2" },
          "adj":  { "elementId": "j", "portId": "p3" }
        }
      }
    ],
    "systems": []
  }
}
See the API section of the main docs for transport details, MCP client configuration snippets, and the direct HTTP fallback at /api/public/simulate.