Skip to content

fix(mcp): onboard Studio Pro 11.13 — repair ALTER PAGE and make capabilities probe-gated - #874

Merged
ako merged 2 commits into
mainfrom
mxcli-mcp
Aug 11, 2026
Merged

fix(mcp): onboard Studio Pro 11.13 — repair ALTER PAGE and make capabilities probe-gated#874
ako merged 2 commits into
mainfrom
mxcli-mcp

Conversation

@ako

@ako ako commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Onboards Studio Pro 11.13 for the MCP backend. Two commits: an ALTER PAGE regression 11.13 introduced, and the capability-model change that finding forced.

The 11.13 release notes announce none of this — they cover auto-port-selection, a status-bar port indicator, and four fixes to Studio Pro's MCP client. Everything below came from a live tools/list probe against 11.13 (fixture added at mdl/backend/mcp/testdata/tools-11.13.json).

1. fix(mcp): read pages whole on 11.13

11.13 gave pg_read_page a depth argument defaulting to 4, replacing deeper nodes with the literal string "...". ALTER PAGE is read-modify-replace-whole-page, so the truncated read went back as the new page body and pg_patch_page rejected it with PROP_NOT_PRIMITIVEALTER PAGE over MCP was broken on 11.13. The page was left intact, so this cost the feature rather than data. CREATE PAGE was unaffected (it does not read).

Measured live: Administration.Account_Overview read 32,594 bytes at full depth but 1,052 at the default, its whole widget tree collapsed to {"widgets":["...","..."]}. Not an edge case — all three PgTest pages sampled truncated too.

