# 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____` 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:///{+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 ` 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:///{+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). ## BROKER FOLLOW-UP BUILT (2026-07-05, branch feature/broker-resources-prompts — awaiting commit) D4's deferred leg, started by flipping the gateway capabilities test as declared (it now asserts resources+prompts ARE advertised): - **Resources** (`mcp_resources.go`): template `mark://{world}/{+path}` with `#anchor` section attach; each configured world's `index.md` registered as a concrete picker entry at construction (the world set is config-static per pod — worlds[] changes roll the broker — so no dynamic listing is needed, unlike the client). Auth came free: the /mcp transport sits behind gatewayAuth, and reads dispatch with an empty bearer exactly like handleMarkFetch. Reads bypass outline/dedup (D2). - **Prompts** (`mcp_prompts.go`): orient / recall / whats-new, deliberately NOT mirrors of the client's — the knowledge system spans worlds, so recall and whats-new start from mark_worlds and sweep per-world catalogs; whats-new gains an optional `world` arg to scope. Different content, not a mirror — nothing to hoist (the fetchdedup lesson applies to mirrors, not siblings). - Tests: per-world hub + template listing via real resources/list round trips, whole/section/error reads, prompt list/get/args, and the flipped handshake test. **BROKER FOLLOW-UP MERGED 2026-07-05 — PR #233 (`85834ff`), auto-released tools/v0.6.0** (broker image + chart 0.6.0 via the 1:1 pinning). With this the plan is fully closed on both surfaces; the deploy-repo pin bump to 0.6.0 puts it on the live knowledge system.