MCP 2.3.0: tea_file_edit, exact-text replacements in one file (#13) Closes #12. A commit through the MCP needs the whole file in one call, and one model answer carries about 100 KB at most; tea_file_edit reads a file at the branch, applies exact-text replacements in order (each old text exactly once in the file as it stands), commits one update with the file's sha, and answers with the new size and sha256 to check against the caller's copy. 40 tests pass from a clean checkout on hb-5. Merged on the owner's say-so in the chat. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKUMBXauq7XVN4BhTXjCSM
Teahub MCP
Teahub's MCP (Fly app green-tea-mcp, https://mcp.teahub.xyz/mcp) against the Gitea at GITEA_URL. Sign-in is Gitea's OAuth (Gitea signs people in with GitHub or nostr), and every tool acts with the caller's own Gitea token: no service token, no allowlist, nothing that outruns the caller's own permissions. Reads and writes are bounded, and no tool deletes a repository, branch, file, issue or comment.
Env: GITEA_URL, PUBLIC_URL, ALLOWED_HOSTS; secrets GITEA_OAUTH_CLIENT_ID, GITEA_OAUTH_CLIENT_SECRET (an OAuth2 application on the Gitea with redirect PUBLIC_URL/auth/callback), JWT_SIGNING_KEY. State: /data (FastMCP's OAuth store).
Tools (32), all acting as you. Their parameters are typed, so a bad argument is refused before Gitea is asked anything.
- Issues and pull requests:
tea_issues,tea_issue_get/create/edit,tea_issue_comments/comment,tea_labels,tea_label(add or remove by name),tea_pull_get(branches, mergeability, checks, diff),tea_pull_create,tea_pull_review,tea_pull_merge(keeps the head branch). - Repositories and organisations:
tea_whoami,tea_repo,tea_repo_edit(description, website, visibility, default branch, archived),tea_repo_create,tea_org_create,tea_org_repo_create,tea_org_add_member(name the team),tea_hook_create(one hook per URL). - Files:
tea_tree,tea_file_get,tea_file_change,tea_file_edit(exact-text replacements in one file, for a file too long to send whole; it answers with the new file's size and sha256),tea_commit(up to 50 files, text or base64, 3 MB in all),tea_branch_create. - Domains:
tea_domains(Cloudflare Registrar: exact names checked live, and suggestions, with prices). - Actions:
tea_actions(recent runs),tea_action_logs(a run's jobs, steps and log tails),tea_workflow_dispatch,tea_secret_set(never echoed),tea_variable_set.
tea_domains and GET /domains?q=<name or domain> (the Domains tab of Teahub's dashboard) are one search: Cloudflare Registrar's live check of the exact names and its suggestions, with prices; nothing is registered or bought. The tool is behind this server's sign-in like the others, and the tab is only on the signed-in dashboard. The address the tab calls can't see a teahub.xyz sign-in, so it is open and bounded: only GITEA_URL may read it from a browser (CORS), each client gets 8 searches a minute and everyone together 20, and answers are kept ten minutes. Both need the secrets CLOUDFLARE_API_TOKEN (Registrar read) and CLOUDFLARE_ACCOUNT_ID and say it is not set up without them.
New repositories are private unless asked otherwise, and labels must already exist. The Actions tools need Gitea 1.25 or later (prod runs 28).
Tests: from mcp/, python -m unittest discover -s tests (a fake Gitea and a fake Cloudflare; needs requirements.txt).