Skip to content

feat(mcp): expose bundled prompts as static MCP resources#2734

Closed
obchain wants to merge 5 commits into
tinyhumansai:mainfrom
obchain:feat/mcp-resources-mvp
Closed

feat(mcp): expose bundled prompts as static MCP resources#2734
obchain wants to merge 5 commits into
tinyhumansai:mainfrom
obchain:feat/mcp-resources-mvp

Conversation

@obchain
Copy link
Copy Markdown
Contributor

@obchain obchain commented May 27, 2026

Summary

  • Adds resources/list and resources/read to the MCP stdio + HTTP server so external MCP clients (Claude Desktop, Cursor, Zed) can attach OpenHuman's bundled prompt assets as conversation context.
  • Catalog ships 21 static, read-only resources: 3 core identity files (IDENTITY.md, SOUL.md, USER.md) plus 18 subagent prompt.md files (one per BUILTINS row in agent::agents::loader).
  • initialize now advertises a resources capability with subscribe: false and listChanged: false because the catalog is include_str!-bundled at compile time and cannot change at runtime.
  • 11 new unit tests cover catalog parity vs BUILTINS, per-URI content distinctness, the wired JSON-RPC happy paths, and the -32002 Resource not found / -32602 Invalid params error conventions.
  • Single-page-per-resources/list response: the cursor parameter is accepted for spec-compliance but ignored, and the response omits nextCursor.

Problem

The MCP server today only implements initialize, ping, tools/list, and tools/call; every other spec method returns -32601 Method not found. External MCP clients connecting to openhuman-core therefore see a tools-only surface and have no way to pull OpenHuman's own prompt scaffolds into their own conversations — even though those scaffolds are already bundled into the binary at compile time and contain no per-user data.

Concretely, a Claude Desktop user who connects OpenHuman as an MCP server cannot today attach IDENTITY.md / SOUL.md / USER.md or any subagent prompt without reading the OpenHuman source tree by hand. That's the smallest user-visible spec gap on the server-side MCP surface and lands without backend coordination.

Solution

Three atomic commits:

SHA Title Files
75df6176 feat(mcp): add static resources catalog module new src/openhuman/mcp_server/resources.rs + mod.rs register. Catalog is an include_str!-bundled &[StaticResource] slice, so the asset paths are checked at compile time. Exposes pub fn list_resources_result(cursor) and pub fn read_resource_result(uri) — both pure, no I/O, no async.
b38f425a feat(mcp): wire resources/list + resources/read into protocol src/openhuman/mcp_server/protocol.rs adds two handle_request match arms, advertises the resources capability in initialize_result, and updates the existing initialize test to assert the new capability block. Missing-uri-32602 Invalid params. Unknown-URI lookups → -32002 Resource not found per the MCP error-code convention.
d35c9d68 docs(mcp): document the resources surface and coverage row gitbooks/developing/mcp-server.md adds a Resources section listing the URI catalog and contract notes, plus extends the smoke-test snippet to exercise both methods against openhuman://core/identity. docs/TEST-COVERAGE-MATRIX.md adds row 11.1.7 and bumps the Covered total from 69 to 70.

URI scheme

URI Source path
openhuman://core/identity src/openhuman/agent/prompts/IDENTITY.md
openhuman://core/soul src/openhuman/agent/prompts/SOUL.md
openhuman://core/user src/openhuman/agent/prompts/USER.md
openhuman://agents/<id>/prompt src/openhuman/agent/agents/<id>/prompt.md (one entry per BUILTINS row)

