feat(mcp): expose thread search#8722

closed2
agents/mcp-thread-search/search
agents/mcp-thread-search/tool
openedAug 30, 2026byJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3d ago

Problem

Agents can read known threads but cannot search durable thread content and then navigate directly to a matching visible message.

Change

Expose t3_thread_search as a read-only MCP tool over the bounded projection query from #8721. The tool:

  • defaults to the calling thread and current project scope
  • supports an optional same-project thread filter and archived opt-in
  • returns bounded snippets, source and storage origin, live pagination state, and nullable V2 read anchors
  • lets t3_thread_read.anchor start inclusively at the matching visible source/message identity
  • maps typed input errors to invalid_request and persistence failures to fixed structural errors without exposing SQL details
  • remains available to every provider, including Claude's read-only allowlist
  • keeps the merged t3_thread_update registration and metadata behavior intact

Behavior

Search is read-only and never imports transcripts, acknowledges child delivery, or returns full messages. An anchor that is foreign, stale, rolled back, or no longer visible fails instead of falling back to a raw ordinal.

Validation

  • vp test run apps/server/src/mcp/OrchestratorMcpToolkit.integration.test.ts apps/server/src/mcp/toolkits/worktree/registration.test.ts packages/contracts/src/orchestratorMcp.test.ts packages/shared/src/t3McpToolPresentation.test.ts (15/15)
  • production MCP registration with a real SQLite/V2 search hit to anchored-read round trip
  • root-object tool schemas, current-project rejection, bounded astral-Unicode result encoding, and provider presentation/allowlist coverage
  • scoped t3, @t3tools/contracts, and @t3tools/shared typechecks
  • targeted lint, format, and git diff --check

Dependency

Upper member of native stack #8785. Depends on #8721.

Implemented by GPT-5.6-Sol via Codex in T3 Code.

Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d5761cd6-780d-4df6-8211-48816877e81d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

MmacroscopeappBotreviewed · 1 inline threadAug 30, 2026
Synced from GitHub

Reviewed the new ThreadSearchMcpService and its call sites against the Effect service conventions. One violation found: a standalone ThreadSearchMcpServiceShape interface instead of an inline Context.Service interface. Imports, make/layer naming, dependency acquisition (yield* ThreadManagementService / yield* ProjectionSnapshotQuery), and the test-only Layer.mock seams all look consistent with the conventions.

Posted via Macroscope — Effect Service Conventions

apps/server/src/mcp/ThreadSearchMcpService.tslines 20–30Outdated · 7ae406dOpen thread
……@@ -0,0 +1,127 @@
27+export class ThreadSearchMcpService extends Context.Service<
28+ ThreadSearchMcpService,
29+ ThreadSearchMcpServiceShape
30+>()("t3/mcp/ThreadSearchMcpService") {}
MmacroscopeappBoton lines 20–30Aug 30, 2026

mcp/ThreadSearchMcpService.ts:30

Consider defining the service interface inline in the Context.Service declaration rather than keeping a standalone ThreadSearchMcpServiceShape (the sibling WorktreeMcpService does this). The inferred shape can then be referenced as ThreadSearchMcpService["Service"].

ts
1export class ThreadSearchMcpService extends Context.Service<ThreadSearchMcpService>()(
2 "t3/mcp/ThreadSearchMcpService",
3 {
4 readonly search: (
5 scope: McpInvocationScope,
6 input: OrchestratorMcpThreadSearchInput,
7 ) => Effect.Effect<OrchestratorMcpThreadSearchResult, OrchestratorMcpFailure>;
8 }
9) {}

(or keep the current two-type-argument form with the object literal inlined). The satisfies ThreadSearchMcpServiceShape on line 124 then becomes satisfies ThreadSearchMcpService["Service"], or use ThreadSearchMcpService.of({ search }).

No longer relevant as of e5585e831fb1e8f76154c05ffcac31662ab42c99

Synced from GitHub

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 70a74a5.

This comment will update automatically after the next completed run.

apps/server/src/mcp/ThreadSearchMcpService.tsline 81Outdated · fe198b0Open thread
……@@ -0,0 +1,132 @@
78+ }
79+ }
80+
81+ const page = yield* projectionQuery

🟠 High mcp/ThreadSearchMcpService.ts:81

search returns no hits for newly created V2 threads, including their titles and messages, because searchThreadContent joins only the legacy projection_threads data while V2 projections are stored in orchestration_v2_projection_threads. Update the query to include the V2 projection table (or a unified source) so current MCP threads are searchable.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
text
1In file @apps/server/src/mcp/ThreadSearchMcpService.ts around line 81:
2
3`search` returns no hits for newly created V2 threads, including their titles and messages, because `searchThreadContent` joins only the legacy `projection_threads` data while V2 projections are stored in `orchestration_v2_projection_threads`. Update the query to include the V2 projection table (or a unified source) so current MCP threads are searchable.

Fixed by the lower query layer in 0fc6b466c87620156b8213855dd7403a83597cd6 and carried into this PR at eaff95128e6315530803cad7d6ab3d829bec338e. Search metadata is now V2-authoritative for native and imported V2 threads, including title, archive, and deletion state. Legacy metadata remains only for thread IDs with no V2 counterpart. The production MCP integration uses managed V2 writes and the real SQLite query, then reads the returned anchor.

packages/contracts/src/orchestratorMcp.tsline 345Outdated · fe198b0Open thread
……@@ -301,14 +302,86 @@ export const OrchestratorMcpThreadListResult = Schema.Struct({
342+ archived: Schema.Boolean,
343+ source: Schema.Literals(["title", "user", "assistant"]),
344+ origin: Schema.Literals(["legacy", "v2"]),
345+ snippet: Schema.String.check(Schema.isMaxLength(1_000)),
MmacroscopeappBoton line 345Aug 30, 2026

🟠 High src/orchestratorMcp.ts:345

A search result containing 1,000 astral Unicode characters is rejected by OrchestratorMcpThreadSearchResult, so emoji/non-BMP snippets cannot be returned successfully. Schema.isMaxLength(1_000) counts UTF-16 code units, while the producer counts Array.from(...).length code points; use the same code-point limit for snippet and query (the latter currently rejects valid 101–200-character astral queries at Schema.isMaxLength(200)).

✅ Resolved in e5585e831fb1e8f76154c05ffcac31662ab42c99

Synced from GitHub

Approvability

Verdict: Approved at 3430825

Macroscope's review found this PR approvable — This adds a bounded, read-only MCP search tool around the existing projection query, with capability/project scoping, strict result limits, and coverage for contracts, integration, and registration behavior. Existing thread-read behavior and stored data remain unchanged unless the new search/anchor path is explicitly used.

No code changes detected at 70a74a5. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

Added 2 commits

  • test(mcp): provide search query to replay toolkit70a74a5
  • feat(mcp): expose thread searche73cb5f

Superseded as the active MCP proposal by #10561 in the rebuilt MCP stack, following the maintainer request to review thin service wrappers separately from service hardening.

This is not a full feature-parity replacement. This filters the global top results, so a project can underfill the requested limit. It is not exhaustive or paginated. Project-first SQL pagination and search-service correctness changes belong in a separate service PR.

Closing this mixed proposal without merging. The remote branch agents/mcp-thread-search/tool and exact head 70a74a55ba4420d213fc2a56e2f627c8bd4d6b96 are retained so the service changes can be extracted for separate review later.