feat(github): add github_get_content and github_resolve_ref read-by-ref tools (#193)#195
Conversation
…ef tools (#193) Two lightweight read-only tools so common lookups no longer require cloning a whole repository: - github_get_content: wraps GET /repos/{owner}/{repo}/contents/{path}?ref= and returns the base64-decoded file text plus blob sha and size. Lists entries for a directory path; reports too-large files (>1MB, which the contents API omits) with a pointer to the blobs API. - github_resolve_ref: wraps GET /repos/{owner}/{repo}/commits/{ref} to resolve a branch, tag (including annotated), or short SHA to its full commit SHA (plus author/date/subject). Both reuse github_client_context and work on private repos with the server's existing GITHUB_TOKEN. This removes the previous workaround of cloning a 71k-file repo just to read one file or resolve a tag, and makes the MCP a complete substitute for the `gh api contents`/`commits` calls the routing policy blocks. New module github/contents.py; models GitHubGetContent/GitHubResolveRef; registered as core tools in the lean interface (re-exported via api.py). README tool counts updated to 64 (27 git, 34 GitHub, 3 Azure), which also reconciles a pre-existing 63-vs-62 doc inconsistency. Adds 7 tests (decoded file, 404, directory listing, too-large; ref resolution success, 404, 422). Full github unit suite passes. Closes #193 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @MementoRC's task —— View job PR Review
Overall this is a clean, well-scoped addition. The implementation is idiomatic for this codebase. A few things worth addressing: Bugs / Correctness
endpoint = f"/repos/{repo_owner}/{repo_name}/contents/{path.lstrip('/')}"
if ref:
endpoint += f"?ref={ref}"
params = {"ref": ref} if ref else {}
response = await client.get(endpoint, params=params)(The Same issue in endpoint = f"/repos/{repo_owner}/{repo_name}/commits/{ref}"Here
Missing test coverageNo mock_context.return_value.__aenter__.return_value = mock_clientbut never configure mock_context.return_value.__aexit__ = AsyncMock(return_value=False)No test for non-200/non-404 error path ( No test for unexpected encoding ( No test for Minor / style
__all__ = ["github_get_content", "github_resolve_ref"]
SummaryThe core logic is correct and the happy-path tests are solid. The two issues most worth fixing before merge are:
|
|
Claude finished @MementoRC's task —— View job PR Review
Overall this is a clean, well-scoped addition that follows the codebase's conventions. The previous automated review already captured the main issues — here's a focused assessment of what still matters and what's fine. Bugs / Security Issues1. URL injection via unencoded
|
Summary
Closes #193. Adds two lightweight, read-only GitHub tools so two very common lookups no longer require cloning an entire repository.
New tools
github_get_content— wrapsGET /repos/{owner}/{repo}/contents/{path}?ref={ref}. Returns the base64-decoded file text plus blobshaandsize. Lists entries for a directory path; reports too-large files (>1MB, which the contents API omits) with a pointer to the blobs API.refis optional (defaults to the repo's default branch).github_resolve_ref— wrapsGET /repos/{owner}/{repo}/commits/{ref}to resolve a branch, tag (including annotated tags), or short SHA to its full commit SHA (plus author/date/subject).Both reuse
github_client_contextand work on private repos with the server's existingGITHUB_TOKEN.Motivation (from the issue)
Resolving
tag v2.9.6 → commit SHAand reading one workflow file from a private repo previously forced a fullgit_cloneof a 71,000-file repo into scratchpad, thengit_show+ localRead— a heavyweight workaround for two one-line lookups. These tools also make the MCP a complete substitute for thegh api contents/commitscalls the routing policy intentionally blocks.Wiring
github/contents.py; modelsGitHubGetContent/GitHubResolveRef; registered as core tools in the lean interface and re-exported viaapi.py.Tests
Adds 7 tests (decoded file, 404, directory listing, too-large; ref resolution success, 404, 422). Full github unit suite passes.
Closes #193
🤖 Generated with Claude Code