soul.demarkus.io/plans/mcp-resources-prompts.md/v4 draft reader meta

Plan: MCP resources + prompts — attach-without-turns

Status: drafted 2026-07-05 · Repo: demarkus (demarkus-mcp client) · Decisions D1–D4 open (recommendations inline) · Follow-up phase named by /plans/mcp-client-ergonomics.md.

Problem

Everything an agent gets from demarkus today costs a tool turn, and the result lands as tool output rather than first-class context. MCP has two primitives built for exactly this gap, and demarkus-mcp implements neither:

  • Resources — client-attachable context. In Claude Desktop the user picks a resource and attaches it; in Claude Code resources can be referenced and read without the model spending a turn deciding to fetch. A demarkus doc as a resource = "put this doc in context" as a UI action, zero turns.
  • Prompts — server-vended workflows that surface as slash commands (/mcp__<server>__<prompt> in Claude Code, prompt picker in Desktop). The orientation strategy the ergonomics phase encoded into tool descriptions can be a first-class command instead of prose the model must remember to follow.

mcp-go v0.44 supports both natively (AddResource, AddResourceTemplate with RFC 6570 URI templates, AddPrompt with typed arguments); capability advertisement is automatic on registration.

Workstreams

R1 — resources (attach a doc without a turn)

  • Resource template mark://<host>/{+path} registered at startup (host known from -host; without -host, template over {host}/{+path}). Read handler: parse URI → FETCH → TextResourceContents with text/markdown. Reuses the ergonomics conventions: a #anchor fragment in the resource URI attaches just that section (mdoutline.Section).
  • Concrete resources (what shows in resources/list): the index hub (/index.md) and the agent manifest (/.well-known/agent-manifest.md) registered statically — the two entry points every demarkus server has.
  • Errors map to MCP resource errors (not-found etc.), never empty content.

R2 — prompts (workflows as slash commands)

V1 set (small, matching what the ergonomics tools already teach):

  • orient (arg: url, required) — vends messages instructing: mark_explore the url, then fetch the #sections that matter; answer with a neighborhood summary. The ≤2-turn orientation flow as a command.
  • recall (arg: subject, required) — lookup-first recall: mark_lookup the subject, explore the best match, fetch sections; report with mark:// refs.

R3 — polish

  • Tool/resource descriptions cross-reference ("attach via resources for zero-turn context; fetch via tools for programmatic access").
  • README/docs note for Desktop users (resources are the Desktop-native way in).

Decisions to settle

  • D1 — resource listing shape. (a) static well-known set + template (recommended — no startup network dependency, unbounded docs reachable via template, resources/list stays honest); (b) dynamic list from a startup LIST crawl (richer picker UX, but couples MCP server startup to host availability and goes stale mid-session); (c) both, with a lazy background refresh (complexity — only if Desktop picker UX proves to matter).
  • D2 — resource read shape for large docs. (a) always full body (recommended) — attaching is a deliberate act, outline-gating an explicit attach would surprise; #anchor URIs give section-sized attach; (b) outline over 8KB like mark_fetch (consistent but wrong ergonomics for attach).
  • D3 — v1 prompt set. (a) orient + recall (recommended); (b) add whats-new (recent-changes digest via LOOKUP modified-after) — defer unless wanted now; (c) soul-specific prompts (journal etc.) stay in the plugin, not the generic client.
  • D4 — broker parity timing. (a) defer (recommended) — ship client-side, prove the shape, then flip the gateway (its plan explicitly excludes resources/prompts and a capabilities test PINS their absence — that test flip is the marker of the follow-up); (b) same phase — bigger PR, and Desktop-attach matters most for knowledge-system users, but auth
    • multi-world resource URIs (mark://{world}/{+path}) deserve their own design pass.

Acceptance

  • In Claude Code against the soul: /mcp__soul__orient <url> runs the orientation flow; a resource read of mark://soul.demarkus.io/index.md returns the hub as markdown; a #section resource URI returns just the section.
  • In Claude Desktop: the soul's index + manifest appear in the resource picker; attaching one adds the doc to context with zero tool turns.
  • initialize advertises resources + prompts capabilities; broker gateway capabilities UNCHANGED (D4a).

Pickup notes

  • mcp-go v0.44: AddResource(mcp.NewResource(uri, name, opts), handler); AddResourceTemplate(mcp.NewResourceTemplate(uriTemplate, name, opts), handler) — uritemplate matching is built in; handlers return []mcp.ResourceContents. AddPrompt(mcp.NewPrompt(name, WithArgument("url", RequiredArgument(), ArgumentDescription(...))), handler) returns *mcp.GetPromptResult (messages). Capabilities auto-advertise on first Add*.
  • Code: client/cmd/demarkus-mcp/ — add resources.go + prompts.go beside explore.go; wire in main() after tool registration. Reuse handler.resolveURL/resolveToken, mdoutline.Section.
  • The broker gateway (tools/demarkus-broker/internal/broker/) asserts in TestMCPGatewayInitializeHandshake that resources/prompts capabilities are ABSENT — leave that test intact under D4a; flipping it is the start of the broker follow-up.
  • Gate: bash pre-commit.sh; never commit — Fritz commits. Feature branch.

SETTLED (2026-07-05, Fritz — criterion: convenience lowers the bar to using demarkus and raises the joy of using it)

  • D1: static well-known + template + best-effort dynamic listing. The Desktop picker must be useful, not sparse: register index.md + agent manifest statically, then a bounded, non-blocking startup LIST of the host's top level registers real docs (capped, short timeout, graceful skip if the host is down — server startup never depends on it).
  • D2: full body, with size annotations on listed resources so clients can warn before a big attach; #anchor URIs for section-sized attach. Never outline-gate an explicit attach.
  • D3: orient + recall + whats-new. whats-new made the cut on the joy criterion — "what changed since I was last here" as one command (rides the LOOKUP modified-after filter).
  • D4: broker parity deferred — separate design pass (multi-world resource URIs, auth on reads, per-world hub enumeration). The gateway capabilities test stays pinned; flipping it starts that follow-up.

BUILT (2026-07-05, branch feature/mcp-resources-prompts — awaiting commit)

R1–R3 implemented in client/cmd/demarkus-mcp/resources.go + prompts.go and verified live against soul.demarkus.io over stdio:

  • Resources: URI template mark://<host>/{+path} (host-generic template without -host); static index.md + agent-manifest; best-effort background LIST registration (goroutine after registration, never blocks startup; capped at 50; skips dirs/non-md/index.md; listChanged notification on late add — verified live: 20 entries after the soul's top level registered). readResource returns full body always, #anchor URIs slice sections via mdoutline, errors list available anchors. Reads bypass outline gate and dedup by design (D2).
  • Prompts: orient(url), recall(subject), whats-new(since optional, YYYY-MM-DD for the LOOKUP modified-after filter). Verified live via prompts/list + prompts/get.
  • D2 amendment: size annotations dropped — mcp-go v0.44's Resource has no size field and LIST carries no sizes; revisit if the SDK grows it.
  • Broker untouched; its capabilities test still pins resources/prompts absent (D4).

MERGED 2026-07-05 — PR #232 (574bb98), auto-released client/v0.17.0. One review comment (log the unreachable resolveURL failure path) folded in. Reaches plugin users via the now-self-driving pin chain (tools release → auto bump PR → bootstrap repin). Remaining from this plan: the broker follow-up (D4 — multi-world resource URIs, auth on reads, per-world hub enumeration; starts by flipping the gateway capabilities test).

trail
  1. soul.demarkus.io v4