refactor(mcp): phase 5.3 — thread RepoProvider through server + tool handlers#30
Merged
Merged
Conversation
…handlers
Completes the provider-abstraction plumbing. createServer now accepts a
provider option alongside projectRoot; tool register functions take the
provider as a first-class parameter; write-path handlers gate on
projectRoot presence and return a uniform capability error when local
disk access is unavailable. Read-only static tools (describe_format)
now work against any ToolProvider — the foundation for phase 5.4's
remote write path.
Changes:
Read helpers (core/)
- readConfig / readVocabulary (core/config.ts) and readModel / listModels
(core/model-manager.ts) add RepoReader-based overloads alongside the
legacy projectRoot signature. Backward-compatible: every existing
caller keeps working; GitHubProvider reads go through the same
helpers via reader-based overload.
Server plumbing (server.ts)
- ToolProvider type alias (RepoReader + capabilities) — narrower than
the full RepoProvider so LocalProvider (reader + applyPlan today) and
GitHubProvider (full provider) both satisfy it without requiring
LocalProvider to stub branch-ops yet.
- createServer({ provider, projectRoot? }) overload. String argument
continues to work via a backward-compat path that wraps projectRoot
in a LocalProvider. When only a provider is supplied and the provider
is a LocalProvider, projectRoot is derived from it; otherwise stays
undefined.
- Every registerXxxTools call receives (server, provider, projectRoot).
Tool handlers (tools/)
- guards.ts: new capabilityError helper emits a uniform JSON response
with capability_required, a hint, and isError:true so agents can
decide whether to retry against another transport.
- content, model, context, workflow, normalize, setup, bulk — signature
updated to accept ToolProvider + optional projectRoot. Each handler
adds a one-line gate at the top: if projectRoot is undefined, return
capabilityError. contentrain_describe_format is the exception — it
is static data and therefore works against any provider.
- Normalize surfaces the right capability key: contentrain_scan →
astScan, contentrain_apply → sourceRead (extract) or sourceWrite
(reuse). contentrain_bulk, contentrain_content_*, model_*, setup,
workflow → localWorktree.
HTTP transport (server/http/)
- startHttpMcpServerWith({ provider, projectRoot? }) — new variant that
accepts a pre-built provider. Internally shares the same
StreamableHTTPServerTransport wiring as the legacy
startHttpMcpServer({ projectRoot }) path. Node http server,
auth-token guard, mount-path enforcement identical to phase 5.2.
- Both entry points now go through a single startHttpMcpServerInternal
helper so the Bearer / mount / listen / close semantics stay in one
place.
Tests
- tests/server/http.test.ts adds two Phase 5.3 cases:
* describe_format over HTTP with a provider-only config (no
projectRoot) returns the format spec.
* contentrain_status over HTTP with a provider-only config returns
capability_required: localWorktree with isError:true.
- Existing 4 HTTP tests, 25 conformance / parity / validator / github
tests, and 40 tool tests (content 17, model 8, workflow 15) all stay
green — the stdio path is bit-for-bit unchanged.
Verification
- pnpm vitest run conformance serialization-parity core/validator
providers/github server/http → 65/65 (plus 2 new Phase 5.3 cases in
server/http = 6/6 there).
- pnpm vitest run tools/content.test tools/model.test tools/workflow.test
→ 40/40 (~610s).
- pnpm typecheck → all 6 packages clean.
- oxlint on mcp src/ → 0 warnings.
What phase 5.3 does NOT ship (staged for phase 5.4)
- Write path via GitHubProvider. LocalProvider.applyPlan still runs the
full worktree + workflow flow; GitHubProvider.applyPlan is available
but not yet routed from tool handlers. Phase 5.4 picks off
content_save / content_delete / model_save / model_delete and runs
them against a GitHubProvider once the workflow semantics are
adapted (PR fallback, no selective sync, base branch resolution).
- validateProject reader overload. Project-wide validation still reads
via projectRoot, so post-save validation runs only on LocalProvider.
A reader-backed validateProject lands alongside the write path in
phase 5.4.
Refs:
- .internal/refactor/01-mcp-engine-plan.md phase 5
- .internal/refactor/00-principles.md §5.3 capability system
- .internal/refactor/02-studio-handoff.md phase S6 (MCP Cloud endpoint)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the provider-abstraction plumbing started in phase 5.1. `createServer` accepts a provider option alongside `projectRoot`; tool register functions take the provider as a first-class parameter; write-path handlers gate on `projectRoot` presence and return a uniform capability error when local disk is unavailable. Read-only static tools (`contentrain_describe_format`) now work against any `ToolProvider` — the foundation for phase 5.4's remote write path.
Behaviour for the stdio flow (and for HTTP + LocalProvider) is bit-for-bit unchanged; every existing test continues to pass.
What changed
Read helpers (`core/`)
Server plumbing (`server.ts`)
Tool handlers (`tools/`)
HTTP transport (`server/http/`)
Tests
Test plan
What phase 5.3 does NOT ship (staged for phase 5.4)
Refs
🤖 Generated with Claude Code