Skip to content

feat(search): global search MCP tool — store, memory, code, and web arms - #284

Merged
getappz merged 6 commits into
masterfrom
feature/global-search-129
Jul 21, 2026
Merged

feat(search): global search MCP tool — store, memory, code, and web arms#284
getappz merged 6 commits into
masterfrom
feature/global-search-129

Conversation

@getappz

@getappz getappz commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a search MCP tool — a unified entry point over four sources (agentflare item #129, Global AI Agent Search epic — NOT GitHub PR #129):

  • store (default): FTS across agentflare-store documents, grouped by doc_type
  • memory: FTS across brain.db observations, grouped by observation type
  • code: delegated to the gateway's leanctx server (ctx_search, regex action) — no subprocess, no output parsing, compressed results
  • web: delegated to the gateway's rivalsearch web_search tool

Both 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) and rivalsearch (checkout + uv present). Registration goes through gateway_integrations' existing idempotent append; rivalsearch's path is derived from the home directory at runtime — never hardcoded into the binary. Remote integrations (github, …) stay behind init's consent flow.

Review hardening (recorded in the review ledger under this branch)

  • Store search skips stale FTS rows instead of panicking the server when doc_get returns none for a search hit
  • Unknown type values are rejected with invalid_params instead of silently searching store
  • Dropped a consent-free gateway.toml bootstrap that hardcoded personal paths and auto-registered remote servers
  • The code-search test exercises the gateway path and stays green whether or not lean-ctx is installed (CI does not install it)

Test plan

  • 8 search_tests including a live end-to-end gateway delegation test (temp home → auto-registration → gateway spawns lean-ctx → results)
  • 9 gateway_integrations tests (idempotency, parseability, malformed-sibling survival)
  • Full workspace suite: 692 passed, 0 failed; cargo fmt --check clean

getappz added 3 commits July 21, 2026 02:46
- 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
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@getappz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 57f1cc83-77b9-4cd0-b9ef-3562978facc8

📥 Commits

Reviewing files that changed from the base of the PR and between fc7cc8b and c25d1f2.

📒 Files selected for processing (5)
  • src/gateway_integrations.rs
  • src/mcp_server.rs
  • src/mcp_server/search.rs
  • src/mcp_server/tests/search_tests.rs
  • src/mcp_server/types.rs
📝 Walkthrough

Walkthrough

Adds a typed MCP search tool that dispatches queries to store, memory, code, or web backends, validates inputs, groups results, and returns JSON responses with coverage from end-to-end tests.

Changes

Unified MCP Search

Layer / File(s) Summary
Search contract and MCP wiring
src/mcp_server/types.rs, src/mcp_server.rs, src/mcp_server/search.rs
Adds SearchRequest, exposes the MCP search tool, and dispatches requests by backend type.
Store and memory search backends
src/mcp_server/search.rs
Searches stored documents or memory observations, applies limits, groups results, and serializes totals as JSON.
Code and web search backends
src/mcp_server/search.rs
Runs lean-ctx grep for repository searches and invokes the gateway web-search tool, including structured error responses.
Search behavior tests
src/mcp_server/tests/mod.rs, src/mcp_server/tests/search_tests.rs
Tests validation, backend result grouping, default store selection, unknown types, and conditional code-search results.

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
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the new global search MCP tool across store, memory, code, and web.
Description check ✅ Passed Summary and Test plan sections are present and detailed; only the Notes for reviewers section is missing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/global-search-129

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/mcp_server/search.rs (1)

226-256: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

search_web diverges from the documented contract and skips response capping.

Two related gaps versus the rest of this file and mcp_server.rs:

  • On success, search_web returns the raw reg.execute(...) value verbatim (Lines 241-255), but the search tool's docstring in src/mcp_server.rs (Line 1377) promises { query, source, total, groups|results } for every type — this shape isn't guaranteed here since it's whatever rivalsearch's web_search tool happens to return.
  • Unlike tool's "execute" arm in src/mcp_server.rs (which caps payloads via gateway_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 reusing truncate_if_needed for consistency with the tool action.

Separately, there's a search_*_requires_non_empty_query test for store/memory/code but none for web, 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

📥 Commits

Reviewing files that changed from the base of the PR and between a2a0445 and fc7cc8b.

📒 Files selected for processing (5)
  • src/mcp_server.rs
  • src/mcp_server/search.rs
  • src/mcp_server/tests/mod.rs
  • src/mcp_server/tests/search_tests.rs
  • src/mcp_server/types.rs

Comment thread src/mcp_server/search.rs Outdated
getappz added 2 commits July 21, 2026 12:59
…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
@getappz

getappz commented Jul 21, 2026

Copy link
Copy Markdown
Owner Author

Both CodeRabbit findings addressed:

  • Blocking subprocess without timeout (Major): resolved in 438e2f9 — the code arm no longer spawns a subprocess at all; it delegates to the gateway's leanctx MCP server via the same async reg.execute path as the web arm.
  • search_web raw payload / contract divergence (Nitpick): fixed in aa15ae6 — web results are now wrapped in the same { source, query, results } envelope as every other arm; the limit param already caps results via max_results.

@getappz
getappz enabled auto-merge (squash) July 21, 2026 07:45
@getappz
getappz merged commit bf46211 into master Jul 21, 2026
15 of 16 checks passed
@getappz
getappz deleted the feature/global-search-129 branch July 21, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant