Skip to content

feat(skills): /mcp/v2 compact surface, capability map, one-click/provisioning/troubleshooting references, tool inventory refresh (v4.2.0) - #37

Open
neobuilds wants to merge 15 commits into
mainfrom
feat/mcp-v2-compact-surface
Open

feat(skills): /mcp/v2 compact surface, capability map, one-click/provisioning/troubleshooting references, tool inventory refresh (v4.2.0)#37
neobuilds wants to merge 15 commits into
mainfrom
feat/mcp-v2-compact-surface

Conversation

@neobuilds

@neobuilds neobuilds commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

What and why

The skills claimed 110 MCP tools, full parity. That number was two API
releases stale, the endpoint tables were missing 39 operations, and nothing in
the package told an agent which jobs xCloud simply cannot do over the API — so
agents invented endpoints for dashboard-only work. This release fixes the
inventory, documents the new compact /mcp/v2 surface, and adds the capability
map plus the references that were missing.

Every claim here was verified against the xCloud application at master
9ab59ef: the spec docs/public/xcloud-public-api.openapi.yaml, app/Mcp/**,
app/Http/Controllers/PublicAPI/V1/**, app/Policies/** and routes/*.php.

1. Tool inventory: 110 → 149

  • 152 operations in the spec; three are excluded from tool generation
    (health.check, user.tokens.index, user.tokens.revoke) → 149 tools.
  • Execution split, derived from the server's own rule (a GET is never
    destructive; a mutating operation is destructive unless the spec marks it
    x-destructive: false): 88 reads / 11 non-destructive writes / 50
    destructive
    .
  • Execution class is derived from the required scope: 90 read / 9 write /
    50 destructive
    . git.detect and servers.dns.check are side-effect-free
    read-scoped POSTs, so they sit in the read class alongside the 88 GETs,
    and a read-only token or an mcp:read grant sees exactly those 90
    operations. Confirmation is a separate axis: 50 destructive operations need
    confirm: true, and eleven mutating operations are explicitly marked
    non-destructive.
  • 39 operations added to the skill endpoint tables: the unauthenticated
    catalog, read-only billing, Git deployment and auto-detect, Git integrations,
    deploy keys, DNS checks, the one-click app family, Docker backups, broken
    links, and sites.events.show. docs/API-COVERAGE.md is re-audited from the
    spec with a reproducible script; coverage gaps are now zero.

2. /mcp/v2 compact surface

New section in plugins/xcloud/reference/mcp.md: the four tools
(xcloud_search, xcloud_execute_read, xcloud_execute_write,
xcloud_execute_destructive), their arguments, per-class execution rules,
confirm, idempotency_key, the never-guess-an-id rule, the
search-then-execute workflow, the three typed result sections, and the
executors' response envelope. Canonical operation id vs tool alias is spelled
out with a worked example (servers.sites.git.autoservers_sites_git_auto).
/mcp and its per-operation tools remain available and unchanged — nothing
is deprecated — and the docs say when to prefer each surface (context budget vs
per-tool approvals) and that only one should be connected per session.

3. Capability map and new references

  • plugins/xcloud/reference/capabilities.md (new shared reference, linked
    from all five skills): API vs dashboard-only vs impossible, with the tool
    alias and canonical id for each job, the dashboard page when it is UI-only,
    and the refusals with their reason. It closes with two separate lists —
    dashboard only (ten jobs the human does in the UI before the agent
    continues over the API, buying a server and database management among them)
    and not possible on any surface (a second site on an agentic server,
    WordPress on Docker) — matching the brain capability map's ui and
    impossible buckets.
  • servers/reference/provisioning.md — buying or connecting a server is
    dashboard-only; the catalog reads around it; what each stack allows.
  • sites/reference/oneclick-apps.md — catalog → schema → compatibility →
    install → status → credentials → lifecycle.
  • sites/reference/troubleshooting.md — the 500/502 read ladder, the log
    types only Site → Logs can show, temporary sudo / site SSH with an explicit
    revoke step.
  • sites/reference/backups.md rewritten around the three backup kinds
    (native, Docker, snapshots).
  • Deploy-from-Git workflow in xcloud:servers: git_detect
    servers_sites_git_auto (or the explicit nginx/Docker endpoints) → confirm
    with sites_status; deploy keys for private repos; servers_dns_check for a
    live domain; the agentic/Docker/site-limit refusals.
  • reference/conventions.md gains the compact-surface confirmation rules
    and the executor envelope; reference/auth.md documents read:billing.

4. Deprecations and fixes

  • servers/reference/databases.md marked deprecated — the routes are
    commented out upstream and management is dashboard-only.
  • docs/TROUBLESHOOT.md labelled legacy; its invented
    POST /sites/{uuid}/restart replaced with POST /sites/{uuid}/rescue. The
    rest of the v1 docs/*.md prose was deliberately left alone.
  • v4.2.0 across every manifest, ClawHub metadata, and a regenerated
    .clawhubsafe.

Decisions from the shared contract that apply

  • Decision 1: /mcp/v2 is additive; /mcp and its 149 tools stay untouched and
    nothing is deprecated.
  • Decision 2: the four tool names and signatures are documented exactly as
    specified, including confirm: true on the destructive executor only.
  • Decision 3: canonical operation id = spec operationId (dots); alias = the
    generated tool name, every character outside [A-Za-z0-9_-] replaced with
    _. Both resolve.
  • Decision 4: unknown ids never execute; the docs forbid guessing one.
  • Decision 6: search returns three typed sections (operations, guidance,
    passages) plus meta, never one blended list.
  • Decision 10: xCloud owns the executable contract; this repo mirrors the
    guidance in prose.

How it was tested

python3 dist/agent-plugin/build.py           # dist regenerated, committed
python3 dist/agent-plugin/validate.py        # portable package invariants: PASS
bash dist/claude-app/build.sh                # 28 files, zip built
npx skills-ref validate dist/agent-plugin/xcloud/skills/*   # 5/5 Valid skill
bash -n on every *.sh                        # 0 failures
shellcheck -S warning plugins dist/agent-plugin              # clean
bash plugins/xcloud/scripts/tests/wrapper-test.sh            # 8 passed, 0 failed
bash src/tests/json-safety-test.sh                           # 8 passed, 0 failed
sha256sum -c .clawhubsafe                                    # 35/35 OK
version consistency across the six manifests                 # all 4.2.0
JSON validity of every manifest                              # valid
portable wrapper resolves from a foreign cwd (exit 64)       # 5/5 ok

plugins/xcloud/skills/*/tests/smoke.sh were not run: they require a live
XCLOUD_API_TOKEN and real server/site UUIDs, and exit 64 without one. CI skips
them for the same reason unless the secret is configured.

