MCP server for tangled
architecture#
tangled platform overview#
tangled is a git collaboration platform built on the AT Protocol. it consists of:
components#
-
appview (tangled.org): web interface using traditional HTTP routes
- handles OAuth authentication for browser users
- serves HTML/CSS/JS for the UI
- proxies git operations to knots
- does NOT expose XRPC endpoints
-
knots (e.g., knot1.tangled.sh): git hosting servers
- expose XRPC endpoints for git operations
- host actual git repositories
- handle git-upload-pack, git-receive-pack, etc.
-
PDS (Personal Data Server): AT Protocol user data storage
- stores user's atproto records
- repos stored in
sh.tangled.repocollection - each repo record contains: name, knot, description, etc.
data flow#
- user creates repo on tangled.org
- appview writes repo record to user's PDS (
sh.tangled.repocollection) - repo record includes
knotfield indicating which knot hosts it - git operations routed through appview to the appropriate knot
MCP server implementation#
resolution flow#
when a client calls list_repo_branches("@owner/repo"):
-
normalize input: strip @ if present (
@owner→owner) -
resolve handle to DID:
- if already DID format: use as-is
- otherwise: call
com.atproto.identity.resolveHandle - result:
did:plc:...
-
query repo collection:
- call
com.atproto.repo.listRecordson owner's PDS - collection:
sh.tangled.repo(NOTsh.tangled.repo.repo) - find record where
namematches repo name
- call
-
extract knot:
- get
knotfield from repo record - example:
knot1.tangled.sh
- get
-
call knot XRPC:
- construct URL:
https://{knot}/xrpc/sh.tangled.repo.branches - params:
{"repo": "{did}/{repo_name}", "limit": N} - auth: service token from
com.atproto.server.getServiceAuth
- construct URL:
authentication#
uses AT Protocol service auth:
- authenticate to user's PDS with handle/password
- call
com.atproto.server.getServiceAuthwithaud: did:web:tangled.org - receive service token (60 second expiration)
- use token in
Authorization: Bearer {token}header for XRPC calls
key implementation details#
- collection name:
sh.tangled.repo - knot resolution: dynamic based on repo record, not hardcoded
- handle formats: both
owner/repoand@owner/repoaccepted - private implementation: resolution logic in
_tangled/package - public API: clean tool interface in
server.py
error handling#
- invalid format:
ValueErrorwith clear message - handle not found:
ValueErrorfrom identity resolution - repo not found:
ValueErrorafter querying collection - XRPC errors: raised from httpx with status code