Skip to content

refactor(mcp): align catalog with explicit capability boundaries - #293

Merged
morluto merged 2 commits into
mainfrom
agent/clean-mcp-catalog
Aug 12, 2026
Merged

refactor(mcp): align catalog with explicit capability boundaries#293
morluto merged 2 commits into
mainfrom
agent/clean-mcp-catalog

Conversation

@morluto

@morluto morluto commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Description

The MCP catalog had two conflicting models at once: composable fact and acquisition tools were the intended public boundary, while older workflow-shaped operations still bundled reads, network hydration, local writes, verdicts, jobs, and bespoke artifacts. A removal shim hid several of those tools without completing their migrations, leaving dossier generation unreachable and discarding useful offline analysis.

This refactor makes the catalog match its capability boundaries:

  • exposes dossier construction as the idempotent local-write corpus.materialize_repository_dossier and returns a followable dossier resource;
  • restores fix-pattern mining as snapshot-bound, offline corpus.analyze_fix_patterns, with storage-free classification, bounded proof-style detection, coverage, limitations, and typed acquisition recovery;
  • restores cross-repository corpus.rank_contribution_candidates through the application-owned Contribution Radar service;
  • replaces preflight and related-work composites with explicit authenticated-identity, fork-comparison, duplicate, competing-PR, coverage, and exact-thread operations;
  • makes corpus.search_code the bounded canonical single-query and batch route;
  • keeps DeepWiki as an optional non-authoritative external research primitive;
  • scopes pull-request feedback discovery and recovery to the requested PR state, serializes the shared feedback writer boundary, and stops querying GraphQL fields removed from PullRequestReviewComment;
  • removes obsolete workflow/report contracts, compatibility routing, and generated setup guidance that named retired tools.

The documentation now has one current MCP guide instead of separate migration, redesign, scalable-workflow, and composition narratives. The runbooks were also corrected to use supported CLI behavior.

Behavior and compatibility

This intentionally removes the public composite routes workflow.prepare_issue_set, workflow.preflight_contribution, workflow.find_related_work, workflow.build_repository_dossier, workflow.mine_repository_fix_patterns, corpus.preview_fix_patterns, and the legacy scalar code-search alias. There are no compatibility aliases, consistent with the repository's architecture contract.

No GitHub mutation capability is added. Fix-pattern analysis and candidate ranking remain offline reads; dossier materialization is an honestly annotated local write. No issue-evidence aggregate is added without controlled evidence that clients repeatedly lose coverage or provenance during composition.

Suggested review order

  1. internal/mcpcontract, internal/fixpatterns, and internal/radar for the public contracts and storage-free computation.
  2. internal/app/mcp_fix_pattern_analysis.go, internal/app/mcp_radar.go, and internal/app/mcp_github_identity.go for side-effect ownership and recovery.
  3. internal/mcpserver for registration, annotations, schemas, and resource routing.
  4. Pull-request feedback corpus/application changes for state-scoped coverage and writer serialization.
  5. docs/mcp.md, docs/architecture.md, and docs/runbooks.md for the resulting public contract.

Testing

  • make verify passes
  • Focused regression coverage was added or updated where applicable
  • make test-race passes for storage, concurrency, locking, or cancellation changes

Additional documentation checks included local Markdown target validation and stale-reference scanning.

Compatibility and scope

  • Storage and side-effect invariants remain intact
  • No unrelated cleanup or generated-output churn is included

@morluto
morluto marked this pull request as ready for review August 12, 2026 12:34
@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a99ac5cfb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

threadState = "all"
}
threads, err := c.ListPullRequestsWithIncompleteFeedback(ctx, repositoryID, channels, threadState, 50)
threads, err := c.ListPullRequestsWithIncompleteFeedback(ctx, repositoryID, channels, threadState, maxExactFeedbackPullRequests)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope incomplete-feedback recovery to the requested state

When a search is scoped to state=open or state=closed, page.Coverage.IncompletePRs is calculated only for that state, but this recovery query still lists incomplete PRs from every state. Because the list is ordered and capped at 100, unrelated closed PRs can fill the recovery batch for an open-only search, leaving the PRs responsible for the partial result unsynchronized on every retry. Pass the requested PR state into this query or filter its results accordingly.

AGENTS.md reference: AGENTS.md:L12-L16

Useful? React with 👍 / 👎.

next := request.canonical
next.SnapshotToken = ""
if out.Truncated {
next.CandidateLimit = min(100, max(next.CandidateLimit*2, next.CandidateLimit+1))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Make capped fix-pattern recovery advance

If a symptom matches more than 100 PRs, CandidateLimit is already at its allowed maximum, so this expression leaves it at 100 and the returned recovery action reruns the identical truncated analysis. With complete history and no unknown outcomes, that rerun is the only action and can never make progress. Provide pagination or a narrowing recovery, or avoid advertising an unchanged rerun at the cap.

AGENTS.md reference: AGENTS.md:L48-L49

Useful? React with 👍 / 👎.

Comment thread internal/app/mcp_radar.go
if out.Truncated {
out.Status = "partial"
next := freshCandidateRankingInput(in)
next.Limit = min(100, max(in.Limit*2, in.Limit+1))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid a no-op recovery at the ranking limit

When the caller already requests limit=100 and more candidates exist, out.Truncated is true but this recovery leaves next.Limit at the maximum of 100. After the header sync, the prescribed rerun has the same bounds and remains truncated indefinitely for a stable repository. The recovery should offer a progressing strategy, such as narrowing the repository set/query, rather than replaying an unchanged capped request.

AGENTS.md reference: AGENTS.md:L48-L49

Useful? React with 👍 / 👎.

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