Skip to content

MCP

What MCP does here

MCP is the agent-facing protocol surface for clumsies. It is how an agent discovers available material, loads the specific rules, workflows, and context it needs, declares which constraints it actually applied, and proposes edits back into the system.

That makes MCP more than a transport layer. It is the runtime contract between agent work and the managed rule, context, and attestation model.

The current tool surface

The current implementation exposes these MCP tools:

Tool familyTools
session and attestationmemory.setup, memory.discover, memory.load, memory.refer, memory.submit, memory.reject
draft mutationsdraft

This is the real protocol surface in the running code. The server test suite explicitly asserts that memory.begin, memory.complete, memory.startup, memory.list, and memory.activate are not part of the public tool list.

The core runtime cycle

The stable mental model now matches the current META_PROMPT very closely:

  1. bootstrap the session with memory.setup
  2. discover relevant material with memory.discover
  3. load only the content the task actually needs with memory.load
  4. apply the loaded rules in the work
  5. declare applied constraints with memory.refer
  6. use draft when the task is to refine rules, context, or MPF
  7. close the turn with memory.submit or memory.reject

That cycle is the runtime expression of the whole product:

  • Hub publishes authoritative state
  • local cache keeps runtime fast
  • MCP serves that state to the agent
  • attestation records what actually happened

Result envelope

Every successful tool call is wrapped in the same envelope shape:

json
{
  "content": [
    {
      "type": "text",
      "text": "{...serialized structured result...}"
    }
  ],
  "structuredContent": {
    "...": "tool-specific payload"
  },
  "isError": false
}

Error results use the same outer shape, but set isError to true and place an error string under structuredContent.error.

This detail matters because the protocol is not only human-readable. Agents are expected to consume the machine-readable structuredContent payload directly.

memory.setup

memory.setup bootstraps the session. It returns the current workspace identity, the current session ID, and the current META_PROMPT frame.

Input

FieldTypeRequiredMeaning
session_idstringyeshost-agent session or thread id
knownHashstringnolets the client ask for delta behavior if it already knows the last meta-prompt hash

Structured result

FieldMeaning
workspaceIdauthoritative workspace ID
sessionIdsession identifier used to group later attestation events
mpf.hashcurrent META_PROMPT hash
mpf.contentcurrent META_PROMPT content when changed or initially loaded
mpf.changedfalse when the caller already knows the same hash

A typical result looks like this:

json
{
  "workspaceId": "ws-4a5c282474c9b5d9385dec0502267738",
  "sessionId": "4f04001af902673e92094a7c59d86abb",
  "mpf": {
    "hash": "1eb791139b9f265846dc2d0d8d6a0c1ce5116a245c42829838ddcb492fc13337",
    "content": "# clumsies\n..."
  }
}

In the current runtime, that meta-prompt frame comes from the workspace-scoped META_PROMPT.md asset. The session object also records a local .setup attestation event when the session is created.

The current bootstrap content is intentionally simpler than earlier revisions. It now frames the protocol as discover -> load -> apply -> refer -> refine -> submit, and its priority model is loaded rules > this meta-prompt > your defaults.

memory.discover

memory.discover discovers available rules, workflows, and context files without loading their full content.

Input

FieldTypeRequiredMeaning
kindstring enumnoone of rule, workflow, context
groupstringnofilter by first path segment or logical group
querystringnofree-text query across searchable metadata

Structured result

The tool returns:

json
{
  "items": [
    {
      "id": "p-e60e775a-fc91-4780-bd32-2bb451404298",
      "kind": "workflow",
      "path": "workflow/CODING.md",
      "name": "CODING",
      "group": "workflow",
      "hash": "sha256:..."
    }
  ]
}

Each item can include:

FieldMeaning
idstable object ID
kindrule, workflow, or context
pathcurrent workspace-relative path
namedisplay name derived from the path
groupoptional group value
hashcurrent content hash
descriptionoptional metadata description when present

Discover is inventory, not content delivery. Its job is to let the agent choose what is relevant before spending context window on full content.

memory.load

memory.load resolves full content for the selected IDs. This is where protocol flow stops being inventory and becomes working task context.

Input

FieldTypeRequiredMeaning
idsstring arrayyesone or more rule, workflow, or context IDs
knownHashesobject mapyes{id: hash} map for delta loading; include every requested id

Each ids entry must also be present in knownHashes. Pass the remembered hash when available. Pass an empty string when the caller explicitly does not know the hash yet. Omitting knownHashes, or omitting one requested id from the map, is invalid.

Structured result

The tool returns:

json
{
  "workspaceId": "ws-4a5c282474c9b5d9385dec0502267738",
  "items": [
    {
      "id": "p-e60e775a-fc91-4780-bd32-2bb451404298",
      "kind": "workflow",
      "path": "workflow/CODING.md",
      "changed": true,
      "hash": "sha256:...",
      "hasDraft": false,
      "content": "# ...",
      "constraints": [
        {
          "id": "Steps",
          "name": "Steps",
          "text": "Inspect the diff and suggest a commit message.",
          "textHash": "..."
        }
      ]
    }
  ]
}

Important item fields are:

FieldMeaning
changedwhether the current hash differs from the caller's knownHashes entry
hashcurrent content hash
hasDraftwhether the loaded result resolves to draft-aware state
draftBaseHashoptional base hash when draft-aware content is involved
contentfull text content, or null when unchanged under delta loading
constraintsreferable rule/workflow constraint entries parsed from the loaded content

For rules and workflows, the returned content includes the refer reminder footer. Context items do not get that footer.

