Skip to main content
Glama
README.md
# tangled-mcp

MCP server for [Tangled](https://tangled.org) - a git collaboration platform built on AT Protocol.

reads go through [bobbin](https://docs.tangled.org/bobbin.html), tangled's public XRPC API (`api.tangled.org`) — **no credentials needed**. writes (issues, comments, labels) are atproto records put directly on your PDS and require an app password.

> **note**: this repository is mirrored to [GitHub](https://github.com/zzstoatzz/tangled-mcp) for deployment via [FastMCP Cloud](https://fastmcp.cloud).

## hosted server

a hosted instance runs at **`https://nate-tangled-mcp.fastmcp.app/mcp`** — no install needed:

```bash
claude mcp add --transport http tangled https://nate-tangled-mcp.fastmcp.app/mcp
```

for write access, pass credentials per request via headers:

```bash
claude mcp add --transport http tangled https://nate-tangled-mcp.fastmcp.app/mcp \
  --header "x-tangled-handle: your.handle" \
  --header "x-tangled-password: your-app-password"
```

your PDS is auto-discovered from your handle — self-hosted PDS works with no extra config.

## installation

```bash
git clone https://tangled.org/zzstoatzz/tangled-mcp
cd tangled-mcp
just setup
```

> [!IMPORTANT]
> requires [`uv`](https://docs.astral.sh/uv/) and [`just`](https://github.com/casey/just)

## configuration

credentials are optional — only write tools need them. hosted/multi-tenant deployments can send them per request via `x-tangled-handle` / `x-tangled-password` headers, which take precedence over env. for local use, create `.env`:

```bash
TANGLED_HANDLE=your.handle
TANGLED_PASSWORD=your-app-password
```

## usage

<details>
<summary>MCP client installation instructions</summary>

### claude code

```bash
# read-only (no credentials)
claude mcp add tangled -- uvx tangled-mcp

# with write access
claude mcp add tangled \
  -e TANGLED_HANDLE=your.handle \
  -e TANGLED_PASSWORD=your-app-password \
  -- uvx tangled-mcp
```

### cursor

add to your cursor settings (`~/.cursor/mcp.json` or `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "tangled": {
      "command": "uvx",
      "args": ["tangled-mcp"],
      "env": {
        "TANGLED_HANDLE": "your.handle",
        "TANGLED_PASSWORD": "your-app-password"
      }
    }
  }
}
```

### codex cli

```bash
codex mcp add tangled \
  --env TANGLED_HANDLE=your.handle \
  --env TANGLED_PASSWORD=your-app-password \
  -- uvx tangled-mcp
```

### other clients

for clients that support MCP server configuration, use:
- **command**: `uvx`
- **args**: `["tangled-mcp"]`
- **environment variables** (optional, for writes): `TANGLED_HANDLE`, `TANGLED_PASSWORD`

</details>

### development usage

```bash
uv run tangled-mcp
```

## tools

repositories are `owner/repo` (e.g. `zzstoatzz.io/tangled-mcp`); handles (with or without `@`) and DIDs both work for the owner. issues are identified by at-uri.

### discovery (no auth)
- `search(query, limit)` - full-text search across repos, issues, and strings
- `list_repos(owner, limit)` - list a user's repositories
- `get_repo(repo)` - metadata: knot, default branch, languages, labels
- `get_record(uri)` - fetch the full record behind any at-uri (strings/pastes, comments, ...)

### git (no auth)
- `list_branches(repo, limit)` / `list_tags(repo, limit)`
- `list_files(repo, path, ref)` - browse the tree
- `read_file(repo, path, ref)` - file contents
- `commit_log(repo, ref, limit)` - recent commits
- `compare(repo, rev1, rev2)` - diff two revisions

### issues & pulls (no auth)
- `list_issues(repo, state, limit)` - filterable by open/closed
- `get_issue(issue)`
- `list_pulls(repo, status, limit)` - filterable by open/closed/merged
- `get_pull(pull)` - single PR with live state (derived from PDS status records, no index lag)
- `list_pipelines(repo, limit)` - CI pipeline runs

### writes (require credentials)
- `create_pull(repo, title, patch | edits, target_branch, body)` - open a PR from `git format-patch` output, or from whole-file `edits` (no clone needed — the server synthesizes the patch)
- `create_issue(repo, title, body, labels)`
- `update_issue(issue, title, body)`
- `set_issue_state(issue, state)` - close/reopen
- `set_pull_state(pull, state)` - close/reopen a PR
- `comment_on_issue(issue, body)`
- `delete_issue(issue)`

## development

```bash
just test   # run tests
just check  # run pre-commit checks
```

see [docs/bobbin-api.md](docs/bobbin-api.md) for notes on tangled's public API.

---

mcp-name: io.github.zzstoatzz/tangled-mcp

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct resource and action: issues (create, delete, update, list), branches (list), labels (list), and pull requests (list). No overlapping purposes.

Naming Consistency5/5

All tools follow a consistent verb_repo_noun pattern (e.g., create_repo_issue, list_repo_branches), with snake_case throughout.

Tool Count5/5

7 tools is well-scoped for a repository management server, covering core operations without being overwhelming or sparse.

Completeness3/5

Issues have full CRUD, but branches and labels only have list operations, and pull requests are limited to listing only the authenticated user's PRs. Notable gaps exist for create/update/delete on other resources.

Maintenance

ActivityMaintained
ResponsivenessNo issues