Out of scope (deliberately, follow-up tracking only)

  • Dynamic memory-as-resources (openhuman://memory/recent, openhuman://memory/search?q=…) — needs per-user context plumbing and SecurityPolicy gating; lands cleaner on top of this MVP.
  • resources/subscribe / resources/unsubscribe / notifications/resources/list_changed — the static catalog cannot change at runtime, so subscriptions would be no-ops.
  • resources/templates/list — no templated URIs in the MVP catalog.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — 7 catalog tests in resources.rs (parity vs BUILTINS, per-URI distinctness, required-field shape, no nextCursor, unknown-URI rejection) + 4 protocol tests in protocol.rs (list happy path, read happy path, unknown-URI -32002, missing-uri -32602).
  • Diff coverage ≥ 80% — changed Rust lines are 100% covered by the 11 new unit tests; docs lines are not eligible.
  • Coverage matrix updated — added row 11.1.7 MCP resources (resources/list + resources/read) in docs/TEST-COVERAGE-MATRIX.md and bumped the Covered total.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — feature ID 11.1.7 (new row).
  • No new external network dependencies introduced (mock backend used per Testing Strategy) — tests are pure in-memory; no HTTP, no socket, no fixtures beyond the include_str!-bundled markdown.
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: stdio/HTTP MCP server is opt-in and not on the release-cut smoke path.
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Runtime/platform impact: none on existing tool-call flow; the new methods are additive and only fire when an MCP client invokes them.
  • Performance: zero overhead at startup (catalog is a const); request-time cost is a Vec<Value> build of ≈21 entries for resources/list and a linear scan to find a single URI for resources/read.
  • Security: the catalog is include_str!-bundled at compile time and contains only assets already in the repo; there is no async I/O, no filesystem traversal, and no user-context plumbing introduced. SecurityPolicy is unchanged.
  • Migration / compatibility: backwards-compatible — older clients that ignore the resources capability and never call the new methods continue to see the same surface.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: N/A
  • Commit SHA: N/A

Validation Run

  • pnpm --filter openhuman-app format:check — N/A: no app/ code changed.
  • pnpm typecheck — N/A: no TS source changed.
  • Focused tests: ran cargo test --lib openhuman::mcp_server::resources::tests (7/7 pass) and cargo test --lib openhuman::mcp_server::protocol::tests::resources (4/4 pass) plus cargo test --lib openhuman::mcp_server::protocol::tests::initialize (9/9 pass) to confirm the amended initialize assertion.
  • Rust fmt/check (if changed): cargo fmt --manifest-path Cargo.toml --check clean on the touched files; cargo check --manifest-path Cargo.toml --lib produces no new warnings.
  • Tauri fmt/check (if changed): N/A — no Tauri code changed.

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: MCP server now exposes 21 static read-only resources via resources/list + resources/read, and the initialize capability response advertises the new surface.
  • User-visible effect: external MCP clients (Claude Desktop, Cursor, Zed) connected to openhuman-core can attach OpenHuman's bundled prompts as conversation context.

Parity Contract

  • Legacy behavior preserved: yes — existing tools/list / tools/call paths are untouched and the new methods are purely additive.
  • Guard/fallback/dispatch parity checks: no production code outside mcp_server/ changed; tool dispatch, security policy, and session lifecycle are unaffected.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none.
  • Canonical PR: this PR.
  • Resolution: N/A.

Summary by CodeRabbit

  • New Features

    • Added MCP resources interface to expose bundled prompt assets via resources/list and resources/read operations
    • Resources accessible through stable openhuman:// URIs for identity and subagent prompts
  • Documentation

    • Updated test coverage matrix with new resources test coverage
    • Added resources surface documentation with supported URIs and error handling details

Review Change Stack

@obchain obchain requested a review from a team May 27, 2026 07:24
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6f9585c-67a0-4b55-897f-053b290b1783

📥 Commits

Reviewing files that changed from the base of the PR and between 4b53354 and e44f8b4.

📒 Files selected for processing (4)
  • docs/TEST-COVERAGE-MATRIX.md
  • gitbooks/developing/mcp-server.md
  • src/openhuman/mcp_server/protocol.rs
  • src/openhuman/mcp_server/resources.rs
✅ Files skipped from review due to trivial changes (2)
  • docs/TEST-COVERAGE-MATRIX.md
  • gitbooks/developing/mcp-server.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/openhuman/mcp_server/resources.rs
  • src/openhuman/mcp_server/protocol.rs

📝 Walkthrough

Walkthrough

This PR implements the MCP resources/list and resources/read methods, exposing OpenHuman's bundled prompt assets—three core identity files and each subagent's static prompt—as a compile-time static catalog accessible to external MCP clients. The implementation includes request dispatch, error mapping, capability advertisement, comprehensive tests, and updated documentation.

Changes

MCP Static Resources Surface

Layer / File(s) Summary
Resource catalog and data model
src/openhuman/mcp_server/resources.rs (module doc, catalog def)
Module documentation and RESOURCES constant define a compile-time static resource catalog with StaticResource metadata and markdown bodies embedded via include_str! for each openhuman://core/* and openhuman://agents/<id>/prompt URI.
List, read, and error operations
src/openhuman/mcp_server/resources.rs (operations)
list_resources_result enumerates all catalog entries in a single page; read_resource_result looks up a URI in the catalog and returns contents or ResourceError::NotFound with formatted error message.
Protocol dispatch and capability advertisement
src/openhuman/mcp_server/protocol.rs (dispatch, initialize)
handle_request routes resources/list (optional cursor) and resources/read (required uri) to their operation handlers, maps unknown URIs to MCP -32002 and missing uri to -32602, advertises capabilities.resources in initialize with subscribe: false and listChanged: false, and updates server instructions to reference resource methods.
Operation and error handling validation
src/openhuman/mcp_server/protocol.rs (tests)
Async tests validate resources/list returns the full catalog with specific URIs, resources/read returns expected markdown for known resources, error code -32002 with "unknown MCP resource" message for unknown URIs, and error code -32602 with "requires a uri" message for missing parameters.
Documentation and coverage matrix
gitbooks/developing/mcp-server.md, docs/TEST-COVERAGE-MATRIX.md
Added Resources section describing the static catalog, supported URI scheme, response shapes, and error behavior; updated MCP smoke test to exercise resources/list and resources/read with 4 expected JSON response lines; added new coverage matrix entry and updated totals (Covered: 70, Total leaves: 206).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2745: Implements the same MCP resources feature by wiring resources/list and resources/read in protocol dispatch and defining the static catalog with the same URI scheme and error handling.

Suggested reviewers

  • senamakel

Poem

🐰 A rabbit hops through MCP halls,
Where static resources now live on calls—
resources/list and read gently sing,
Bundled prompts on compile-time's wing!
Identity and agents, prompt by prompt,
All exposed at startup, not runtime crumped.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main feature: exposing bundled prompts as static MCP resources. It directly relates to the primary objective of the PR.
Linked Issues check ✅ Passed All acceptance criteria from #2732 are addressed: resources/list and resources/read implemented with proper error codes (-32602 for missing uri, -32002 for unknown), initialize advertises resources capability, catalog parity tested, docs updated, and coverage requirements met.
Out of Scope Changes check ✅ Passed All changes align with the PR scope: static MCP resources module, protocol.rs wiring, documentation updates, and test-coverage matrix. No dynamic memory resources, subscriptions, or templated URIs are introduced.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/openhuman/mcp_server/resources.rs (1)

288-329: ⚡ Quick win

Make BUILTINS parity assertion bidirectional.

This test only checks for missing expected URIs; it won’t fail on stale extra subagent URIs. Prefer exact set equality for subagent URIs.

Suggested test hardening
     #[test]
     fn list_resources_advertises_every_subagent_prompt() {
@@
-        let expected = [
+        let expected_uris = [
             "openhuman://agents/archivist/prompt",
@@
             "openhuman://agents/trigger_triage/prompt",
         ];
         let out = list_resources_result(None);
         let resources = out
             .get("resources")
             .and_then(Value::as_array)
             .expect("resources array");
-        let uris: Vec<&str> = resources
+        use std::collections::BTreeSet;
+        let actual_subagent_uris: BTreeSet<&str> = resources
             .iter()
             .filter_map(|r| r.get("uri").and_then(Value::as_str))
+            .filter(|uri| uri.starts_with("openhuman://agents/"))
             .collect();
-        for uri in expected {
-            assert!(
-                uris.contains(&uri),
-                "missing subagent resource `{uri}` from resources/list — \
-                 catalog drift vs `agent::agents::loader::BUILTINS`"
-            );
-        }
+        let expected_subagent_uris: BTreeSet<&str> = expected_uris.into_iter().collect();
+        assert_eq!(
+            actual_subagent_uris,
+            expected_subagent_uris,
+            "subagent resource catalog drift vs `agent::agents::loader::BUILTINS`"
+        );
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_server/resources.rs` around lines 288 - 329, The test
list_resources_advertises_every_subagent_prompt only asserts that every item in
the expected array appears in the discovered uris, so it misses extra/stale
URIs; change the check to assert exact set equality between the expected set and
the discovered set (built from out -> resources -> uris). Convert expected and
uris into HashSet<String> (or sort and compare vectors) and assert they are
equal (or assert that their symmetric difference is empty) so the test will fail
on both missing and extra subagent URIs; refer to the existing symbols expected,
uris, resources, and list_resources_result to locate where to replace the
current loop/assert.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/openhuman/mcp_server/resources.rs`:
- Around line 288-329: The test list_resources_advertises_every_subagent_prompt
only asserts that every item in the expected array appears in the discovered
uris, so it misses extra/stale URIs; change the check to assert exact set
equality between the expected set and the discovered set (built from out ->
resources -> uris). Convert expected and uris into HashSet<String> (or sort and
compare vectors) and assert they are equal (or assert that their symmetric
difference is empty) so the test will fail on both missing and extra subagent
URIs; refer to the existing symbols expected, uris, resources, and
list_resources_result to locate where to replace the current loop/assert.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1dbd0768-4211-478a-9a1e-daebbbe6b261

📥 Commits

Reviewing files that changed from the base of the PR and between e6192e2 and d35c9d6.

📒 Files selected for processing (5)
  • docs/TEST-COVERAGE-MATRIX.md
  • gitbooks/developing/mcp-server.md
  • src/openhuman/mcp_server/mod.rs
  • src/openhuman/mcp_server/protocol.rs
  • src/openhuman/mcp_server/resources.rs

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@obchain hey! the code looks good to me — solid implementation of the MCP resources surface. catalog parity tests lock in the subagent list, compile-time include_str! validation catches missing assets, and error codes follow the spec perfectly.

however, there's a CI failure on windows (Rust Core Tests — secrets ACL) that needs to be sorted first. once that's green, i'll come back and approve this.

@obchain
Copy link
Copy Markdown
Contributor Author

obchain commented May 27, 2026

Done in 4b533545. Replaced the subset loop with a BTreeSet equality assertion filtered to openhuman://agents/ URIs, so catalog drift now fails in both directions (missing and stale entries).

@obchain
Copy link
Copy Markdown
Contributor Author

obchain commented May 27, 2026

@graycyrus rebased catalog parity test on 4b533545 (set-equality + agents-only filter). The cancelled Windows secrets ACL job was an infra glitch, not a real failure — the new push will rerun it automatically.

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
@obchain obchain requested a review from graycyrus May 27, 2026 16:29
obchain added 5 commits May 28, 2026 11:26
Introduces `src/openhuman/mcp_server/resources.rs` — a compile-time
`include_str!`-bundled catalog of OpenHuman's prompt assets (the three
core identity files plus each built-in subagent's `prompt.md`) plus
two pure builders, `list_resources_result` and `read_resource_result`,
that shape the MCP `resources/list` and `resources/read` responses.

The module is wired into the protocol layer in the next commit. Keeping
the catalog as its own change lets the test suite cover catalog parity
(against the `agent::agents::loader::BUILTINS` slice) and per-URI
content distinctness independently of the protocol-handler wiring.
Hooks the static catalog module into the JSON-RPC dispatch so external
MCP clients can pull OpenHuman's bundled prompts as conversation
context. Three changes:

* `initialize` now advertises a `resources` capability with
  `subscribe: false` and `listChanged: false` so clients know they
  can call `resources/list` but should not expect change notifications
  (the catalog is bundled at compile time).
* `resources/list` returns the full catalog in one page; the `cursor`
  parameter is accepted for spec-compliance but ignored, and the
  response omits `nextCursor`.
* `resources/read` looks up by `uri` and returns the markdown body.
  Missing-`uri` rejections surface as `-32602 Invalid params`;
  unknown-URI lookups surface as `-32002 Resource not found` per the
  MCP error-code convention.

Four protocol tests cover the wired handlers plus the existing
`initialize` test grows an assertion for the new capability.
Adds a Resources section to the MCP server gitbook listing the URI
catalog and contract notes (`subscribe`/`listChanged` both false,
`-32002` for unknown-URI lookups). Extends the smoke-test snippet to
also exercise `resources/list` and `resources/read` against
`openhuman://core/identity` and updates the expected-response sketch
to match the new initialize capabilities block.

Adds row 11.1.7 to the test-coverage matrix referencing
`mcp_server/resources.rs` and `mcp_server/protocol.rs` for the seven
catalog tests plus the four protocol-layer tests, and bumps the Covered
total from 69 to 70.
Replace subset check with BTreeSet equality so the test also fails on
stale catalog entries that have fallen out of agent::agents::loader::BUILTINS,
not only on missing ones.
@sanil-23
Copy link
Copy Markdown
Contributor

Closing as superseded — issue #2732 was completed by #2745 (merged 2026-05-27 18:24Z), which landed the same resources/list + resources/read MVP this branch targets. Thanks for the contribution! If there are gaps vs. what #2745 shipped, happy to look at a follow-up PR scoped to the delta.

@sanil-23 sanil-23 closed this May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose bundled prompts as static MCP resources (resources/list + resources/read)

4 participants