MCP server for Atlassian Teamwork Graph: Jira, Confluence, Jira Service Management, Assets, Goals, Projects, Teams, Loom, Trello, Rovo search, code search, people and org context, and the links between them, served from Atlassian's twg CLI to Claude (claude.ai, Claude Desktop, Claude Code, mobile) and other AI agents over the Model Context Protocol.
One standard-library Python file. It serves streamable HTTP on the loopback interface behind a bearer secret, and runs twg for each call against explicit allowlists.
Two tools. Each takes {"args": [...]}: the words that would follow twg, command first, global options (-o json, --output-summary inline, --select …) after them.
| Tool | What it runs |
|---|---|
twg_read |
Only commands on the read allowlist (313 commands): get, query, list, search and other non-mutating subcommands |
twg_write |
Only commands on the write allowlist (263 commands): create, update, delete, comment, transition, worklog, link/unlink, archive, approve, move, share, … |
Read allowlist, top-level commands: access, admin, artifacts, assets, capabilities, collaborators, commits, confluence, context, csm, deployments, docs, doctor, focus-areas, focus-areas-tree, goals, help, jira, jsm, loom, meetings, notifications, org-tree, people, pr-tree, projects, pull-requests, recently-viewed, resolve, responsibility, rovo, search-code, spaces, subgraph, talent, teams, trello, user, user-search, videos, whoami, work, work-tree, workitem-tree.
Write allowlist, top-level commands: admin, api, assets, confluence, goals, jira, jsm, loom, projects, teams, trello.
A read command sent to twg_write, a write command sent to twg_read, and anything on neither list are refused. --help works on any allowed command through the tool that would run it. The full lists are in the server's initialize instructions and in READ_COMMANDS / WRITE_COMMANDS in server.py. They were generated from twg 1.3.1's help; anything a later twg adds stays refused until it is classified.
Refused by both tools:
bitbucket/bb(use a separate Bitbucket server, such as bitbucket-mcp)login,logout,auth …,admin auth …,rovo auth,env,setup …,update/upgrade,uninstall,upkeep …,consent,skills …,cache clear,completion,doctor --fixbenchmark …,feedback,visualize- commands that move files between the server machine and Atlassian (attachment upload/download,
artifacts file create|update,loom video upload) - every option that names a local file (
--body-file,--input-file,--variables-file,--out, …). Pass content inline instead (--body,--input-json,--variables-json) apiwith an absolute URL, so the credentials never go to another host
- Linux or macOS with Python 3.8 or newer (standard library only)
- Atlassian's Teamwork Graph CLI,
twg, installed and signed in (follow Atlassian's instructions; check withtwg whoami). It is an external requirement and is not included here. - Optional:
cloudflared, to reach the server from claude.ai and mobile
git clone <this repository's URL> teamwork-graph-mcp
cd teamwork-graph-mcp
pipx install . # or: python3 -m pip install --user .
twg-mcp --check # prints the allowlist sizesAll settings are environment variables and all are optional. See config.example.env.
| Variable | Default | Meaning |
|---|---|---|
TWG_MCP_BIND |
127.0.0.1 |
Address the server listens on. Keep it on the loopback interface |
TWG_MCP_PORT |
8772 |
Port the server listens on (--port overrides it) |
TWG_MCP_SECRET_FILE |
~/.config/twg-mcp/mcp-secret |
File holding the bearer secret (mode 600) |
TWG_MCP_PUBLIC_HOSTS |
none | Comma-separated public host names that may reach the server, e.g. a tunnel hostname |
TWG_BIN |
twg on TWG_PATH |
The twg binary |
TWG_HOME |
your home folder | HOME that twg runs with |
TWG_PATH |
$TWG_HOME/.local/bin:/usr/local/bin:/usr/bin:/bin |
PATH that twg runs with |
TWG_CONFIG_DIR |
twg's default | Passed on to twg when set |
TWG_MCP_ACCOUNT_LABEL |
none | Account shown to the model ("signed in as …") |
twg-mcp --init-secret # create the bearer secret (prints its path only)
twg-mcp # serve on 127.0.0.1:8772
twg-mcp --show-header # print "Bearer …" (only when stdout is a terminal)
twg-mcp --rotate-secret # replace the secret, then restart and update clientsAs a systemd user service: copy examples/teamwork-graph-mcp.service to ~/.config/systemd/user/, set the path to twg-mcp, put your settings in ~/.config/twg-mcp/teamwork-graph-mcp.env, then:
systemctl --user daemon-reload
systemctl --user enable --now teamwork-graph-mcp
journalctl --user -u teamwork-graph-mcp -f # one line per requestThe unit runs with ProtectSystem=strict; only ~/.config/twg and ~/.cache/twg are writable, because twg refreshes its OAuth token there.
claude.ai (web, desktop and mobile): Settings → Connectors → Add custom connector. URL https://<your-public-host>/mcp, and an Authorization header with the value from twg-mcp --show-header. claude.ai needs a public HTTPS URL; see the tunnel section below.
Claude Code on the same machine:
claude mcp add --transport http twg http://127.0.0.1:8772/mcp \
--header "Authorization: Bearer $(cat ~/.config/twg-mcp/mcp-secret)"cloudflared tunnel create <TUNNEL-NAME>
cloudflared tunnel route dns <TUNNEL-NAME> <MCP-HOSTNAME>Use examples/cloudflared.yml as the tunnel config, set TWG_MCP_PUBLIC_HOSTS=<MCP-HOSTNAME>, and restart the service. The server itself still listens only on the loopback interface.
- Every request needs
Authorization: Bearer <secret>, compared in constant time. A wrong secret gets401; more than 10 failures a minute from one client get429for 60 seconds. - Requests whose
Hostis not127.0.0.1:<port>,localhost:<port>or a name inTWG_MCP_PUBLIC_HOSTSget421./.well-known/*answers404without the secret, so clients do not look for OAuth. - twg's credentials stay in twg's own config folder; the server never opens them.
- Output is scrubbed of the bearer secret and of anything shaped like a token (JWTs, Atlassian API tokens,
Bearer …) before it is returned. The log records the tool, the command path and the exit code, never arguments or output. - twg runs from an argument list (never a shell) with
TWG_AGENT_DEFAULTS=1, stdin/dev/null, a 120-second timeout (the process group is killed) and combined output capped at 200 KB. twg_readonly runs reads, so a client can auto-approve it and ask beforetwg_write.
Written by Febin Micheal Antony. Built on Atlassian's Teamwork Graph CLI (twg), which is Atlassian's software and is not included here, and the Model Context Protocol.