list_repo_branches
Retrieve and display branch information for a specified repository, allowing users to view available branches with configurable limits for efficient repository exploration.
Instructions
list branches for a repository
Args: repo: repository identifier in 'owner/repo' format (e.g., 'zzstoatzz/tangled-mcp') limit: maximum number of branches to return (1-100)
Returns: list of branches
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | repository identifier in 'owner/repo' format (e.g., 'zzstoatzz/tangled-mcp') | |
| limit | No | maximum number of branches to return |
Implementation Reference
- src/tangled_mcp/server.py:45-71 (handler)Handler function for the 'list_repo_branches' tool. Includes input schema via Annotated/Field, calls helpers, and returns typed result. Also serves as registration via @tangled_mcp.tool decorator.@tangled_mcp.tool def list_repo_branches( repo: Annotated[ str, Field( description="repository identifier in 'owner/repo' format (e.g., 'zzstoatzz/tangled-mcp')" ), ], limit: Annotated[ int, Field(ge=1, le=100, description="maximum number of branches to return") ] = 50, ) -> ListBranchesResult: """list branches for a repository Args: repo: repository identifier in 'owner/repo' format (e.g., 'zzstoatzz/tangled-mcp') limit: maximum number of branches to return (1-100) Returns: list of branches """ # resolve owner/repo to (knot, did/repo) knot, repo_id = _tangled.resolve_repo_identifier(repo) response = _tangled.list_branches(knot, repo_id, limit, cursor=None) return ListBranchesResult.from_api_response(response)
- Pydantic models defining the output schema: BranchInfo and ListBranchesResult, including a classmethod to parse from raw tangled API response.class BranchInfo(BaseModel): """branch information""" name: str sha: str class ListBranchesResult(BaseModel): """result of listing branches""" branches: list[BranchInfo] @classmethod def from_api_response(cls, response: dict[str, Any]) -> "ListBranchesResult": """construct from raw API response Args: response: raw response from tangled API with structure: { "branches": [ {"reference": {"name": "main", "hash": "abc123"}}, ... ] } Returns: ListBranchesResult with parsed branches """ branches = [] if "branches" in response: for branch_data in response["branches"]: ref = branch_data.get("reference", {}) branches.append( BranchInfo( name=ref.get("name", ""), sha=ref.get("hash", ""), ) ) return cls(branches=branches)
- Core helper function that performs the actual API call to tangled's knot via XRPC to list repository branches.def list_branches( knot: str, repo: str, limit: int = 50, cursor: str | None = None ) -> dict[str, Any]: """list branches for a repository Args: knot: knot hostname (e.g., 'knot1.tangled.sh') repo: repository identifier in "did/repo" format (e.g., 'did:plc:.../repoName') limit: maximum number of branches to return cursor: pagination cursor Returns: dict containing branches and optional cursor """ params = {"repo": repo, "limit": limit} if cursor: params["cursor"] = cursor return make_tangled_request("sh.tangled.repo.branches", params, knot=knot)
- Helper function to resolve user-friendly 'owner/repo' identifier to the (knot, did/repo) format required for tangled XRPC calls.def resolve_repo_identifier(owner_slash_repo: str) -> tuple[str, str]: """resolve owner/repo format to (knot, did/repo) for tangled XRPC Args: owner_slash_repo: repository identifier in "owner/repo" or "@owner/repo" format (e.g., "zzstoatzz.io/tangled-mcp" or "@zzstoatzz.io/tangled-mcp") Returns: tuple of (knot_url, repo_identifier) where: - knot_url: hostname of knot hosting the repo (e.g., "knot1.tangled.sh") - repo_identifier: "did/repo" format (e.g., "did:plc:.../tangled-mcp") Raises: ValueError: if format is invalid, handle cannot be resolved, or repo not found """ if "/" not in owner_slash_repo: raise ValueError( f"invalid repo format: '{owner_slash_repo}'. expected 'owner/repo'" ) owner, repo_name = owner_slash_repo.split("/", 1) client = _get_authenticated_client() # resolve owner (handle or DID) to DID if owner.startswith("did:"): owner_did = owner else: # strip @ prefix if present owner = owner.lstrip("@") # resolve handle to DID try: response = client.com.atproto.identity.resolve_handle( params={"handle": owner} ) owner_did = response.did except Exception as e: raise ValueError(f"failed to resolve handle '{owner}': {e}") from e # query owner's repo collection to find repo and get knot try: records = client.com.atproto.repo.list_records( models.ComAtprotoRepoListRecords.Params( repo=owner_did, collection="sh.tangled.repo", # correct collection name limit=100, ) ) except Exception as e: raise ValueError(f"failed to list repos for '{owner}': {e}") from e # find repo with matching name and extract knot for record in records.records: if (name := getattr(record.value, "name", None)) and name == repo_name: knot = getattr(record.value, "knot", None) if not knot: raise ValueError(f"repo '{repo_name}' has no knot information") return (knot, f"{owner_did}/{repo_name}") raise ValueError(f"repo '{repo_name}' not found for owner '{owner}'")