Delta loading only suppresses repeated content text. For rule and workflow items, constraints are still returned when changed is false and content is null, because agents need those stable entries to call memory.refer without guessing from markdown.

In this protocol, a constraint is a referable semantic markdown section in a rule or workflow file. It is either a whole H2 section, or one list item inside an H2 section. A whole H2 section uses the H2 title as its stable returned id. A list item uses H2 title/ordinal, such as Steps/1 and Steps/2. The name field is the H2 title used for display/grouping, and text is the H2 body or list item content. Agents must copy the returned id exactly into the constraintId wire field in memory.refer; they must not invent IDs.

memory.refer

memory.refer is the strongest usage signal in the model. It is the point where the agent claims that one of the constraints entries returned by memory.load for a rule or workflow actually shaped the turn.

Context files are reference material, not refer targets. A context ID supplied as ruleId is rejected.

Input

FieldTypeRequiredMeaning
refsobject arrayyesone or more declared constraint references

Each ref object can contain:

FieldTypeRequiredMeaning
ruleIdstringyesstable rule or workflow ID
constraintIdstringyeswire field containing an exact returned constraints[].id value
ruleHashstringnocurrent content hash when available
reasonstringnohuman-readable explanation of why the constraint mattered

Structured result

json
{
  "ok": true,
  "count": 2
}

count is the number of accepted reference objects processed in that call.

Retryable errors

memory.refer validation errors are structured so agents can retry instead of treating the text message as opaque. Unknown rule/workflow IDs tell the agent to rediscover and reload. Unknown constraint IDs include the valid constraint candidates for that rule/workflow when available.

Example invalid constraint response:

json
{
  "error": "memory.refer constraintId 'Step' is not valid for ruleId 'p-...'; retry with one of: Steps",
  "code": "unknown_constraint",
  "retryable": true,
  "retryAction": "retry_with_valid_constraint",
  "validConstraints": [
    {
      "id": "Steps",
      "name": "Steps",
      "text": "Inspect the diff and suggest a commit message."
    }
  ]
}

Agents should use validConstraints[].id exactly.

memory.submit

memory.submit closes a successful turn by recording the agent summary.

Input

FieldTypeRequiredMeaning
summarystringyesshort summary of the completed work

Validation

  • summary must be present
  • summary must be a string
  • summary must not be empty

Structured result

json
{
  "ok": true
}

In the current implementation, this records an .agent_report attestation event.

memory.reject

memory.reject closes an unsatisfactory turn when the output did not follow loaded constraints.

Input

FieldTypeRequiredMeaning
reasonstringnooptional rejection reason

Structured result

json
{
  "ok": true
}

In the current implementation, this records a .reject attestation event.

draft

draft stages local drafts instead of mutating Library rules, workspace context, or MPF.

The input is a tagged command object:

json
{
  "resource": "context",
  "op": {
    "update": {
      "id": "ctx-123",
      "body": "# New content\n",
      "description": "Clarify setup notes"
    }
  }
}

op must contain exactly one key. The protocol has one public MCP tool, and payloads stay typed.

Top-level input

FieldTypeRequiredMeaning
resourcestring enumyesone of context, rule, or mpf
optagged objectyestagged operation

create

Creates a new draft file.

FieldTypeRequiredMeaning
pathstringyestarget path for the new draft
bodystringyesdraft content
descriptionstringnooptional human-facing summary

Structured result

json
{
  "ok": true,
  "draft_path": "spec/new-context.md"
}

update

Creates a modify draft against an existing object. For context and rule, the implementation resolves id through the manifest, reads the current cached file, computes a base hash, and creates a draft. For MPF, id should be META_PROMPT.md.

FieldTypeRequiredMeaning
idstringyescontext id, rule id, or META_PROMPT.md
bodystringyesreplacement draft body
descriptionstringnooptional summary

rename

Creates a rename draft. rename is valid for context and rule; MPF has the reserved path META_PROMPT.md and cannot be renamed.

FieldTypeRequiredMeaning
idstringyescontext id or rule id
new_pathstringyesproposed new path
descriptionstringnooptional summary

delete

Creates a delete draft for an existing resource. If delete targets a create-only draft with no manifest entry, the client treats the call as discarding that create draft.

FieldTypeRequiredMeaning
idstringyesresource id, draft path, temp id, or MPF
descriptionstringnooptional summary

discard

Discards an existing draft object. This is different from delete: delete proposes deletion of a real resource. discard removes an unsubmitted draft.

FieldTypeRequiredMeaning
idstringyesany draft or resource identifier

Current error behavior

Several validation and runtime errors are already stable enough to document:

SituationResult
invalid argument types or missing required fieldsisError: true with an error message
unknown tool nameUnknown tool
memory.load receives an unknown rule IDUnknown rule id
memory.refer receives an unknown rule/workflow IDstructured code: "unknown_rule_or_workflow", retryable: true, retryAction: "rediscover_and_reload"
memory.refer receives an invalid constraint IDstructured code: "unknown_constraint", retryable: true, retryAction: "retry_with_valid_constraint", optional validConstraints
draft path is unsafeunsafe path
draft target is missingfile not found in cache
create collides with an existing draftdraft already exists

For memory.submit, validation is slightly stricter than the schema summary alone suggests. summary is required, must be a string, and must not be empty.

MCP and attestation

The protocol is tightly coupled to attestation, but not in a noisy way.

Each meaningful runtime action records structured local evidence. memory.discover, memory.load, memory.refer, memory.submit, memory.reject, and draft operations generate attestation events that later feed Hub-side aggregation.

This is one reason clumsies is different from plain prompt storage. The protocol is not there only to serve content. It is there to make rule use and content-change proposals legible.