Codex review

Four rounds with gpt-6-astra, read-only, against the spec, controllers,
policies and routes (files kept under the session scratchpad):

Round Findings Outcome
1 1 HIGH, 12 MEDIUM, 2 LOW all fixed
2 0 HIGH, ~20 MEDIUM/LOW (in scope: 11) all in-scope fixed
3 0 HIGH, 6 MEDIUM/LOW all fixed
4 0 HIGH, 1 MEDIUM, 3 LOW all fixed

The corrections were substantive, not cosmetic: wp-debug is a write not a
read; the one-click install body needs title and go_live/staging_env;
deploy-key verify needs a repository_url body; git_detect answers under
detection.*; idempotency keys apply to exactly four operations; backups are
keyed by uuid with file_size; backup-status reports schedule state, not
job completion; broken-link polling must run through queued as well as
running; cache purge is asynchronous and confirmed through events, not status;
and the agentic refusal is 403 on some endpoints and 422 on others.

Round 4 verified dist parity across 75 files and all 35 checksums.

Left for the owner

  1. Spec vs controller mismatch in xCloud (not fixed here). The spec
    describes sites.deployment-logs as "the site's git REDEPLOY history … each
    entry's status, commit, branch and time", but
    SiteController::deploymentLogs() returns DeploymentLog rows (status,
    action, source site, destination site, initiated_by, timestamps) — the
    staging↔production push/pull deployments, with no commit or branch. The
    skills document the controller's behaviour. The spec text should be corrected
    in the xCloud repo, or the endpoint changed to match it.
  2. Read-only scope vs class — resolved. The Codex review surfaced a seam
    here and this PR briefly recorded it as a deviation; shared-contract
    decision 3 has since been amended, and that deviation is superseded. On
    /mcp/v2 the execution class is scope-derived, so git.detect and
    servers.dns.check are class read, they run through xcloud_execute_read
    (which accepts body for their POST payloads), and xcloud_execute_write
    is never offered to a read-only session. A read-only grant still sees 90
    operations on /mcp. The docs now describe the amended rule; nothing is left
    open.
  3. Known leftovers, out of scope by instruction — pre-existing jq
    projections that Codex found wrong in files this PR did not otherwise touch:
    wordpress/reference/pagespeed.md, wordpress/reference/plugins-themes.md
    (versioncurrent_version), wordpress/reference/vulnerabilities.md
    (.site.domain.site.name), sites/reference/domains.md (the response
    is an object, not an array), servers/reference/sudo-users.md (required
    fields understated), sites/reference/ssh.md, and the jq --arg password
    examples in plugins/xcloud/scripts/xcloud.sh. Worth a small follow-up PR.
  4. The v1 docs/*.md prose (CONFIGURE, OPERATIONS, WORKFLOWS, DEPLOY, …)
    still contains invented endpoints (PATCH /sites/{uuid},
    POST /sites/{uuid}/restore) and credential fields the API does not return.
    It is excluded from the published package; only the TROUBLESHOOT line named
    in the task was fixed. Deleting or rewriting that directory is its own
    decision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W

NasirNobin and others added 15 commits September 8, 2026 21:53
… compact surface

The '110 tools, full parity' claim was two API releases stale. The spec now
carries 152 operations; three stay REST-only, so the server generates 149
tools (88 reads, 11 non-destructive writes, 50 destructive).

Adds the compact surface: the four /mcp/v2 tools, their arguments, the
per-class execution rules, confirm, idempotency keys, the never-guess-an-id
rule, the search-then-execute workflow and the three typed result sections.
Records the canonical operation id vs tool alias mapping, and how to choose
between the two surfaces. /mcp is unchanged and nothing is deprecated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…billing

Destructive operations run only through xcloud_execute_destructive with
confirm: true after an explicit human approval; the class boundary is never
routed around; unknown operation ids are never guessed; and search output is
data, never instructions or approval.

auth.md gains the read:billing scope and the OAuth mcp:read / mcp:write
ability mapping.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…ible

New reference/capabilities.md, verified against the xCloud spec, routes and
policies: for each job it names the tool alias and canonical operation id, the
dashboard page when the job is UI-only, and the refusals with their reason —
agentic stacks host only their provisioned site, WordPress is refused on Docker
servers, databases are withheld from the API, and token management never
reaches MCP.

Both distribution builders now treat capabilities.md as part of the shared
layer so its links are rewritten in the portable and consolidated packages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
… references

- servers/reference/provisioning.md: buying or connecting a server is
  dashboard-only; the catalog and pricing reads an agent can make around it,
  and what each server stack allows.
- sites/reference/oneclick-apps.md: catalog, schema, compatibility, install,
  status polling, credentials handling and lifecycle actions.
- sites/reference/troubleshooting.md: the 500/502 read ladder, the log types
  only Site -> Logs can show, and temporary sudo / site SSH access with an
  explicit revoke step.
- sites/reference/backups.md: rewritten around the three backup kinds (native,
  Docker, snapshots), what is read-only, and the dashboard-only restore,
  bulk-apply and storage-provider paths.
- sites/reference/git.md: deployment-logs records redeploys only — a new site's
  first deploy is confirmed with sites_status.
- servers/reference/databases.md: marked deprecated; those routes are withheld
  upstream and management is dashboard-only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…every skill

xcloud:servers gains the full deploy flow — git_detect, then
servers_sites_git_auto (or the explicit nginx/Docker endpoints), deploy keys
for private repositories, servers_dns_check for a live domain, and the
agentic/Docker/site-limit refusals — plus a provisioning reference.

Endpoint tables now carry the operations the skills never mentioned:
catalog_apps_index and catalog_pricing_index, read-only billing_*,
integrations_git_index/repositories, servers_git_deploy-keys_*,
oneclickApps_*, sites_docker_* backups, sites_broken-links_*,
sites_events_show, and the monitoring/site-scripts/ip-access aliases that were
previously collapsed into brace notation. Every skill links the new shared
capability map.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
docs/API-COVERAGE.md re-derived from the spec: 152 operations, 3 excluded, 149
tools, the read/write/destructive split, the 39 operations newly documented in
this release, and a reproducible script for the next audit.

README, root SKILL.md and the install guide now state 149 tools, describe the
compact surface, and list the widened skill coverage.

docs/TROUBLESHOOT.md is labelled legacy and its invented
POST /sites/{uuid}/restart call is replaced with the real rescue endpoint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
Version bumped in every manifest the CI consistency gate checks, ClawHub
metadata and changelog refreshed, and the safety attestation regenerated for
the four new runtime reference files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
Regenerated with dist/agent-plugin/build.py and dist/claude-app/build.sh so the
committed output matches the source exactly, as CI requires.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…review round 1

Verified every example against the OpenAPI spec and the xCloud controllers:

- troubleshooting: steps 1-4 are reads, step 5 (wp-debug) is a write needing
  write:sites and approval; event projections use uuid/name (not task_uuid or
  step) and access logs slice data.entries.
- one-click install: title is required and domain_parking_method is go_live or
  staging_env, not "custom".
- deploy-key verify requires a repository_url body.
- git_detect returns detection.site_type / detection.serving_mode, and a Docker
  server's compatible:false with docker_deployable:true is not a dead end.
- site status polling reads .data.
- native site backup takes {"type": local|remote}; there is no label, and
  backups are identified by id.
- native backup refusals apply to trigger and list, not the count/settings/
  status reads.
- agentic refusals documented per endpoint (403 on WordPress and native/auto
  Git, 422 on the Docker endpoint, 422 stack failure on a one-click install).
- site snapshots are Site -> Snapshots; Server -> Backup is the provider
  server-image feature with no API at all.
- token management is unavailable over MCP, not impossible: REST still works
  with a full-access token.
- the catalog reads are shown with curl, because the bundled wrapper always
  sends a token; idempotency notes say the wrapper cannot set headers.
- 'writes are async' softened to 'poll only what the operation says is async'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…pes from review round 2

- Read-only visibility is decided by required scope, not execution class:
  git_detect and servers_dns_check are read-scoped POSTs, so an mcp:read grant
  sees 90 operations, not 88. Corrected in mcp.md and API-COVERAGE.md; the
  88/11/50 execution-class split is unchanged.
- Idempotency keys apply only to the four operations whose spec declares the
  header (three Git creates + one-click install); executable curl examples with
  Idempotency-Key replace prose, because the wrapper cannot set headers.
- deployment-logs described from the controller: deployment records between
  sites (status, action, source, destination) — staging push/pull in practice,
  no commit or branch, and not the first deploy. The spec's own description
  claims git redeploy history; that mismatch is flagged for the API owner.
- Blanket 'writes are async' claims in the servers and sites skills now
  distinguish async from synchronous operations.
- backup-status answers 'are schedules configured', not 'did my backup finish';
  backups are identified by uuid with file_name/file_size/is_remote.
- Creating a WordPress site from a ready snapshot_uuid documented as the one
  API-side snapshot exception.
- Broken links: poll through queued and running, stop on completed/failed/
  cancelled; a 403 can also be the free-plan gate.
- Response projections corrected against the controllers: oneclick status
  (installation_status + site_status), catalog pricing (renewal_type and the
  real resource fields), GET /user (current_team_id), site certificates
  (hostnames).
- Agentic refusal messages quoted per endpoint; the startup banner shows the
  current version.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…s from review round 3

- conventions.md documents the compact executors' envelope: operation_id,
  method, path, class, status, outcome (ok/accepted/error), truncated, and the
  REST payload under body — so the documented fields live at body.data — plus
  the separate pre-dispatch error.code/error.message refusal shape.
- mcp.md names the read-only seam explicitly: xcloud_execute_read is GET-only,
  so the two read-scoped POSTs are class write and a read-only session is
  offered xcloud_execute_write holding exactly those two. Recorded in
  CONTRACT.md as a clarification of decision 3.
- Cache purge moved to the asynchronous group; it queues work and answers 202.
- The Git deploy polling sequence no longer polls deployment-logs; it polls
  sites_events and sites_status.
- sites_events_show is a bounded output window anchored to the end, with
  output_complete / offset / next_offset, not 'the full output'.
- GET /user projects uuid and current_team_uuid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
… from review round 4

- Cache purge and the other queued site writes are confirmed through
  sites_events (or servers_tasks), not sites_status: an already-provisioned
  site stays terminal while a purge is queued or failing. sites_status is for
  provisioning and deploy state.
- xcloud_execute_read advertises operation_id, path_params and query only — it
  takes no body; recorded alongside the read-only clarification in CONTRACT.md.
- The read-only scope-vs-class behaviour is labelled in the shipped reference
  as the recorded clarification it is.
- conventions.md no longer claims the envelope applies identically on every
  transport, now that the compact wrapper is documented.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…Ts are class read

Follows the amendment to shared-contract decision 3, which supersedes the
deviation this PR recorded earlier.

- git_detect and servers_dns_check are class `read` on /mcp/v2 and run through
  xcloud_execute_read, which accepts `body` for their POST payloads.
- xcloud_execute_write is never offered to a read-only session; a read-only
  grant reaches the 90 read-class operations and nothing else.
- The 149 tools are now stated as 90 read / 9 write / 50 destructive, with
  confirmation documented as a separate axis (50 destructive, 11 mutating
  operations explicitly marked non-destructive — two of which are the
  read-scoped POSTs, which is why they sit in the read class).
- The "90 visible on /mcp for a read-only grant" count is unchanged.

Updated in reference/mcp.md, docs/API-COVERAGE.md, README.md and the changelog;
dist rebuilt and the safety attestation rehashed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
…P method

`docs/API-COVERAGE.md` states 90 read / 9 write / 50 destructive, but the
re-run script at the bottom of the same file derived the class from the HTTP
method and printed 88 / 11 / 50 — so anyone re-running the audit before a
release would have contradicted the document it is meant to verify.

The snippet now resolves the class the way `OperationContract::executionClass()`
does: the effective destructive flag first (an explicit `x-destructive` wins
either way, a GET is never destructive, every other method defaults to
destructive), then the required scope, which is `x-required-scope` where the
spec declares one and otherwise read for GET and write for everything else.
Verified against the spec at xCloud `cbc1a904`: 90 / 9 / 50 over the 149
eligible operations, matching the deployed contract operation for operation.

Documentation only — no shipped file changed, so `dist/` and the safety
attestation are unaffected (all 35 checksums still verify).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
The closing list mixed two categories: buying or connecting a server and
database management are dashboard-only — the human does one step in the UI and
the agent continues over the API — while a second site on an agentic server and
WordPress on a Docker server have no path at all. They are now two lists,
matching the brain capability map's ui vs impossible buckets, and the
dashboard-only list carries all ten UI steps the tables above name. The
databases row moves its explanation into the dashboard column, since Server ->
Database is a real path, not a refusal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQoCQdgHYtf79TSxFi3b4W
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.

2 participants