⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
⚠️ Required pattern: mirror loopover_refresh_repo_docs in src/mcp/server.ts — same
"force an immediate refresh of a cached repo artifact" shape, same write-access auth boundary.
Context
POST /v1/repos/:owner/:repo/focus-manifest/refresh (src/api/routes.ts) force-reloads a repo's
cached .loopover.yml focus manifest from GitHub (loadRepoFocusManifest(c.env, fullName, { refresh: true })), gated by requireRepoWriteAccess, and is documented in OpenAPI. This is a pure
cache-refresh action — it does not author new policy content (that's the separate PUT /v1/repos/:owner/:repo/focus-manifest write route, out of scope here).
The read side of this same manifest already has an MCP tool: loopover_get_repo_focus_manifest
(added in #7808, explicitly documented as "Read-only... same auth boundary as GET
/v1/repos/:owner/:repo/focus-manifest"). A separate, already-shipped tool,
loopover_refresh_repo_docs, establishes the exact "force a cached artifact to refresh now" pattern
for a different artifact (AGENTS.md/CLAUDE.md docs) with the same requireRepoWriteAccess-class auth
boundary. The focus-manifest refresh action has no MCP tool at all.
Requirements
- Add a new MCP tool
loopover_refresh_repo_focus_manifest in src/mcp/server.ts, registered via
the standard register(...) wrapper (_meta.category from MCP_TOOL_CATEGORIES; use
"maintainer", matching loopover_refresh_repo_docs).
- Input shape: reuse
ownerRepoShape ({ owner, repo }) — same as loopover_get_repo_focus_manifest.
- Auth: write-access boundary, matching the REST route's
requireRepoWriteAccess (not the weaker
read-only boundary loopover_get_repo_focus_manifest uses — this action forces a live refresh, so
it needs the same write-access check the REST route enforces).
- Handler: call
loadRepoFocusManifest(this.env, fullName, { refresh: true }) (the same function and
refresh: true option the REST route uses) then compileFocusManifestPolicy, returning the same
{ repoFullName, manifest, policy } shape the REST route returns.
- No OpenAPI/schema regeneration required:
POST /v1/repos/:owner/:repo/focus-manifest/refresh is
unchanged and already documented — only a new MCP tool wrapper is added.
Deliverables
All deliverables are required in this one PR — there is no follow-up issue.
Test Coverage Requirements
99%+ Codecov patch target (codecov/patch, unsharded via npm run test:coverage) on every branch of
the new tool, including the auth-rejection branch. Add a regression test asserting the tool actually
forces a fresh load (not a cached read) — e.g. by asserting the underlying refresh: true option is
passed through, matching the REST route's own behavior.
Expected Outcome
A write-access-authenticated MCP client can force a repo's cached focus manifest to refresh from
GitHub without falling back to the REST API — closing the gap between the read tool
(loopover_get_repo_focus_manifest, #7808) and its refresh counterpart.
Links & Resources
Context
POST /v1/repos/:owner/:repo/focus-manifest/refresh(src/api/routes.ts) force-reloads a repo'scached
.loopover.ymlfocus manifest from GitHub (loadRepoFocusManifest(c.env, fullName, { refresh: true })), gated byrequireRepoWriteAccess, and is documented in OpenAPI. This is a purecache-refresh action — it does not author new policy content (that's the separate
PUT /v1/repos/:owner/:repo/focus-manifestwrite route, out of scope here).The read side of this same manifest already has an MCP tool:
loopover_get_repo_focus_manifest(added in #7808, explicitly documented as "Read-only... same auth boundary as GET
/v1/repos/:owner/:repo/focus-manifest"). A separate, already-shipped tool,
loopover_refresh_repo_docs, establishes the exact "force a cached artifact to refresh now" patternfor a different artifact (AGENTS.md/CLAUDE.md docs) with the same
requireRepoWriteAccess-class authboundary. The focus-manifest refresh action has no MCP tool at all.
Requirements
loopover_refresh_repo_focus_manifestinsrc/mcp/server.ts, registered viathe standard
register(...)wrapper (_meta.categoryfromMCP_TOOL_CATEGORIES; use"maintainer", matchingloopover_refresh_repo_docs).ownerRepoShape({ owner, repo }) — same asloopover_get_repo_focus_manifest.requireRepoWriteAccess(not the weakerread-only boundary
loopover_get_repo_focus_manifestuses — this action forces a live refresh, soit needs the same write-access check the REST route enforces).
loadRepoFocusManifest(this.env, fullName, { refresh: true })(the same function andrefresh: trueoption the REST route uses) thencompileFocusManifestPolicy, returning the same{ repoFullName, manifest, policy }shape the REST route returns.POST /v1/repos/:owner/:repo/focus-manifest/refreshisunchanged and already documented — only a new MCP tool wrapper is added.
Deliverables
loopover_refresh_repo_focus_manifesttool registered insrc/mcp/server.ts, backed byloadRepoFocusManifest(..., { refresh: true })+compileFocusManifestPolicy, with the samewrite-access auth boundary as the REST route.
MCP_TOOL_CATEGORIES.session without write access must be rejected, distinct from the read tool's weaker boundary).
All deliverables are required in this one PR — there is no follow-up issue.
Test Coverage Requirements
99%+ Codecov patch target (
codecov/patch, unsharded vianpm run test:coverage) on every branch ofthe new tool, including the auth-rejection branch. Add a regression test asserting the tool actually
forces a fresh load (not a cached read) — e.g. by asserting the underlying
refresh: trueoption ispassed through, matching the REST route's own behavior.
Expected Outcome
A write-access-authenticated MCP client can force a repo's cached focus manifest to refresh from
GitHub without falling back to the REST API — closing the gap between the read tool
(
loopover_get_repo_focus_manifest, #7808) and its refresh counterpart.Links & Resources
src/api/routes.ts:POST /v1/repos/:owner/:repo/focus-manifest/refreshsrc/mcp/server.ts:loopover_get_repo_focus_manifest(loopover_get_repo_focus_manifest (read-only) has a REST route but no remote MCP tool or local stdio MCP tool #7808, read-side sibling to pair with),loopover_refresh_repo_docs(refresh-action pattern sibling)