Feature request: list_repo_contents and get_repo_tree MCP tools #115

Closed
opened 2026-05-05 12:32:25 +00:00 by BrilliantKahn · 1 comment
BrilliantKahn commented 2026-05-05 12:32:25 +00:00 (Migrated from codeberg.org)

Problem

The operation/repo/ domain exposes tools for file CRUD, branch management, and commit listing, but there is no way to discover what files or directories exist in a repository. Two complementary tools would close this gap:

  1. list_repo_contents — list directory entries at a given path using the SDK's ListContents method (/repos/{owner}/{repo}/contents/{path})
  2. get_repo_tree — retrieve a full Git tree for a ref using the SDK's GetTrees method (/repos/{owner}/{repo}/git/trees/{ref})

Without these, an MCP client that wants to navigate a repository must call get_file_content with guessed paths, which is awkward in an agentic context.

Proposed tools

Tool 1: list_repo_contents

  • WHEN list_repo_contents is called with owner, repo, ref, and path (empty string for root)
    → THEN returns the array of ContentsResponse entries at that path (name, path, type file/dir/symlink/submodule, sha, size)

Tool 2: get_repo_tree

  • WHEN get_repo_tree is called with owner, repo, ref, and recursive=false (default)
    → THEN returns a GitTreeResponse with the top-level entries for that ref

  • WHEN get_repo_tree is called with recursive=true
    → THEN returns a GitTreeResponse with all entries in the full tree

Both tools follow the existing registration pattern (mcp.NewTool + mcp.WithString/mcp.WithNumber/mcp.WithBoolean, handler returns to.TextResult(result)).

Breaking change note

None. This is a pure addition — two new tools, no changes to existing tools or handlers.

Open design point: pagination in list_repo_contents

The current SDK signature is:

func (c *Client) ListContents(owner, repo, ref, filepath string) ([]*ContentsResponse, *Response, error)

It accepts no pagination options. The proposed implementation includes page and limit parameters in the tool definition for consistency with other list-tools (list_branches, list_repo_commits, etc.), but does not forward them to the SDK call.

Two acceptable resolutions — happy to defer to your preference:

(a) Accept the inconsistency and document it: keep page/limit in the tool definition as a forward-compatible placeholder until the SDK supports pagination on this endpoint.

(b) Drop page/limit from the tool definition entirely: lean interface, no phantom parameters, revisit when the SDK adds support.

get_repo_tree does not have this issue — GetTreesOptions already embeds ListOptions{Page, PageSize}.

Working implementation

A working implementation is available at BrilliantKahn/forgejo-mcp, branch feat/repo-tree-listing.

Changes are confined to three files:

  • operation/repo/contents.go (new) — both tool definitions and handlers
  • operation/repo/repo.go — registration of both tools
  • operation/repo/contents_test.go (new) — white-box httptest-mock tests for both success paths

The branch is based on upstream main HEAD 25ecabdd (v2.19.0, 2026-05-02). make build and go test ./... pass.

This is a request for feedback on the approach and the pagination design point above — not a PR announcement. I want to confirm the parameter shape and your preference on option (a) vs (b) before opening a PR.

SDK rationale

  • list_repo_contents uses ListContents rather than GetContents because the tool's purpose is directory listing; GetContents returns a single ContentsResponse and errors on directories.
  • get_repo_tree uses GetTrees (SDK method) directly. Two tools rather than one with a recursive flag: the two SDK methods return structurally different types ([]*ContentsResponse vs *GitTreeResponse), and merging them would require transformation logic that conflicts with the 1-to-1 SDK-wrapping pattern the repo uses.
