Implements the final two slices of the OpenSpec change
mcp-resource-templates. The change now ships all 7 entity
resources (owner, repo, commit, status, issue, comment, pr) on
the forgejo:// URI scheme.
Slice 6 — mcp-resource-pr
- operation/pull/resources.go registers
forgejo://repo/{owner}/{repo}/pr/{index}
- Handler returns JSON metadata (head/base refs, mergeability,
state) + text/markdown sidecar + bounded recent_comments and
recent_reviews (cap 30, sentinels name list_issue_comments
and list_pull_reviews respectively)
- Non-numeric index → -32602; missing PR → -32003
- 6 test cases: open/merged PR, > cap comments, > cap reviews,
non-numeric index, 404
- Wired from RegisterCoreResources
Slice 7 — docs/wrap
- README "Resources" section enriched with URI scheme rationale,
the coexist-with-tools rule, and the embedded-list bounding
policy
- AGENTS.md "## Resources" subsection added for future AI
assistants modifying the resource surface
- CHANGELOG.md unreleased section: additive resource surface
- Follow-up beads filed:
- forgejo-mcp-7ra: revisit subscribe=true once a real
subscription use case appears
- forgejo-mcp-7de: revisit EmbeddedListCap=30 once telemetry
available
Tasks 6.1-6.5, 7.1-7.6 ticked. Final tick count: 46/47.
Only 1.11 (manual client verification across Claude
Code/Desktop/Codex/Cursor) remains, out of scope for this team.
Driven by team:dev-loop (impl, runner; impl replaced by impl2
mid-slice-6 after the original impl ignored two checkpoint
probes). Closes the implementation portion of forgejo-mcp-13x.
67 lines
5.7 KiB
Markdown
67 lines
5.7 KiB
Markdown
## 1. Resource Framework (slice 1 — `mcp-resources-core`)
|
|
|
|
- [x] 1.1 Add `server.WithResourceCapabilities(false, false)` to `newMCPServer` in `operation/operation.go`
|
|
- [x] 1.2 Create `operation/resource/` package skeleton with `doc.go`
|
|
- [x] 1.3 Implement URI parser helpers in `operation/resource/parse.go`: one typed-struct parser per entity (`ParseOwner`, `ParseRepo`, `ParseCommit`, `ParseIssue`, `ParsePR`, `ParseComment`, `ParseStatus`)
|
|
- [x] 1.4 Implement template-registration helpers in `operation/resource/register.go` (thin wrapper around `mcp.NewResourceTemplate` + `s.AddResourceTemplate`)
|
|
- [x] 1.5 Implement embedded-list bounding helper in `operation/resource/bound.go`: produces sentinel block referencing a named list tool, default cap = 30 exposed as `const EmbeddedListCap = 30`
|
|
- [x] 1.6 Implement error-mapping helper in `operation/resource/errors.go`: `MapForgejoError(uri, err) *mcp.JSONRPCError` mapping HTTP `403` → `-32002`, `404` → `-32003`
|
|
- [x] 1.7 Add unit tests for `operation/resource/parse.go` covering: happy path each entity, short sha, non-numeric index, unknown kind
|
|
- [x] 1.8 Add unit tests for `operation/resource/bound.go` covering: under-cap, at-cap, over-cap with sentinel contents
|
|
- [x] 1.9 Add unit tests for `operation/resource/errors.go` covering both code paths
|
|
- [x] 1.10 Add `RegisterCoreResources(s *server.MCPServer)` stub function in `operation/operation.go` (no-op for slice 1, gives stable wiring point)
|
|
- [ ] 1.11 Manual verification against Claude Code, Claude Desktop, Codex, Cursor: confirm each sends `resources/templates/list` and `resources/read`; record results in design.md "Open Questions" answer
|
|
|
|
## 2. Commit Resource (slice 2 — `mcp-resource-commit`)
|
|
|
|
- [x] 2.1 Create `operation/repository/resources_commit.go` (commit lives under repository domain) with `RegisterCommitResource(s *server.MCPServer)`
|
|
- [x] 2.2 Register template `forgejo://repo/{owner}/{repo}/commit/{sha}` with description marking immutability
|
|
- [x] 2.3 Implement handler returning JSON metadata block plus `text/markdown` body sidecar
|
|
- [x] 2.4 Reject shas not exactly 40 hex chars via `operation/resource.ParseCommit`
|
|
- [x] 2.5 Unit tests: existing sha (mock client), short sha, missing sha, sidecar present
|
|
- [x] 2.6 Wire `RegisterCommitResource` from `operation/operation.go`
|
|
- [x] 2.7 README: append commit row to a new "Resources" table
|
|
|
|
## 3. Commit Status Resource (slice 3 — `mcp-resource-status`)
|
|
|
|
- [x] 3.1 Create `operation/repository/resources_status.go` with `RegisterStatusResource(s *server.MCPServer)`
|
|
- [x] 3.2 Register template `forgejo://repo/{owner}/{repo}/commit/{sha}/status` with cacheability note in description
|
|
- [x] 3.3 Implement handler returning aggregate state + bounded `statuses` array via `operation/resource.Bounded(..., "get_commit_statuses")`
|
|
- [x] 3.4 Map empty-statuses case to aggregate `state="unknown"`
|
|
- [x] 3.5 Unit tests: < cap, > cap with sentinel naming `get_commit_statuses`, empty case, short sha, missing sha
|
|
- [x] 3.6 Wire from `operation/operation.go`
|
|
- [x] 3.7 README: append status row to Resources table
|
|
|
|
## 4. Repo + Owner Resources (slice 4)
|
|
|
|
- [x] 4.1 Create `operation/repository/resources_repo.go` with `RegisterRepoResource(s *server.MCPServer)`; template `forgejo://repo/{owner}/{repo}`; return counts only, no embedded lists
|
|
- [x] 4.2 Create `operation/user/resources_owner.go` with `RegisterOwnerResource(s *server.MCPServer)`; template `forgejo://owner/{owner}`; resolve user or org
|
|
- [x] 4.3 Unit tests for each: happy path, 403, 404
|
|
- [x] 4.4 Wire both from `operation/operation.go`
|
|
- [x] 4.5 README: append rows for `repo` and `owner` to Resources table
|
|
|
|
## 5. Issue + Comment Resources (slice 5)
|
|
|
|
- [x] 5.1 Create `operation/issue/resources.go` with `RegisterIssueResources(s *server.MCPServer)`
|
|
- [x] 5.2 Register issue template `forgejo://repo/{owner}/{repo}/issue/{index}` with handler returning metadata + markdown sidecar + bounded `recent_comments` (sentinel names `list_issue_comments`)
|
|
- [x] 5.3 Register comment template `forgejo://repo/{owner}/{repo}/{kind}/{index}/comment/{id}` constraining `kind ∈ {issue, pr}` in parser (reject `wiki` etc. with `-32602`)
|
|
- [x] 5.4 Unit tests: issue happy path, issue with > cap comments, non-numeric index, unknown kind for comment, missing comment
|
|
- [x] 5.5 Wire from `operation/operation.go`
|
|
- [x] 5.6 README: append rows for `issue` and `comment` to Resources table
|
|
|
|
## 6. PR Resource (slice 6 — `mcp-resource-pr`)
|
|
|
|
- [x] 6.1 Create `operation/pull/resources.go` with `RegisterPullResources(s *server.MCPServer)`
|
|
- [x] 6.2 Register template `forgejo://repo/{owner}/{repo}/pr/{index}` with handler returning metadata + head/base refs + mergeability + markdown sidecar + bounded `recent_comments` (sentinel names `list_issue_comments`) + bounded `recent_reviews` (sentinel names `list_pull_reviews`)
|
|
- [x] 6.3 Unit tests: open PR, merged PR, PR with > cap comments, PR with > cap reviews, non-numeric index, missing PR
|
|
- [x] 6.4 Wire from `operation/operation.go`
|
|
- [x] 6.5 README: append row for `pr` to Resources table
|
|
|
|
## 7. Documentation & Wrap-up
|
|
|
|
- [x] 7.1 Add "Resources" section to README explaining the URI scheme, listing all templates in one table, and stating the coexist-with-tools rule
|
|
- [x] 7.2 Add "Resources" subsection to AGENTS.md mirroring the README rule for AI assistants modifying the codebase
|
|
- [x] 7.3 Update CHANGELOG (or release notes file) noting the additive surface
|
|
- [x] 7.4 Verify `make build` and full test suite pass with all seven `RegisterXResources` calls wired
|
|
- [x] 7.5 File a follow-up bead to revisit `WithResourceCapabilities(subscribe=true, …)` once a real subscription use case appears (`forgejo-mcp-7ra`)
|
|
- [x] 7.6 File a follow-up bead to revisit the default embedded-list cap (currently `30`) once usage telemetry is available (`forgejo-mcp-7de`)
|