You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add three read-only MCP tools on top of the Phase 1 surface (memory.search, memory.recall, tree.read_chunk):
tree.browse — paginated chunk listing with source / topic / time filters.
tree.search_entities — find chunks by named entity (person, org, project).
integrations.list_connections — list connected sources so a client can scope subsequent queries.
All three are thin adapters over existing controller-registry RPCs, follow the Phase 1 ToolCallError / enforce_read_policy model, and stay strictly read-only.
Problem
The Phase 1 surface (#1760 + #1790) is enough for "find a chunk by keyword / semantic query and read it." It leaves three gaps that show up the moment an MCP client tries to be useful beyond direct keyword recall:
No way to browse. A client can only call memory.search / memory.recall and hope the query is right. There is no listing, no filtering by source, no time-window scan. A user asking "what's recent in my Gmail?" forces the LLM to guess search terms instead of paging through.
No entity awareness. A client cannot ask "what does my memory say about Alice / Acme Corp?" without pretending it's a keyword. memory_tree_search_entities already exists in the registry — Phase 1 just doesn't expose it.
No source discovery. Before running any query the client has no way to know which integrations (Gmail, Slack, Notion, …) actually have data. Models end up calling memory.search against keywords that have no chance of matching anything.
These are the three single-call shapes a Claude Desktop / Cursor session most often needs after the initial "I know roughly what I'm looking for" interaction.
Solution (optional)
Sketch, happy to revise per maintainer input:
MCP tool
Backing RPC
Why this one
tree.browse
openhuman.memory_tree_list_chunks
Paginated listing already supports the source_kind / source_id / entity_ids / time-window / keyword filters we want.
tree.search_entities
openhuman.memory_tree_search_entities
Lets the LLM say "Alice" instead of guessing every keyword permutation.
integrations.list_connections
composio.list_connections
Cheap discovery call. Lets the LLM pre-filter searches to sources that actually have data, instead of fishing on dead ones.
Same module + adapter pattern as Phase 1:
Tools live next to the existing three in src/openhuman/mcp_server/tools.rs.
Each runs through validate_controller_params and enforce_read_policy(ToolOperation::Read).
Tool descriptions are tuned so the LLM picks the right tool: "browse when you want pagination or a source filter; recall/search when you have a query string."
integrations.list_connections — no args; returns connected toolkits with their last-sync time. Skips sensitive fields (tokens).
Schema validation — every new tool round-trips through validate_controller_params against its mapped RPC schema; mapping regression caught at unit test time (same pattern as mapped_rpc_methods_are_registered).
enforce_read_policy — every new tool gated through SecurityPolicy with ToolOperation::Read.
Diff coverage ≥ 80% — happy path + at least one invalid-arg path per tool, per Testing Strategy.
Summary
Add three read-only MCP tools on top of the Phase 1 surface (
memory.search,memory.recall,tree.read_chunk):tree.browse— paginated chunk listing with source / topic / time filters.tree.search_entities— find chunks by named entity (person, org, project).integrations.list_connections— list connected sources so a client can scope subsequent queries.All three are thin adapters over existing controller-registry RPCs, follow the Phase 1
ToolCallError/enforce_read_policymodel, and stay strictly read-only.Problem
The Phase 1 surface (#1760 + #1790) is enough for "find a chunk by keyword / semantic query and read it." It leaves three gaps that show up the moment an MCP client tries to be useful beyond direct keyword recall:
memory.search/memory.recalland hope the query is right. There is no listing, no filtering by source, no time-window scan. A user asking "what's recent in my Gmail?" forces the LLM to guess search terms instead of paging through.memory_tree_search_entitiesalready exists in the registry — Phase 1 just doesn't expose it.memory.searchagainst keywords that have no chance of matching anything.These are the three single-call shapes a Claude Desktop / Cursor session most often needs after the initial "I know roughly what I'm looking for" interaction.
Solution (optional)
Sketch, happy to revise per maintainer input:
tree.browseopenhuman.memory_tree_list_chunkssource_kind/source_id/entity_ids/ time-window / keyword filters we want.tree.search_entitiesopenhuman.memory_tree_search_entitiesintegrations.list_connectionscomposio.list_connectionsSame module + adapter pattern as Phase 1:
src/openhuman/mcp_server/tools.rs.validate_controller_paramsandenforce_read_policy(ToolOperation::Read).ToolCallErrorvariants not required — the new tools surface asInvalidParamsfor bad input andInternalfor config-load failures, matching fix(mcp): tighten stdio server logging and error semantics #1790.Acceptance criteria
tree.browse— acceptssource_kind?,source_id?,entity_ids?,since?,until?,keyword?,page?,k?(defaults & caps mirror Phase 1'sk); rejects unexpected args.tree.search_entities— acceptsentity(required, non-empty string) andk?(≤ 50); rejects unexpected args.integrations.list_connections— no args; returns connected toolkits with their last-sync time. Skips sensitive fields (tokens).validate_controller_paramsagainst its mapped RPC schema; mapping regression caught at unit test time (same pattern asmapped_rpc_methods_are_registered).enforce_read_policy— every new tool gated throughSecurityPolicywithToolOperation::Read.Related
11.1.4(MCP stdio server)