Core — Rosetta MCP tool vocabulary¶
Runtime-agnostic catalog of the rosetta_* MCP tools the plugin exposes via the
bundled rosetta-mcp-server binary. As of server v0.11.0 (api 1.12.0)
the surface is 46 tools — 5 composites + 41 read/write 1:1 wrappers, with
36 wrappers excluded — behind a server-side deny-by-default tool-policy (§7).
Every key sees the same tools; the upstream server decides per route what a key
may do (§7.1). Both adapter runtimes
(Claude Code, Cowork) bind to this vocabulary; the adapter MUST NOT rename tools,
collapse the composite/1:1 distinction, invent parallel names, or call a tool the
server tool-policy denies.
The binary registers the 1:1 wrappers mechanically from the vendored
api/rosetta-v1.yaml (rosetta_<operationId-snake-cased>); the composites come
from config/mcp/composites.yaml. The plugin manifest does not declare the
tools — the binary does, at startup.
This catalog covers READ and WRITE. The cross-cutting write discipline
(confirm-before-destructive, idempotency, enum validation, partition/access) is
core/write-safety.md; per-family detail is in core/engagement-twin.md,
core/governance-lifecycle.md, core/engagement-lifecycle.md,
core/engagement-canvas.md. Reach for those before driving a write.
1. Five composites (task-shaped) — the default reach¶
Composites bundle a common multi-call flow into one MCP tools/call. Source of
truth: config/mcp/composites.yaml.
| Composite | Purpose | Fans out to |
|---|---|---|
rosetta_turn |
One conversation turn end-to-end (project-scoped). | rosetta_create_conversation (idempotent) → rosetta_persist_conversation_turn → rosetta_decide_flow_next_action. Returns the flow decision. |
rosetta_engagement_turn |
One engagement-scoped turn; binds the session to an engagement and is meant to write turn semantics into the twin. | same three, with engagementId (slug) on create + an optional semanticProjection (decisions / gaps / citations) on persist. Returns the flow decision. In server v0.11.0 the persist step does not carry engagementId, so the projection is not written; use the 1:1 wrappers for that (core/conversation-lifecycle.md §11). |
rosetta_record |
Governance batch write. Always a DecisionTrace; conditionally an ADRApplication + a QueryTrace. Partial-success contract. | rosetta_create_decision_trace → (rosetta_record_adr_application if present) → (rosetta_create_query_trace if present). |
rosetta_query |
Context retrieval with expand=full (inlines governingADRs[], semanticEntities[], vocabularyTerms[]; removes N+1 hydration). |
rosetta_create_context_retrieval with expand=full forced. |
rosetta_engagement_canvas_slack |
An engagement's canvas as publish-ready Slack-canvas markdown, one call. | rosetta_get_engagement_canvas with format=slack; returns { status, text }. Hand text to the Slack MCP. See core/engagement-canvas.md. |
Reach for a composite first; fall back to the 1:1 wrappers (§2/§3) for fine-grained control or an endpoint no composite covers.
2. Read wrappers (fine-grained)¶
Grouped by family. All are non-mutating.
Context / patterns / ADRs / spec-manifest
| Tool | REST |
| --- | --- |
| rosetta_create_context_retrieval | POST /api/v1/context (sparse; expand=full opt) |
| rosetta_get_pattern | GET /api/v1/patterns/[id] |
| rosetta_get_a_d_r | GET /api/v1/adrs/[id] |
| rosetta_get_spec_manifest | GET /api/v1/spec-manifests/[id] |
Conversation / identity
| Tool | REST |
| --- | --- |
| rosetta_get_conversation_context | GET /api/v1/conversations/[id] |
| rosetta_get_authenticated_user | GET /api/v1/users/me |
Engagement (twin / memory / lifecycle / canvas)
| Tool | REST | Notes |
| --- | --- | --- |
| rosetta_list_engagements | GET /api/v1/engagements | discover engagementIds (slugs) |
| rosetta_get_engagement | GET /api/v1/engagements/[uid] | |
| rosetta_get_engagement_twin | GET /api/v1/engagements/[uid]/twin | full TwinDocument; since=[int revision] for delta; no include= (filter client-side) |
| rosetta_recall_engagement_memory | GET /api/v1/engagements/[uid]/memory | hybrid graph+vector; q, kinds=decision\|artifact\|gap\|session, limit, cursor |
| rosetta_get_engagement_canvas | GET /api/v1/engagements/[uid]/canvas | format=json (default) or slack; include= section subset |
| rosetta_get_digital_twin_node | GET /api/v1/digital-twin/nodes/[id] | one node by its UUID uid; include=history, asOf |
| rosetta_get_digital_twin_node_by_key | GET /api/v1/digital-twin/nodes/[label]/[key] | one node by label + catalog merge key (§8); reaches seeded canonical content, whose uids are slugs, and nodes with no uid; include=history, asOf. An engagement node needs a grant on that engagement or its account's owner/admin (403 otherwise); any other node is readable by any authenticated key |
Governance — reads included, every row needs a platform admin's key
(403 otherwise; §7.1)
| Tool | REST |
| --- | --- |
| rosetta_get_promotion_candidate | GET /api/v1/promotion-candidates/[id] |
| rosetta_list_promotion_candidates | GET /api/v1/promotion-candidates (filters: status, decisionPoint) |
| rosetta_get_governance_review | GET /api/v1/governance-reviews/[id] |
3. Write wrappers (fine-grained) — see core/write-safety.md first¶
Conversation / governance-batch members
| Tool | REST | Idempotency |
| --- | --- | --- |
| rosetta_create_conversation | POST /api/v1/conversations | 201 create / 200 exists on (sessionId, projectId, userId) |
| rosetta_persist_conversation_turn | POST /api/v1/conversations/[id]/turns | new turn each call; turnNumber skip = race. With engagementId (slug) in the body (api 1.10.0+): needs a grant on that engagement (403); semanticProjection decisions and gaps are validated, and a gap needs gapType + description (400/422); a key another lane, session or engagement holds is 409, refused before the turn is persisted. Without engagementId the projection is ignored. core/conversation-lifecycle.md §12 |
| rosetta_decide_flow_next_action | POST /api/v1/flow/next-action | read-shaped (no persist) |
| rosetta_create_decision_trace | POST /api/v1/decision-traces | 201/200 on (sessionUid, decisionPoint) |
| rosetta_record_adr_application | POST /api/v1/adr-applications | on (adrUid, engagementUid, surfacedBy) |
| rosetta_create_query_trace | POST /api/v1/query-traces | per RESOLVED_VIA target |
| rosetta_upsert_practitioner | POST /api/v1/practitioners | upsert on email (200 always) |
Engagement twin (core/engagement-twin.md)
| Tool | REST | Notes |
| --- | --- | --- |
| rosetta_apply_engagement_twin | POST /api/v1/engagements/[uid]/twin:apply | forensic lane: atomic edits[] for confirmed graph-canonical state; send Idempotency-Key; 200/409 |
| rosetta_apply_engagement_twin_rehearsal | POST /api/v1/engagements/[uid]/twin:apply-rehearsal | rehearsal lane: the honesty-routing target for [SIMULATED] / status:PROPOSED / simulationRunId content (core/write-safety.md §1.5). Admits traceKind:"runtime" and stamps the revision ProvenanceEvent provenance:"simulated". Available since mcp v0.8.7 (generated from the applyEngagementTwinRehearsal operation, tag engagement-twin). |
| rosetta_create_digital_twin_node | POST /api/v1/digital-twin/nodes | platform admin only, any label (403 otherwise); body nodeType, properties, domainIdentity (five-field identity, valid overrideMode), projectId (uuid); an own-lane label is 422 (§8) |
| rosetta_update_digital_twin_node | PATCH /api/v1/digital-twin/nodes/[id] | properties patch by UUID uid; optional baseVersion on a node outside any engagement only (stale = 409; on an engagement node, 422); same authz and 422s as the keyed form below |
| rosetta_update_digital_twin_node_by_key | PATCH /api/v1/digital-twin/nodes/[label]/[key] | patch by label + merge key (§8). An engagement node needs that engagement's lead or its account's owner/admin; every other (canonical) node needs a platform admin (403 otherwise). A change to the key that addresses the node is 422, and so is an own-lane label |
Engagement lifecycle (core/engagement-lifecycle.md)
| Tool | REST | Notes |
| --- | --- | --- |
| rosetta_create_engagement | POST /api/v1/engagements | clientUid REQUIRED (api 1.5.0; :Client.uid slug, lazily MERGEd; absent/empty/malformed → 422) + name; optional engagementUid slug ≤64; dual-write; 201/409/422 |
| rosetta_update_engagement | PATCH /api/v1/engagements/[uid] | name / status / clientUid (non-empty = edge move; "" = unlink, confirm-before; omitted = unchanged) |
| rosetta_create_project | POST /api/v1/projects | new project namespace |
| rosetta_compile_spec_manifest | POST /api/v1/spec-manifests/compile | exactly one of projectId / engagementId |
Governance three-gate (core/governance-lifecycle.md) — every row needs a
platform admin's key (403 otherwise; §7.1)
| Tool | REST | Gate |
| --- | --- | --- |
| rosetta_evaluate_decision_trace | POST /api/v1/decision-traces/[id]/evaluate | Gate 1, one trace |
| rosetta_run_gate1 | POST /api/v1/governance/gate1-run | Gate 1, every pending trace across all engagements |
| rosetta_create_promotion_candidate | POST /api/v1/promotion-candidates | Gate 2 (decisionPoint) |
| rosetta_create_governance_review | POST /api/v1/governance-reviews | Gate 3, open a review |
| rosetta_approve_governance_review | POST /api/v1/governance-reviews/[id]/approve | Gate 3 (irreversible) |
| rosetta_reject_governance_review | POST /api/v1/governance-reviews/[id]/reject | Gate 3 (destructive) |
| rosetta_request_governance_review_revision | POST /api/v1/governance-reviews/[id]/request-revision | Gate 3 |
| rosetta_rollback_a_d_r | POST /api/v1/adrs/[id]/rollback | ADR (destructive) |
Content ingest (content-ingest tag; mcp v0.11.0) — dry runs only
against production until the DT-RX-036 switch (§8, core/write-safety.md §1.7)
| Tool | REST | Notes |
| --- | --- | --- |
| rosetta_ingest_content | POST /api/v1/domains/[domainKey]/content:ingest | platform admin only (403 otherwise). One plugin run's canonical bundle, shaped like a twin:apply document: envelope bundleId, producer, runId, sourceBundleSha256 (+ note), then nodes[] and edges[]. One transaction; dryRun: true validates and returns the plan (status: planned, 200) without writing. A refused bundle is a 422 that lists every failure |
4. When to use which tier¶
- Composite first for the high-frequency flows (turn, engagement-turn, governance batch, full-context retrieval, canvas→Slack).
- 1:1 read wrapper when you hold a uid and want the canonical record, or when the sparse context default suffices.
- 1:1 write wrapper when a composite does too much, when writes are spread
across turns, or when you need fine-grained error handling — always under
core/write-safety.md.
The composite-vs-1:1 choice is intent-driven, not capability-driven.
5. Idempotency contract¶
| Tool(s) | Key / behavior |
|---|---|
rosetta_turn / rosetta_engagement_turn |
(sessionId, projectId, userId, turnNumber); create step idempotent, turnNumber increments server-side |
rosetta_create_conversation |
(sessionId, projectId, userId) → 201 create / 200 exists (NOT an error) |
rosetta_create_decision_trace / rosetta_record |
(sessionUid, decisionPoint) |
rosetta_record_adr_application |
(adrUid, engagementUid, surfacedBy) |
rosetta_upsert_practitioner |
email (always 200) |
rosetta_apply_engagement_twin |
client-supplied Idempotency-Key (uuid); 200 success / 409 conflict |
rosetta_update_digital_twin_node / _by_key |
optional baseVersion (the node's version from a read), for a node outside any engagement only; a stale one is 409, not an overwrite. On an engagement node (it keeps time on the engagement revision) a baseVersion is 422 |
rosetta_ingest_content |
bundleId: the same bundleId with the same body returns the first result (replayed: true, 200); the same bundleId with a different body is 409. A commit is 201 |
| reads | idempotent by definition |
Status codes: 200 where you expected 201 = idempotent hit (normal; do not
alarm). 409 = conflict → reload state, do not blind-retry; on a turn
persist it means the projection reused another lane's, session's or
engagement's key and, unless the detail says otherwise, the turn was not
persisted (core/conversation-lifecycle.md §12). 422 =
referential or contract failure → surface and fix the payload: an invalid
userId FK on conversation create (since v0.8.3); a node write that would change
the key addressing the node; a node create or patch on an own-lane label; a
baseVersion on an engagement node's patch; a refused ingest bundle (the body lists every failure). 401 = missing/invalid
bearer. 403 = this key may not do this (§7.1): on a governance tool, a
canonical node write, any node create, or rosetta_ingest_content it means
this key isn't a platform admin; on an engagement-scoped call it means no
grant on that engagement (or, for a write, not its lead or the account's
owner/admin). Neither is retryable (core/write-safety.md §4). Retry is safe on
the idempotent writes above; it is NOT safe on a 409.
6. Enum catalog (writes are validated server-side; off-enum = 400)¶
| Field | Allowed values |
|---|---|
decisionType |
architecture, configuration, trade-off, scope |
outcome |
accepted, rejected, modified, deferred |
retrievalStrategy |
graphrag, keyword, hybrid, direct_lookup |
surfacedBy |
agent_recommendation, manual_attachment, architecture_review |
phase (flow state) |
discovery, clarification, pattern-matching, recommendation, validation |
solutionMode / icp |
customer-360, agentforce-first, marketing-cdp, data-governance, analytics-first, integration-first, unknown |
overrideMode |
base, supplement, refine, replace, suppress (corrected v0.8.2 — the old extend/inherit values are gone) |
gapType (a turn projection's gap; required, with description) |
missing_intent, ambiguous_decision, unmatched_configuration, contradictory_signals |
Pre-validate against this table before any write; the server rejects off-enum values with 400.
7. Server tool-policy (the boundary)¶
The server exposes tools by allowlist (deny-by-default) —
config/mcp/tool-policy.yaml. Allowed tags: context, patterns, adrs,
digital-twin, spec-manifests, projects, conversations, flow,
governance, practitioners, identity, engagement-twin,
engagement-memory, engagements, engagement-canvas, content-ingest.
Denied (NOT exposed, not callable, must never be hand-rolled): accounts,
account-members, platform-admin (cross-account administration, including
granting, listing and revoking platform admins), engagement-access (ACL
grant/revoke), export (bulk Cypher/Markdown exfiltration), presence
(web-only SSE/heartbeat), twin-ratification (the human ratification lane;
core/write-safety.md §1.6), and the operations forkProject,
ratifyEngagementTwin and rejectEngagementTwin. If a flow seems to need a
denied capability, that is an operator / out-of-band action, not a plugin call.
7.1 The key decides (upstream authorization)¶
The tool list is the same for every key. The upstream rosetta-app-server authorizes each call against the bearer's user, so the same tool can succeed on one key and answer 403 on another:
| Tools | Who may call (403 otherwise) |
|---|---|
Governance: rosetta_run_gate1, rosetta_evaluate_decision_trace, rosetta_create_promotion_candidate, rosetta_list_promotion_candidates, rosetta_get_promotion_candidate, rosetta_create_governance_review, rosetta_get_governance_review, rosetta_approve_governance_review, rosetta_reject_governance_review, rosetta_request_governance_review_revision, rosetta_rollback_a_d_r |
a platform admin, reads included (api 1.11.0+, app-server v0.8.0) |
rosetta_create_digital_twin_node |
a platform admin, any label |
rosetta_update_digital_twin_node / _by_key on a node outside any engagement (canonical content) |
a platform admin |
rosetta_update_digital_twin_node / _by_key on an engagement's node |
that engagement's lead, or its account's owner/admin |
rosetta_get_digital_twin_node / _by_key |
an engagement's node: any grant on that engagement, or its account's owner/admin; any other node: any authenticated key |
rosetta_ingest_content |
a platform admin |
rosetta_get_engagement_twin / rosetta_apply_engagement_twin |
read: any grant on that engagement, or its account's owner/admin; apply: its lead, or the account's owner/admin |
rosetta_persist_conversation_turn with an engagementId |
the conversation's owner, holding any grant on that engagement or being its account's owner/admin (api 1.10.0+) |
- Platform admin is a property of the user who owns the key: a row in the
app-server's
platform_adminstable. It is not a key scope, and it is not therolethatrosetta_get_authenticated_userreturns (aroleofadminis a practitioner role, not a platform admin). No allowlisted tool reports it; the first 403 from one of the tools above is the signal. - Granting it is never a plugin action. The grant, list and revoke routes
sit in the denied
platform-admintag, so no tool on this surface reaches them; an existing platform admin makes a grant, out of band. - Not gated on platform admin:
rosetta_create_decision_trace,rosetta_record_adr_application,rosetta_create_query_traceand therosetta_recordcomposite. They are governance-tagged but are not gate routes. - The decision verbs stay on the agent surface (app-server
gate3-governance-authz.md, ruling Q-C-2): on a platform admin's key an agent can approve, reject, revise and roll back. The plugin's confirm-before rule (core/write-safety.md§1) is then the only interlock, and it is a client-side courtesy, not a control.
8. Wire-contract notes¶
engagementIdis a slug, not a UUID:^[A-Za-z0-9_.:\-]+$, ≤64 (e.g.nto-02,eng-nto-01). Applies to context, conversation create, the turn persist body,rosetta_engagement_turn, twin/canvas/memory/lifecycle calls.sessionId/projectId/userIdremain UUIDs.rosetta_get_engagement_twintakes NOinclude=; read the full TwinDocument and filter node types client-side. Usesince=[int revision]for a delta read.rosetta_compile_spec_manifesttakes exactly one ofprojectId(uuid) orengagementId(slug) — engagement-scoped compile since v0.8.1.- 422 documents referential-integrity failures on conversation create
(MySQL
user_idFK; theproject_idFK was dropped in platform migration 033). - Keyed node address (
*_by_key, mcp v0.10.0):labelis a catalog label;keyis its catalog merge key —qualifiedKeyon the eight inheritable labels (ContextPattern, ADR, BusinessIntent, VocabularyTerm, SemanticEntity, PlatformObject, EngineFunction, ContextArtifact) and on SourceArtifact (app-server v0.8.1), the label's own natural key otherwise (traceId,engagementId, ...). The binary percent-encodes the key as one path segment. A write that would change that key is refused with 422, on the UUID route too. - Own-lane labels —
Engagement,Client,Practitioner,EnablementSession,PromotionCandidate,GovernanceReview,SpecManifest,QualityFlag,QueryTrace— have their own API or gate. Node create and patch on them are refused with 422; reads are unaffected. rosetta_ingest_contentlands canonical, engagement-less labels only (ContextPattern, ADR, BusinessIntent, VocabularyTerm, SemanticEntity, PlatformObject, EngineFunction, SourceArtifact), each keyed byqualifiedKeyand in the path'sdomainKey. Created patterns landdraft, ADRs and BusinessIntentsproposed. Its closed edge allowlist is pinned to rosetta-platform's edge registry (db/schema/edge-registry.yaml) at the release the app-server vendors; an unlisted edge or edge property is 422, never ignored. Until the DT-RX-036 switch (rosetta-platform manifest §11B, E9-I1), no plugin submits to the production ingestion API: production use isdryRun: trueonly.
9. Schema introspection¶
Per-tool schemas live in api/rosetta-v1.yaml#/components/schemas/; the
tools/list response carries a description per tool. Read the OpenAPI spec
directly — do NOT introspect by calling a tool with an empty payload (the error
is not a schema).
10. What NOT to do¶
- Do not invent tool names or call a tool the §7 tool-policy denies.
- Do not call
/api/v1/*directly, bypassing MCP — the bearer lives in the binary (RCP-C-6); bypassing it leaks the token. - Do not call a composite for one of its writes — use the 1:1 wrapper.
- Do not blind-retry a 409; do not treat a 200-where-you-expected-201 as an error.
- Do not perform a destructive write without operator confirmation
(
core/write-safety.md). - Do not retry 401 with a different token (config error;
core/mcp-token.md). - Do not work around a 403. On a governance tool, a canonical node write, a
node create or
rosetta_ingest_contentit means this key isn't a platform admin: surface that and stop (§7.1). - Do not commit an ingest bundle to production (
rosetta_ingest_contentwithoutdryRun: true) before the DT-RX-036 switch (§8).
Consumed by¶
skills/agent-orchestration/SKILL.mdskills/context-retrieval-flows/SKILL.mdskills/conversation-lifecycle/SKILL.mdskills/decision-trace-capture/SKILL.mdskills/engagement-twin/SKILL.mdskills/governance-lifecycle/SKILL.mdskills/engagement-lifecycle/SKILL.mdskills/engagement-canvas/SKILL.md
This page as Markdown — for pasting into Claude or another assistant · llms.txt