Skip to content

Asking Claude directly

The model explorer speaks MCP, so a Claude session can query the application itself — from any repository, without a copy of this one. Useful when the question is about the running system rather than about the prose: "which live flows can set a booking to CX, and who can run them?"

Connect it once

claude mcp add --transport http --scope user ww-model http://localhost:8001/-/mcp
claude mcp list          # ww-model ... ✔ Connected

--scope user registers it for every repository on your machine. Use --scope project inside a specific repo instead to write .mcp.json there, so teammates inherit it when they clone — worth doing once this stops being localhost.

The model explorer must be running: cd serve && docker compose up -d.

A session that was already open will not see it

A Claude session builds its tool list when it starts, and claude mcp add does not retro-fit it. This is easy to misread as a broken server, because the shell says everything is fine: claude mcp list reported ww-model ... ✔ Connected while the session running in the next window had no execute_sql at all.

Start a new session — a new terminal, or /exit and claude again — and the three tools are there. Nothing needs re-adding; the registration is already on disk.

Checking the endpoint without a session

Useful when you want to know whether the server or the session is the problem. The handshake is three calls, and curl can do all of them:

SID=$(curl -s -D /dev/stderr -X POST http://localhost:8001/-/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"}}}' \
      2>&1 >/dev/null | awk '/mcp-session-id/ {print $2}' | tr -d '\r')

curl -s -X POST http://localhost:8001/-/mcp \
  -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -H "mcp-session-id: $SID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"execute_sql","arguments":{"database":"model","sql":"select count(*) as flows from docs where kind = '"'"'Microflow'"'"'"}}}'

A reply naming databases or returning rows means the container, the databases and the read-only path are all healthy, and the problem is on the client side.

What Claude gets

Three tools, and it is told to read the schema before querying:

Tool Does
list_databases the three databases — model, docs and source
get_database_schema every table, view and column
execute_sql one read-only SELECT, returning columns and rows

Writes are refused three ways over: the plugin validates that the statement is a SELECT, Datasette opens the file immutable, and the container mounts it read-only. CREATE, INSERT, UPDATE, DELETE, DROP, PRAGMA writable_schema and ATTACH were each tried and each rejected.

Questions that work well

Ask in plain language — Claude writes the SQL:

  • "Which live flows write Booking.Booking.WindowStatus to CX, and which roles can run them?"
  • "What runs implicitly when a Booking.VoucherTotals is committed?"
  • "If I change Pricing.Sub_AddPriceToDetailedBookingLine_PCG, what could be affected?"
  • "Which Pricing flows are unreachable from Pricing.Sub_PriceBookingAll?"
  • "What does the documentation say about DiscountPercentage_ExclManual, and does the model still agree?"
  • "List the live flows that call flows excluded from deployment."

Three databases, and the questions that cross them

Database Holds
model the application as facts — 504,833 rows: flows, steps, entities, roles, entry points, coverage
docs every section of every document, with the model names it mentions
source the hand-written half — 2,436 files, every Java and JavaScript action linked to its file, and the microflows that call it

The interesting questions cross them, which is why they are served from one place:

  • "What does the Java behind DataManagement.jaImportCSV_BookingChanges actually do, and which microflows call it?"
  • "Which code touches Booking.Booking?" — the model says which flows do; source says which files do
  • "Show me Java that talks to the database directly" — 13 files use JDBC, going around the Mendix data layer entirely, so the model cannot describe what they read or write
  • "Where does Java build a microflow name or an XPath at runtime?" — 31 files do, and those edges cannot be read from the source at all

That last one is the honest limit, and it is worth being exact about what it does not mean. Microflow logic is completely available: a microflow is a model, not text — closer to BPMN than to a file — and every step, branch and expression is in model. What cannot be read is the other direction: Java calls microflows through variables here (Core.microflowCall(this.Microflow)), so exactly one literal microflow name appears across 1,286 Java files. source records what is written down and counts the rest as dynamic; an absent reference means "not named in this file", never "not used". See when to read the code.

Two things it cannot answer

Expressions are stored verbatim, never parsed. A write of if … then CC else CX is one fact mentioning two values, not a decision table. If the answer hinges on which branch runs, read the flow — block: How <flow> is started and the deep dives exist for that.

Runtime configuration is invisible. Whether a scheduled event is enabled in a given environment, what a constant holds in production, which feature flags are set — none of that is in the model, so nothing here can tell you.

If you would rather not use Claude

Everything the MCP endpoint exposes is on the web too: the model explorer autocomplete, and every page answers as JSON or CSV by adding .json or .csv to the URL.