# BondGraph Studio > A WYSIWYG bond graph editor for modelling and simulating multi-physics dynamic systems (electrical, mechanical, hydraulic, thermal, rotational) using the unified bond graph notation. BondGraph Studio lets engineers and students build causal bond graph models on a drag-and-drop canvas, run BDF-2 simulations in the browser, and export models as BGIF (Bond Graph Interchange Format). Reusable subsystems can be saved with custom SVG icons and a portMap into the editor's component library. ## Pages - [Editor](/): The main canvas — drag elements, draw bonds, edit parameters, and run simulations. - [Documentation](/docs): User guide covering bond graph theory, the nine basic elements, history of bond graphs, worked tutorials (RLC, DC motor, robotic arm, thermal, hydraulic, data center), causality, state-space derivation, hybrid systems, common pitfalls, the SPDM workflow, and the public HTTP API. ## HTTP API for AI agents A no-auth, CORS-open endpoint runs the same in-browser simulator on any BGIF model and returns the result as JSON. Both GET (query param) and POST (JSON body) are supported; OPTIONS handles CORS preflight. - [OpenAPI 3.1 specification](/api/public/openapi.json): Machine-readable spec including the full BGIF JSON Schema under `components.schemas.BGIF`. Use this to generate clients or feed an LLM tool-loader. - [Swagger UI](/api-docs): Interactive HTML reference for the same spec. - [API usage doc (self-describing JSON)](/api/public/simulate): GET with no query string returns the parameter schema, defaults, and examples. - [API documentation page](/docs#api): Human-readable description with request/response shapes and curl examples. - [MCP Tool Reference](/docs/mcp): Per-tool reference (inputs, JSON-RPC examples, example responses) for every tool at /api/mcp, including the BGLIB library discovery and validation tools. ## MCP endpoint for AI agents A Model Context Protocol JSON-RPC endpoint exposes the same simulator as native MCP tools, so Claude Desktop, Cursor, Windsurf, the AI SDK MCP client, and any MCP host can discover and call it directly. - Endpoint (Streamable HTTP, no auth, CORS open): `POST https://xn--lda.se/api/mcp` - Tools: `simulate`, `validate_bgif` (with `analyze:true`), `analyze_causality`, `check_units`, `list_examples`, `get_example`, `render_svg`, `list_libraries`, `get_library`, `validate_library`, `fetch_library`, `build_library`, model editing (`add_element`, `remove_element`, `set_parameter`, `rename_element`, `connect`, `disconnect`, `apply_edits`), batch analysis (`parameter_sweep`, `fit_parameters`), frequency-domain analysis (`linearize`, `analyze_frequency`), and symbolic export (`export_equations` — DAE / ODE / Modelica) - Client config (Claude Desktop / Cursor / AI SDK): { "mcpServers": { "bondgraph": { "url": "https://xn--lda.se/api/mcp" } } } ### MCP curl / JSON-RPC examples Every call requires `Accept: application/json, text/event-stream` (Streamable HTTP spec). Replace `` with a BGIF v1 document (`{bgifVersion,components,systems}`) or a `{bgif,layout}` wrapper. Handshake + tool discovery: 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"}' `list_examples` (no arguments): 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":3,"method":"tools/call", "params":{"name":"list_examples","arguments":{}}}' `get_example` (fetch one model by name): 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":4,"method":"tools/call", "params":{"name":"get_example","arguments":{"name":"RLC Circuit"}}}' `validate_bgif` (parse and report errors): 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":5,"method":"tools/call", "params":{"name":"validate_bgif","arguments":{"bgif":}}}' `simulate` (returns time-series JSON inside `result.content[0].text`): 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":6,"method":"tools/call", "params":{"name":"simulate", "arguments":{"bgif":, "config":{"endTime":5,"stepSize":0.01,"solver":"bdf2"}, "format":"compact"}}}' `render_svg` (returns an SVG image string with the same look as the editor canvas): 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":7,"method":"tools/call", "params":{"name":"render_svg", "arguments":{"bgif":,"theme":"dark"}}}' \ | jq -r '.result.content[0].text' > model.svg The same SVG renderer is exposed as a plain HTTP endpoint for embedding in markdown or ``: `GET https://xn--lda.se/api/public/render.svg?bgif=&theme=dark` (or POST with a JSON body). Response `Content-Type: image/svg+xml`. ### Diagnostics, editing, and calibration tools - `analyze_causality` — runs Sequential Causality Assignment (SCAP) and returns per-bond causality, state variables, algebraic loops, derivative-causality elements, an estimated DAE index, and well-posedness. `validate_bgif` accepts `analyze:true` to embed a condensed summary inline. - Model-editing primitives — `add_element`, `remove_element`, `set_parameter`, `rename_element`, `connect`, `disconnect`, and the transactional batch wrapper `apply_edits`. Each takes a BGIF wrapper and returns the updated wrapper, so callers can iterate on a model without resending the whole document. - `parameter_sweep` — Cartesian product of parameter axes (`values:[...]` or `range:{min,max,n,scale:"linear"|"log"}`) over the simulator, with per-output reduction (`final|max|min|absmax|rms|mean`) or full `timeseries`. Capped at `maxRuns` (default 200). - `fit_parameters` — derivative-free Nelder-Mead calibration of free parameters to a target `{t, series:{name:[...]}}`. Optional per-series weights and bounds. Returns fitted values + RMS residual. - `linearize` — extract a small-signal state-space `{A, B?, C?, D?}` around an operating point (user-provided `{stateName:value}`, `"auto"` to settle via simulation, or `"initial"`). State vars are q_*/p_* (bond-graph displacements/momenta). Pass `inputs:[{elementId,key}]` (source params) for `B`/`D` and `outputs:[varName]` (any DAE variable) for `C`/`D`. Assumes DAE index ≤ 1 (the simulator's regime); use `analyze_causality` to check. - `analyze_frequency` — same inputs as `linearize` plus optional `frequencies` (rad/s, list or `{start,stop,points,scale:"log"|"linear"}`). Returns `poles` with damping ratio and natural frequency, a `stable` verdict, `spectralAbscissa`, and (when both inputs and outputs are supplied) Bode magnitude (dB) + phase (deg) at each frequency. - `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 `_unit` strings (e.g. `resistance_unit:"ohm"`, `capacitance_unit:"J/K"`). Reports per-bond inferred effort/flow units, bond-domain conflicts (e.g. an electrical R wired directly to a thermal C without a GY), GY misuse (same domain on both ports), and parameter-unit mismatches. Advisory by default; pass `strict:true` to promote findings to `errors` and flip `ok` to `false`. - `export_equations` — symbolic equation export for any BGIF model. Pass `form:"dae"` for a structured DAE (states, algebraic vars, parameters with units, equations tagged `source` / `junction-equal` / `junction-balance` / `constitutive` / `state-derivative`); `form:"ode"` for a best-effort explicit ODE (forward-substitutes algebraic definitions and linearly solves single-unknown balances — RC / RL / RLC-series reduce to plain `der(q)=…`); or `form:"modelica"` for compilable Modelica source (parameter docstrings, `unit="…"` attributes, `start=` on non-zero states, dialect→Modelica rewrites for `PI`, `step`, `dead`, `**`, `log2`, `cbrt`, `round`, `t→time`). Variable and parameter names use the same alias resolution as the editor and simulation layer, and subsystem instances are flattened before export. 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":"check_units", "arguments":{"bgif":,"strict":false}}}' 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":"parameter_sweep", "arguments":{"bgif":, "parameters":[{"elementId":"r1","key":"resistance","range":{"min":50,"max":200,"n":4}}], "outputs":["q_C1"],"reduce":"final"}}}' 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":"analyze_frequency", "arguments":{"bgif":, "operatingPoint":"auto", "inputs":[{"elementId":"se1","key":"effort","label":"V_in"}], "outputs":["q_C1"], "frequencies":{"start":0.1,"stop":1000,"points":40,"scale":"log"}}}}' 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":"export_equations", "arguments":{"bgif":,"form":"modelica","modelName":"MyModel"}}}' ## Sharing component libraries (BGLIB v1) Reusable subsystems (thermal zones, pumps, generators, …) ship as **BGLIB v1** documents — a thin JSON wrapper around BGIF that carries library-level metadata (name, version, author, description, license, homepage). Users can export any library from the editor as `.bglib.json`, share it over any channel (file, gist, GitHub raw, S3, personal site), and import it via **Import → File** or **Import → URL** in the Component Libraries panel. Agents can list and fetch the shipped libraries, validate user-provided ones, fetch a library from a URL, and bundle a fresh BGLIB from a set of components: # List shipped libraries 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":"list_libraries","arguments":{}}}' # Fetch one as a full BGLIB document (ready to import) 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":"get_library","arguments":{"name":"Hydraulics"}}}' # Inspect a library a user has shared a URL to 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":"fetch_library", "arguments":{"url":"https://example.com/my-pumps.bglib.json"}}}' BGLIB v1 wire shape: { "bglibVersion": "1.0.0", "name": "Acme Pneumatics", "version": "0.3.1", "author": "Acme Engineering", "description": "Single-acting cylinders, valves, accumulators.", "license": "MIT", "homepage": "https://github.com/acme/bondgraph-pneumatics", "bgif": { "bgifVersion": "1.0.0", "components": [...], "systems": [] } } Quick reference: POST /api/public/simulate Content-Type: application/json { "bgif": , "config": { "endTime": 5, "stepSize": 0.01, "solver": "bdf2" } } GET /api/public/simulate?bgif=&endTime=5&stepSize=0.01 Response: `{ status, time, variables, meta, error? }` where `variables` is a record of named time-series traces (`q_`, `p_`, per-bond `e_*` / `f_*`).