feat(search): global search MCP tool — store, memory, code, and web arms - #284
Conversation
- SearchRequest { query, type?, limit? } in types.rs
- search_impl dispatches by type: store|code|web
- type='store' (default): FTS search via agentflare-store doc_search,
grouped by doc_type in { query, source, total, groups }
- type='code': subprocess call to lean-ctx grep, returns file:line:text
results
- type='web': placeholder (agent-level rivalsearch)
- 5 tests: empty-query validation, grouped store results, default type,
code validation, lean-ctx integration
Agentflare-Agent: 1
Agentflare-Branch: feature/global-search-129
- type='memory': opens brain.db via memory::store::open(), calls memory::search::search() for FTS5 + LIKE fallback on observations - Results grouped by observation type (decision, finding, pattern, etc.) - 2 tests: empty-query validation, seeded observation retrieval Agentflare-Agent: 1 Agentflare-Branch: feature/global-search-129
- web search delegates to gateway rivalsearch web_search, with a graceful error payload when the server is not registered - drop the consent-free gateway.toml bootstrap; registration stays with gateway_integrations (personal paths must never ship in the binary) - fix lean-ctx grep parsing: line number is space-separated, not colon - store search: skip stale FTS rows instead of panicking the server - reject unknown search type with invalid_params (+ test) - surface lean-ctx stderr when code search fails with no output - skip the lean-ctx integration test when the binary is not on PATH (CI) Agentflare-Agent: claude-code_2-1-216_agent Agentflare-Branch: feature/global-search-129
|
Warning Review limit reached
Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughAdds a typed MCP ChangesUnified MCP Search
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant MCPClient
participant AgentflareMcp
participant SearchBackend
MCPClient->>AgentflareMcp: Send SearchRequest
AgentflareMcp->>AgentflareMcp: Select store, memory, code, or web
AgentflareMcp->>SearchBackend: Execute backend search
SearchBackend-->>AgentflareMcp: Return grouped JSON results
AgentflareMcp-->>MCPClient: Return search response
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/mcp_server/search.rs (1)
226-256: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
search_webdiverges from the documented contract and skips response capping.Two related gaps versus the rest of this file and
mcp_server.rs:
- On success,
search_webreturns the rawreg.execute(...)value verbatim (Lines 241-255), but thesearchtool's docstring insrc/mcp_server.rs(Line 1377) promises{ query, source, total, groups|results }for every type — this shape isn't guaranteed here since it's whateverrivalsearch'sweb_searchtool happens to return.- Unlike
tool's "execute" arm insrc/mcp_server.rs(which caps payloads viagateway_registry::truncate_if_needed(&value, gateway_registry::DEFAULT_MAX_CHARS)), this path passes the raw result through unbounded.Consider wrapping the success case into the documented shape (e.g.
{"source": "web", "query": q, "results": val}) and reusingtruncate_if_neededfor consistency with thetoolaction.Separately, there's a
search_*_requires_non_empty_querytest for store/memory/code but none forweb, even though the empty-query check (Lines 228-230) runs before any gateway call and needs no live backend to test.♻️ Proposed fix to conform to the documented shape and cap size
- let result_str = serde_json::to_string_pretty(&result).unwrap_or_default(); - Ok(result_str) + let capped = + gateway_registry::truncate_if_needed(&result, gateway_registry::DEFAULT_MAX_CHARS); + Ok(serde_json::json!({ + "source": "web", + "query": q, + "results": capped, + }) + .to_string())🤖 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/mcp_server/search.rs` around lines 226 - 256, Update search_web so successful gateway responses are wrapped in the documented {query, source, results} shape instead of returning the raw value, while preserving the existing web error shape. Apply gateway_registry::truncate_if_needed with gateway_registry::DEFAULT_MAX_CHARS to the wrapped response before serializing and returning it. Add a search_web_requires_non_empty_query test matching the existing non-empty-query tests, confirming empty input returns invalid parameters without invoking the gateway.
🤖 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.
Inline comments:
In `@src/mcp_server/search.rs`:
- Around line 157-165: Update the search_impl/search_code flow so the
synchronous lean-ctx grep subprocess does not block an async runtime worker
indefinitely. Follow the existing tokio::task::spawn_blocking pattern used by
the skill and tool search arms, and add a bounded wait or timeout that
terminates or returns an error for a hung process while preserving the current
error context.
---
Nitpick comments:
In `@src/mcp_server/search.rs`:
- Around line 226-256: Update search_web so successful gateway responses are
wrapped in the documented {query, source, results} shape instead of returning
the raw value, while preserving the existing web error shape. Apply
gateway_registry::truncate_if_needed with gateway_registry::DEFAULT_MAX_CHARS to
the wrapped response before serializing and returning it. Add a
search_web_requires_non_empty_query test matching the existing non-empty-query
tests, confirming empty input returns invalid parameters without invoking the
gateway.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0de599d1-17a7-412e-aa3d-baca9e4cd5e9
📒 Files selected for processing (5)
src/mcp_server.rssrc/mcp_server/search.rssrc/mcp_server/tests/mod.rssrc/mcp_server/tests/search_tests.rssrc/mcp_server/types.rs
…al MCP servers - search_code now calls the gateway's leanctx ctx_search (regex action) like the web arm — drops the subprocess spawn and the fragile file:line output parsing entirely; unregistered server degrades to an error payload - gateway auto-registers LOCAL stdio servers on first use when detected: leanctx (binary installed) and rivalsearch (checkout + uv present), via gateway_integrations' idempotent append; rivalsearch's path is derived from the home dir at runtime, never hardcoded. Remote integrations (github) stay behind init's consent flow - register() split into register_block(name, block) so runtime-built blocks reuse the same idempotency machinery Agentflare-Agent: claude-code_2-1-216_agent Agentflare-Branch: feature/global-search-129
…velope Agentflare-Agent: claude-code_2-1-216_agent Agentflare-Branch: feature/global-search-129
|
Both CodeRabbit findings addressed:
|
Summary
Adds a
searchMCP tool — a unified entry point over four sources (agentflare item #129, Global AI Agent Search epic — NOT GitHub PR #129):doc_typeleanctxserver (ctx_search, regex action) — no subprocess, no output parsing, compressed resultsrivalsearchweb_searchtoolBoth delegated arms degrade to a structured error payload when the server isn't registered.
Gateway auto-registration (local servers only)
On first gateway use, agentflare now auto-registers local stdio MCP servers it detects:
leanctx(binary installed) andrivalsearch(checkout +uvpresent). Registration goes throughgateway_integrations' existing idempotent append; rivalsearch's path is derived from the home directory at runtime — never hardcoded into the binary. Remote integrations (github, …) stay behindinit's consent flow.Review hardening (recorded in the review ledger under this branch)
doc_getreturns none for a search hittypevalues are rejected withinvalid_paramsinstead of silently searching storegateway.tomlbootstrap that hardcoded personal paths and auto-registered remote serversTest plan
search_testsincluding a live end-to-end gateway delegation test (temp home → auto-registration → gateway spawns lean-ctx → results)gateway_integrationstests (idempotency, parseability, malformed-sibling survival)cargo fmt --checkclean