Skip to content

MCP: status tool, self-describing empty results, explicit done-filter error#1362

Merged
r3dbars merged 1 commit into
mainfrom
claude/agent-fix-3-mcp-status-tool-pbwyng
Jul 3, 2026
Merged

MCP: status tool, self-describing empty results, explicit done-filter error#1362
r3dbars merged 1 commit into
mainfrom
claude/agent-fix-3-mcp-status-tool-pbwyng

Conversation

@r3dbars

@r3dbars r3dbars commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Why

The MCP server's dominant failure mode is silent emptiness: an agent getting [] can't distinguish "no data" from "wrong directory" from "index not built" from "feature needs summaries enabled" — so it confidently tells the user they have no meetings. Specific offenders from the agent-surface audit: no runtime introspection at all (the --self-test diagnostics are unreachable from an MCP client), rollup tools that are empty for anyone without saved summaries, and list_action_items status:"done" compiling to AND 1=0.

Product Impact

  • Affects: agent artifacts
  • Lane: agent workflow
  • Why this matters: self-describing responses are the difference between an agent that recovers ("your index has 0 meetings — check the searched folders") and one that hallucinates an answer.

What changed

  • New status tool (13th tool, read-only): server version, resolved meeting/dictation directories, which resolution rule won (env_data_dir / env_kind_dirs / app_manifest / app_preference / default), whether legacy fallback dirs were appended, index directory, and indexed counts (meetings, dictation days/entries, summary items, summarized meetings, summaries_indexed).
  • TranscriptedCaptureKit: additive CaptureLibraryResolutionSource enum + resolutionSource/legacyFallbackAppended on ResolvedCaptureDirectories (new init params defaulted; the CLI call site compiles unchanged).
  • Self-describing empty results in all 9 query tools: empty responses now carry searched_directories, scope-relevant indexed counts, and a hint that distinguishes "nothing indexed — call the status tool" from "nothing matched these filters". Rollup tools explain that they only cover meetings with saved summaries. Non-empty responses are byte-identical.
  • status:"done" now errors explicitly ("not tracked in saved summaries yet; use open or all") instead of returning a silent empty set; tool schema/description updated. The defensive AND 1=0 stays at the index layer.
  • Main.swift now has a single serverVersion constant reused by --version, the startup log, Server(version:), and status.
  • Tests: 8 new handler tests (status shape, empty hints per scope, done error) + resolver source/fallback assertions; TranscriptIndex.counts() with 5 small COUNT queries.
  • Tools/TranscriptedMCP/CLAUDE.md: status row, done-filter note, empty-result gotcha, refreshed file index.

How I checked it

  • scripts/dev/agent-preflight.sh
  • Selected checks from .agents/test-matrix.yml — CaptureKit rule = package-test union + e2e smoke
  • swift test --package-path Tools/TranscriptedCaptureKit + Tools/TranscriptedCLI + Tools/TranscriptedMCP + bash run-e2e-smoke.shall run by Swift CI on macOS at this exact head (802ff5f), green: https://github.com/r3dbars/transcripted/actions/runs/28621577716 (the workflow runs the full matrix: build, fast tests, Core swift test, integration smoke, e2e smoke, and all four Tools package suites)
  • Manual check: resolver changes verified additive against the CLI call site; diff reviewed hunk-by-hunk.

Authoring context: written in a Linux session with no local Swift toolchain; verification is the green macOS Swift CI run above (required merge gate, same matrix as local runs).

Risk Review

  • Privacy / local-first behavior reviewed — status and empty-result fields expose local paths to the local MCP client only (same trust boundary as read_meeting returning transcript text)
  • Storage path or migration impact reviewed — resolution behavior unchanged; only observability added
  • Public-facing copy stays concrete and matches current product scope
  • Release/update impact reviewed — the bundled helper picks this up on the next app build; self-heal refresh covers installed copies
  • Agent PRs link the issue/workpad and stay draft until human review
  • UI changes include sanitized .agent-review/visuals/ evidence — n/a
  • No private transcripts, audio, tokens, personal paths, or customer data are included

Notes

Part of the agent-surface audit series (#1356#1361) and step 2 of the consolidation plan in #1358. Known behavior change: empty responses switch from plain text ("No meetings found.") to structured JSON — intentional, that's the fix. One judgment call: with only one per-kind env override set, resolution_source reports env_kind_dirs even though the other kind resolved lower in the chain (commented in the resolver).

#1363 (read-path pagination) stacks on this branch because both touch ToolHandlers.swift — merge this first.

Agent handoff

COORD_DONE: GREEN | (this PR) | status tool + self-describing empties + done-filter error | none | none | Swift CI green at head 802ff5f (full matrix incl. all package tests + e2e) | human review + mark ready + merge, then #1363

🤖 Generated with Claude Code

https://claude.ai/code/session_01GuGZaFRmNrqfGPpqf7WH4n

…lter error

Kill the "silent empty result" failure mode in the transcripted-mcp server:

- New read-only `status` tool: server version, resolved meeting/dictation
  directories, which resolution rule selected them (plus legacy-fallback
  flag), index directory, and indexed counts (meetings, dictation days,
  dictation entries, summary items, summarized meetings,
  summaries_indexed).
- Zero-result responses from list_meetings, list_dictations, search,
  search_context, recent_context, recap, list_action_items,
  list_decisions, and digest now return a JSON payload with
  searched_directories, the relevant indexed counts, and a hint that
  distinguishes "nothing indexed" from "nothing matched". Non-empty
  responses are byte-identical to before.
- list_action_items with status "done" now returns an explicit MCP error
  (saved summaries do not track completion state) instead of compiling to
  an always-empty SQL filter; "open" and "all" behave as before. The
  tool's inputSchema description says so too.

Supporting changes:

- TranscriptedCaptureKit: additive `resolutionSource` enum
  (env_data_dir / env_kind_dirs / app_manifest / app_preference /
  default) and `legacyFallbackAppended` flag on
  ResolvedCaptureDirectories; existing call sites (TranscriptedCLI,
  e2e smoke) compile unchanged.
- TranscriptedDataDirectories carries the two new fields through to the
  status handler.
- TranscriptIndex.counts() adds small COUNT queries over the derived
  tables.
- Main.swift now sources its version string from a single
  `serverVersion` constant reused by --version, the Server handshake,
  and the status tool.
- Tests: status payload shape, empty-result hint fields (meetings,
  dictations, mixed, rollups), done-filter error, and resolver
  resolution-source assertions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GuGZaFRmNrqfGPpqf7WH4n
@r3dbars

r3dbars commented Jul 2, 2026

Copy link
Copy Markdown
Owner Author

Merge-room hold: draft plus MCP/CaptureKit package proof is missing. Live state checked 2026-07-02: head 802ff5f740d7e38672c6b5582f98f365548e806b, base main, mergeStateStatus=CLEAN, repo-hygiene/build-and-test green, hardware-smokes skipped. This adds a new MCP status tool and changes empty-result/error response shapes. Smallest next action: run swift test --package-path Tools/TranscriptedCaptureKit, Tools/TranscriptedCLI, Tools/TranscriptedMCP, plus bash run-e2e-smoke.sh on a Mac, then mark ready.

@r3dbars r3dbars marked this pull request as ready for review July 3, 2026 01:34
@r3dbars r3dbars merged commit 4d04957 into main Jul 3, 2026
3 checks passed
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.

2 participants