⚠️ 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 the shape of loopover_get_bounty_advisory in src/mcp/server.ts
(registered around the register("loopover_get_bounty_advisory", ...) call, input bountyShape,
handler backed by getBounty).
Context
src/api/routes.ts exposes three bounty endpoints, all documented in src/openapi/spec.ts:
GET /v1/bounties — app.get("/v1/bounties", async (c) => c.json(await listBounties(c.env)));
GET /v1/bounties/:id/advisory — has an MCP mirror: loopover_get_bounty_advisory in
src/mcp/server.ts (bountyShape input, bountyAdvisoryOutputSchema output, calls
getBounty/buildBountyAdvisory).
GET /v1/bounties/:id/lifecycle — app.get("/v1/bounties/:id/lifecycle", ...), calls
getBounty + listBountyLifecycleEvents, returns { bountyId, events }.
Only the advisory route has an MCP tool. The list route (GET /v1/bounties) and the lifecycle
route (GET /v1/bounties/:id/lifecycle) are real, publicly documented REST endpoints
(BountySchema / BountyLifecycleEventsSchema are already registered OpenAPI components) with no
agent-facing MCP equivalent — an agent using the MCP tool surface can inspect one specific bounty's
advisory but cannot discover which bounties exist or read a bounty's lifecycle history at all.
Requirements
- Add a new MCP tool
loopover_list_bounties in src/mcp/server.ts, registered the same way as
every other read-only tool (register("loopover_list_bounties", { description, inputSchema, outputSchema }, handler)), with _meta.category set via the existing MCP_TOOL_CATEGORIES map
(use "discovery", matching loopover_get_bounty_advisory's category). It takes no repo/owner
input — mirror listBounties(c.env) from the REST route exactly (same data, no added filtering).
- Add a new MCP tool
loopover_get_bounty_lifecycle in src/mcp/server.ts, same registration
pattern, input shape bountyShape (reuse the existing { id: z.string().min(1) } shape used by
loopover_get_bounty_advisory), calling getBounty + listBountyLifecycleEvents and returning
the same { bountyId, events } shape the REST route returns. Return the same "bounty not found"
error behavior as the REST route (404) — surfaced as a tool error, not a silent empty result.
- Both tools are read-only lookups with no repo/owner auth scoping in the REST route today — do not
add new auth requirements the REST route doesn't have.
- Add both tool names + their categories to the
MCP_TOOL_CATEGORIES map at the top of
src/mcp/server.ts, next to loopover_get_bounty_advisory: "discovery".
- No OpenAPI/schema regeneration is required for this issue:
GET /v1/bounties and
GET /v1/bounties/:id/lifecycle are unchanged REST routes, already documented in
src/openapi/spec.ts (BountySchema, BountyLifecycleEventsSchema) — this issue only adds new
MCP tool wrappers around existing, already-documented responses. No request/response contract
changes anywhere.
Deliverables
All deliverables are required in this one PR — there is no follow-up issue.
Test Coverage Requirements
New code must hit this repo's 99%+ Codecov patch target (codecov/patch, measured unsharded via
npm run test:coverage) — every branch of both new tool handlers, including the bounty-not-found
error path for loopover_get_bounty_lifecycle, needs a direct unit test in src/mcp/server.test.ts
(or the sibling test file this repo already uses for MCP tool tests). Include a regression test
asserting the tool output for a fixture bounty matches the equivalent REST route's response shape.
Expected Outcome
An MCP client can list all bounties and read a specific bounty's lifecycle history — the same data
already available over REST and already documented in the OpenAPI spec — without needing to fall
back to the REST API directly, closing the last gap in bounty read-parity between the two surfaces.
Links & Resources
src/api/routes.ts: GET /v1/bounties, GET /v1/bounties/:id/advisory, GET /v1/bounties/:id/lifecycle
src/mcp/server.ts: existing loopover_get_bounty_advisory tool (the sibling to mirror)
src/openapi/spec.ts / src/openapi/schemas.ts: BountySchema, BountyAdvisorySchema,
BountyLifecycleEventsSchema (already registered; reuse, don't redefine)
Context
src/api/routes.tsexposes three bounty endpoints, all documented insrc/openapi/spec.ts:GET /v1/bounties—app.get("/v1/bounties", async (c) => c.json(await listBounties(c.env)));GET /v1/bounties/:id/advisory— has an MCP mirror:loopover_get_bounty_advisoryinsrc/mcp/server.ts(bountyShapeinput,bountyAdvisoryOutputSchemaoutput, callsgetBounty/buildBountyAdvisory).GET /v1/bounties/:id/lifecycle—app.get("/v1/bounties/:id/lifecycle", ...), callsgetBounty+listBountyLifecycleEvents, returns{ bountyId, events }.Only the
advisoryroute has an MCP tool. The list route (GET /v1/bounties) and the lifecycleroute (
GET /v1/bounties/:id/lifecycle) are real, publicly documented REST endpoints(
BountySchema/BountyLifecycleEventsSchemaare already registered OpenAPI components) with noagent-facing MCP equivalent — an agent using the MCP tool surface can inspect one specific bounty's
advisory but cannot discover which bounties exist or read a bounty's lifecycle history at all.
Requirements
loopover_list_bountiesinsrc/mcp/server.ts, registered the same way asevery other read-only tool (
register("loopover_list_bounties", { description, inputSchema, outputSchema }, handler)), with_meta.categoryset via the existingMCP_TOOL_CATEGORIESmap(use
"discovery", matchingloopover_get_bounty_advisory's category). It takes no repo/ownerinput — mirror
listBounties(c.env)from the REST route exactly (same data, no added filtering).loopover_get_bounty_lifecycleinsrc/mcp/server.ts, same registrationpattern, input shape
bountyShape(reuse the existing{ id: z.string().min(1) }shape used byloopover_get_bounty_advisory), callinggetBounty+listBountyLifecycleEventsand returningthe same
{ bountyId, events }shape the REST route returns. Return the same "bounty not found"error behavior as the REST route (404) — surfaced as a tool error, not a silent empty result.
add new auth requirements the REST route doesn't have.
MCP_TOOL_CATEGORIESmap at the top ofsrc/mcp/server.ts, next toloopover_get_bounty_advisory: "discovery".GET /v1/bountiesandGET /v1/bounties/:id/lifecycleare unchanged REST routes, already documented insrc/openapi/spec.ts(BountySchema,BountyLifecycleEventsSchema) — this issue only adds newMCP tool wrappers around existing, already-documented responses. No request/response contract
changes anywhere.
Deliverables
loopover_list_bountiestool registered insrc/mcp/server.ts, backed bylistBounties,returning the same data as
GET /v1/bounties.loopover_get_bounty_lifecycletool registered insrc/mcp/server.ts, backed bygetBounty+listBountyLifecycleEvents, returning the same{ bountyId, events }shape asGET /v1/bounties/:id/lifecycle, including the not-found case.MCP_TOOL_CATEGORIES.All deliverables are required in this one PR — there is no follow-up issue.
Test Coverage Requirements
New code must hit this repo's 99%+ Codecov patch target (
codecov/patch, measured unsharded vianpm run test:coverage) — every branch of both new tool handlers, including the bounty-not-founderror path for
loopover_get_bounty_lifecycle, needs a direct unit test insrc/mcp/server.test.ts(or the sibling test file this repo already uses for MCP tool tests). Include a regression test
asserting the tool output for a fixture bounty matches the equivalent REST route's response shape.
Expected Outcome
An MCP client can list all bounties and read a specific bounty's lifecycle history — the same data
already available over REST and already documented in the OpenAPI spec — without needing to fall
back to the REST API directly, closing the last gap in bounty read-parity between the two surfaces.
Links & Resources
src/api/routes.ts:GET /v1/bounties,GET /v1/bounties/:id/advisory,GET /v1/bounties/:id/lifecyclesrc/mcp/server.ts: existingloopover_get_bounty_advisorytool (the sibling to mirror)src/openapi/spec.ts/src/openapi/schemas.ts:BountySchema,BountyAdvisorySchema,BountyLifecycleEventsSchema(already registered; reuse, don't redefine)