The fix has two halves, and the second is the durable one:

  • pgReadPage requests the full depth.
  • hasTruncationSentinel refuses a read still carrying a placeholder rather than letting a partial page reach a write (ADR-0005 guard-don't-drop), so the next change to the server's truncation default fails loudly instead of silently.

depth cannot be sent unconditionally — 11.11/11.12 declare pg_read_page additionalProperties:false without it, so the whole call would fail. Client.SupportsToolArg gates it on a live schema probe, defaulting to not sent.

2. feat(mcp): gate capabilities on the live probe and the project version

Implements ADR-0006 as revised (amended in place — it was still Proposed, and 0008 is now taken by identity-and-idempotence). The original split (probe ∪ table) was right; the keying and the division of labour were not.

  • Presence is probe-authoritative and now actually gates. A feature declares requires_tools; whether they are present comes only from tools/list. A missing tool, or a probe that did not answer, fails the feature closed and says which — a false "no" is the safe direction for a write path.
  • The version axis moves to the project's Mendix version. The old gate was dead code: serverVersionAtLeast compared serverInfo.version, frozen at 1.0.0 across 11.11/11.12/11.13, so no available_since above baseline could ever resolve true. No entry used it, which is why it went unnoticed. available_since_mendix replaces it via ProjectVersion().IsAtLeast — the precedent gateAttributeDefaults already set.
  • Federated tools (mcp_<server>_<tool>, proxied by Studio Pro from MCP servers the user connected to it) are split out, reported for visibility, and never gated on — mxcli does not control their contract.

Why presence cannot be tabulated, observed live: the same Studio Pro session reported 18 tools including mcp_mendix-marketplace_*, then 17 without it an hour later, with no restart. oql_generate likewise disappears when 11.13's new OQL-generation preference is off. A table asserting either would have been wrong within the hour, so capabilities.yaml now documents that tool presence must never be added to it.

Validation

  • Live against Studio Pro 11.13 (macOS host, socat bridge): the round-trip that previously errored now succeeds and the page compares byte-for-byte identical before and after; mxcli mcp capabilities reports 17 Studio Pro tools, 0 federated, 21 features resolved.
  • Controls — each half of the page fix was stubbed and the matching test confirmed to fail: removing the depth arg fails TestPgReadPage_RequestsFullDepth, removing the guard fails TestPgReadPage_RefusesTruncatedPage.
  • Unit coverage for missing-tool blocking, fail-closed-on-probe-failure, project-version gating (incl. nil/malformed), blocker-over-note precedence, and the federated split.
  • go build ./..., go vet, and the mdl/... + cmd/... suites pass (rebased onto current main, parser regenerated).

Docs

  • PED_MCP_CAPABILITIES.md: 11.13 identity row + full delta section, the dual-stack socat recipe (the documented TCP4-LISTEN one cannot work where host.docker.internal is IPv6), port-discovery guidance, and the onboarding procedure now requires diffing tool input schemas, not just names — name-only diffing is exactly what would have let this through.
  • fix-issue.md: symptom row appended.
  • Recorded that Concord is Windows-only — on macOS there is no path at all to DROP a standalone document, since PED has no delete tool and Concord was the only gap-filler.

Notes for review

  • Gating is genuinely stricter: a Backend with no client authors nothing. Correct for a not-connected MCP backend, but a behaviour change rather than a pure refactor. A guard prevents a pre-Connect() call pinning an empty surface into the session cache.
  • No linked issue — this came out of onboarding 11.13 rather than a filed report.

🤖 Generated with Claude Code

ako and others added 2 commits August 11, 2026 20:36
Studio Pro 11.13 gave pg_read_page a `depth` argument defaulting to 4,
replacing anything deeper with the literal string "...". ALTER PAGE is
read-modify-replace-whole-page, so the truncated read went back as the new
page body and pg_patch_page rejected it with PROP_NOT_PRIMITIVE, breaking
ALTER PAGE over MCP. The page was left intact, so this cost the feature
rather than data. CREATE PAGE was unaffected (it does not read).

Measured live on 11.13: Administration.Account_Overview read 32,594 bytes
at full depth but 1,052 at the default, its whole widget tree collapsed to
{"widgets":["...","..."]}. Not an edge case — all three PgTest pages
sampled truncated too.

pgReadPage now requests the full depth, and hasTruncationSentinel refuses a
read still carrying a placeholder rather than letting a partial page reach
a write (ADR-0005 guard-don't-drop). The guard is the durable half: it
makes the next change to the server's truncation default fail loudly
instead of silently. It matches the sentinel only as an array element, so a
caption legitimately reading "..." is real content and does not trip it.

`depth` cannot be sent unconditionally — 11.11/11.12 declare pg_read_page
additionalProperties:false without it, so the whole call would fail.
ListTools now captures each tool's inputSchema.properties and the new
SupportsToolArg gates the argument on that live probe, defaulting to false
when the probe fails: serverInfo.version is frozen at 1.0.0 across 11.11,
11.12 and 11.13, so it cannot discriminate releases.

The 11.13 release notes announce none of this, as 11.12 silently removed
pg_write_page (#697). The onboarding procedure now requires diffing tool
input schemas, not just tool names, since no tool mxcli calls was renamed.

Also records that Concord is Windows-only: on macOS there is no path at all
to DROP a standalone document, PED having no delete tool.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements ADR-0006 as revised. The original split — live probe ∪ version
table — was right; the keying and the division of labour were not.

Tool presence is now probe-authoritative and actually gates, instead of
being reported as decoration. A feature declares which tools it needs
(requires_tools — not observable, so it belongs in the table); whether they
are present is answered only by tools/list. A missing tool, or a probe that
did not answer, fails the feature closed and says which: a false "no" is
the safe direction for a write path, the alternative being a failure
mid-write against a tool that was never there.

The version axis moves from MCP serverInfo.version to the project's Mendix
version. The old gate was dead code: serverVersionAtLeast compared a value
frozen at 1.0.0 across 11.11, 11.12 and 11.13, so no available_since above
the baseline could ever resolve true. No entry used it, which is why the
defect went unnoticed. available_since_mendix replaces it, resolved through
ProjectVersion().IsAtLeast — the precedent gateAttributeDefaults already
set. An unparseable entry blocks rather than gating on zero.

Federated tools (mcp_<server>_<tool>, proxied by Studio Pro from MCP
servers the user connected to it) are split out of the tool list, reported
for visibility, and never gated on: mxcli does not control their contract.
They are excluded from the Studio Pro tool count.

That presence cannot be tabulated is not theoretical. The same Studio Pro
session reported 18 tools including mcp_mendix-marketplace_* and, an hour
later with no restart, 17 without it — the federated tool tracks Studio
Pro's own client connection. oql_generate likewise disappears when 11.13's
new OQL Generation preference is off. A table asserting either would have
been wrong within the hour, so capabilities.yaml now documents that tool
presence must never be added to it.

The report gains the project version, a federated-tools section, a warning
when the probe did not answer, and a note that it describes one session —
bug reports should carry it rather than a version number alone.

Verified live against Studio Pro 11.13: 17 Studio Pro tools, 0 federated,
21 features resolved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ako
ako merged commit 40ec849 into main Aug 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant