Implements the first two slices of the OpenSpec change mcp-resource-templates (merged via PR #148): Slice 1 — mcp-resources-core - server.WithResourceCapabilities(false, false) enabled per design.md D5 - new operation/resource/ package with: - parse.go: typed URI parsers for owner/repo/commit/issue/pr/comment/status enforcing 40-hex sha, numeric index, kind ∈ {issue, pr} - bound.go: EmbeddedListCap = 30 + generic Bounded[T] helper with sentinel - errors.go: MapForgejoError maps 403 → -32002, 404 → -32003 - register.go: thin AddTemplate wrapper over mcp.NewResourceTemplate - RegisterCoreResources stub wired from Run() Slice 2 — mcp-resource-commit - operation/repo/resources_commit.go registers template forgejo://repo/{owner}/{repo}/commit/{sha} - Handler returns application/json metadata + text/markdown sidecar (D9) - Short-sha rejected at parse layer; SDK 404 surfaces via MapForgejoError - RegisterCommitResource wired from RegisterCoreResources - README "Resources" section added with one row for commit Tests - 8 new test files across operation/resource/ and operation/repo/ - All passing under go test -count=1 ./... Tasks - 17/47 checkboxes ticked in openspec/changes/mcp-resource-templates/tasks.md (slice 1+2; 1.11 manual client check deferred) Driven by team:dev-loop. Closes the slice 1+2 portion of forgejo-mcp-13x.
41 lines
1.1 KiB
Go
41 lines
1.1 KiB
Go
package resource
|
|
|
|
import "fmt"
|
|
|
|
// EmbeddedListCap is the default maximum number of items embedded in a resource response.
|
|
const EmbeddedListCap = 30
|
|
|
|
// BoundedResult holds a capped slice of items and metadata for sentinel generation.
|
|
type BoundedResult struct {
|
|
Items []string
|
|
Total int
|
|
Cap int
|
|
ListTool string
|
|
Truncated bool
|
|
}
|
|
|
|
// Bounded returns a BoundedResult capping items at cap (use EmbeddedListCap for default).
|
|
// listTool names the tool the caller should use to fetch more items.
|
|
func Bounded(items []string, cap int, listTool string) BoundedResult {
|
|
total := len(items)
|
|
truncated := total > cap
|
|
shown := items
|
|
if truncated {
|
|
shown = items[:cap]
|
|
}
|
|
return BoundedResult{
|
|
Items: shown,
|
|
Total: total,
|
|
Cap: cap,
|
|
ListTool: listTool,
|
|
Truncated: truncated,
|
|
}
|
|
}
|
|
|
|
// Sentinel returns a truncation marker string when the list was truncated, or empty string otherwise.
|
|
func (b BoundedResult) Sentinel() string {
|
|
if !b.Truncated {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("[truncated: %d of %d items shown. Use %s tool to fetch more.]", b.Cap, b.Total, b.ListTool)
|
|
}
|