## Problem The `operation/repo/` domain exposes tools for file CRUD, branch management, and commit listing, but there is no way to discover what files or directories exist in a repository. Two complementary tools would close this gap: 1. **`list_repo_contents`** — list directory entries at a given path using the SDK's `ListContents` method (`/repos/{owner}/{repo}/contents/{path}`) 2. **`get_repo_tree`** — retrieve a full Git tree for a ref using the SDK's `GetTrees` method (`/repos/{owner}/{repo}/git/trees/{ref}`) Without these, an MCP client that wants to navigate a repository must call `get_file_content` with guessed paths, which is awkward in an agentic context. ## Proposed tools **Tool 1: `list_repo_contents`** - WHEN `list_repo_contents` is called with `owner`, `repo`, `ref`, and `path` (empty string for root) → THEN returns the array of `ContentsResponse` entries at that path (name, path, type `file`/`dir`/`symlink`/`submodule`, sha, size) **Tool 2: `get_repo_tree`** - WHEN `get_repo_tree` is called with `owner`, `repo`, `ref`, and `recursive=false` (default) → THEN returns a `GitTreeResponse` with the top-level entries for that ref - WHEN `get_repo_tree` is called with `recursive=true` → THEN returns a `GitTreeResponse` with all entries in the full tree Both tools follow the existing registration pattern (`mcp.NewTool` + `mcp.WithString`/`mcp.WithNumber`/`mcp.WithBoolean`, handler returns `to.TextResult(result)`). ## Breaking change note None. This is a pure addition — two new tools, no changes to existing tools or handlers. ## Open design point: pagination in `list_repo_contents` The current SDK signature is: ```go func (c *Client) ListContents(owner, repo, ref, filepath string) ([]*ContentsResponse, *Response, error) ``` It accepts no pagination options. The proposed implementation includes `page` and `limit` parameters in the tool definition for consistency with other list-tools (`list_branches`, `list_repo_commits`, etc.), but does not forward them to the SDK call. Two acceptable resolutions — happy to defer to your preference: **(a)** Accept the inconsistency and document it: keep `page`/`limit` in the tool definition as a forward-compatible placeholder until the SDK supports pagination on this endpoint. **(b)** Drop `page`/`limit` from the tool definition entirely: lean interface, no phantom parameters, revisit when the SDK adds support. `get_repo_tree` does not have this issue — `GetTreesOptions` already embeds `ListOptions{Page, PageSize}`. ## Working implementation A working implementation is available at [`BrilliantKahn/forgejo-mcp`](https://codeberg.org/BrilliantKahn/forgejo-mcp/src/branch/feat/repo-tree-listing), branch `feat/repo-tree-listing`. Changes are confined to three files: - `operation/repo/contents.go` (new) — both tool definitions and handlers - `operation/repo/repo.go` — registration of both tools - `operation/repo/contents_test.go` (new) — white-box `httptest`-mock tests for both success paths The branch is based on upstream main HEAD `25ecabdd` (v2.19.0, 2026-05-02). `make build` and `go test ./...` pass. This is a request for feedback on the approach and the pagination design point above — not a PR announcement. I want to confirm the parameter shape and your preference on option (a) vs (b) before opening a PR. ## SDK rationale - `list_repo_contents` uses `ListContents` rather than `GetContents` because the tool's purpose is directory listing; `GetContents` returns a single `ContentsResponse` and errors on directories. - `get_repo_tree` uses `GetTrees` (SDK method) directly. Two tools rather than one with a `recursive` flag: the two SDK methods return structurally different types (`[]*ContentsResponse` vs `*GitTreeResponse`), and merging them would require transformation logic that conflicts with the 1-to-1 SDK-wrapping pattern the repo uses.
goern commented 2026-05-05 15:37:47 +00:00 (Migrated from codeberg.org)

Thanks again — and again, the production-tested branch up front makes this easy.

Two tools rather than one with a recursive flag is the right call. Different SDK return types, different shapes, no value in pretending otherwise. Matches the 1-to-1 wrapping we have everywhere else.

On the pagination question: option (b). Drop page/limit from list_repo_contents until the SDK actually supports them. Every other paginated tool in operation/repo/ (list_branches, list_repo_commits, list_my_repos) wires those params straight into a real ListOptions{Page, PageSize}. Phantom params would break that contract and lie to the MCP schema — caller sees page=2 accepted, gets page 1 back, no error. That's a worse failure mode than not having pagination at all. When the SDK adds support, we add the params then. No forward-compat placeholder.

get_repo_tree keeps page/limit since GetTreesOptions actually plumbs them through. Good.

No breaking change, pure addition — minor bump, v2.20.0 (or rolled into the same release as #114, depending on which lands first).

Open the PR against main. feat: commit, squash. Tool descriptions should be precise about what path="" means for list_repo_contents (root) and what recursive does on get_repo_tree, so the LLM picks the right one without trial and error.

Thanks again — and again, the production-tested branch up front makes this easy. Two tools rather than one with a `recursive` flag is the right call. Different SDK return types, different shapes, no value in pretending otherwise. Matches the 1-to-1 wrapping we have everywhere else. On the pagination question: option (b). Drop `page`/`limit` from `list_repo_contents` until the SDK actually supports them. Every other paginated tool in `operation/repo/` (`list_branches`, `list_repo_commits`, `list_my_repos`) wires those params straight into a real `ListOptions{Page, PageSize}`. Phantom params would break that contract and lie to the MCP schema — caller sees `page=2` accepted, gets page 1 back, no error. That's a worse failure mode than not having pagination at all. When the SDK adds support, we add the params then. No forward-compat placeholder. `get_repo_tree` keeps `page`/`limit` since `GetTreesOptions` actually plumbs them through. Good. No breaking change, pure addition — minor bump, v2.20.0 (or rolled into the same release as #114, depending on which lands first). Open the PR against `main`. `feat:` commit, squash. Tool descriptions should be precise about what `path=""` means for `list_repo_contents` (root) and what `recursive` does on `get_repo_tree`, so the LLM picks the right one without trial and error.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
agentic-forges/forgejo-mcp#115
No description provided.