Skip to main content
Glama

t3-code-agent-mcp

A small, local MCP server that lets a coding agent (Claude Code, Codex CLI, Cursor, or any MCP client) start and drive threads in your running T3 Code app.

Use it when an agent in one thread needs to kick off more work: "open a Codex thread on this repo with gpt-5.6-sol and ask it to fix the flaky test", then read the reply, send follow-ups, or cancel.

  • Talks to T3 the same way the T3 web app does: T3's own HTTP + WebSocket interfaces, T3's own pairing tokens. T3 handles each harness's protocol.

  • Threads show up in the normal T3 UI, with a link back to them.

  • Never opens or writes T3's database.

  • Runs over stdio on your machine. No cloud, no extra ports.

Contents

Related MCP server: t3code-mcp

Tools

Tool

What it does

t3_list_projects

Projects the T3 server knows, with ids and workspace roots

t3_list_worktrees

Git worktrees and local branches of one project

t3_list_harnesses

Harnesses (Codex, Claude, Cursor, Grok, OpenCode, …) and the models each offers, with a usable flag and reason

t3_list_threads

Recent threads, newest first, optionally per project

t3_create_thread

Create a thread with an explicit project + worktree + harness + model and send the first prompt

t3_send_message

Send a follow-up prompt to an existing thread

t3_get_thread

Status, latest turn state, and recent messages including the assistant reply

t3_wait_for_turn

Block until the current turn finishes, then return the reply

t3_cancel_turn

Interrupt the running turn

Guarantees

  • No silent substitution. If the harness or model you name is unknown, disabled, not installed, or signed out, the call fails and lists the valid options. Same for projects and worktrees.

  • No duplicate launches. Pass an idempotencyKey and retries reuse the same thread (or the same turn). Command ids are derived from the key, and T3 dedupes on command id, so even a retry after a crash cannot launch twice. If T3 rejected a command, that key is burned: fix the cause and call again with a new key. The error text says so.

  • Loud on drift. The few response fields the wait loop relies on are checked at runtime. If a T3 upgrade renames them, tools fail with a clear message instead of reporting "done".

Requirements

  • Node.js 20 or newer.

  • A running T3 Code server on the same machine: the desktop app, or npx t3.

  • A pairing link from that T3 (Settings → Connections).

Install

git clone https://github.com/gfsaaser24/t3-code-agent-mcp
cd t3-code-agent-mcp
npm install
npm run build

The server entry point is dist/cli.js.

Pair with T3

One-time step. T3 issues short-lived pairing codes; this server exchanges one for a 30-day bearer token and stores it locally.

  1. In T3 open Settings → Connections and create a pairing link. (CLI users: t3 pair.)

  2. Copy the pairing URL or the short code.

  3. Run one of:

node dist/cli.js pair "http://127.0.0.1:3773/pair#token=XXXXXXXX"
node dist/cli.js pair XXXXXXXX

The token is stored in ~/.t3-code-agent-mcp/credentials.json. Check everything is wired:

node dist/cli.js status
# Server: http://127.0.0.1:3773 (v0.0.52, …) via …/server-runtime.json
# Token: ok (…/credentials.json)
# Projects: 12, threads: 80, harnesses: codex, claudeAgent, cursor, …

When the token expires, run pair again. You can revoke it any time in T3 → Settings → Connections.

Headless alternative: set T3_ACCESS_TOKEN to a token from t3 auth session issue --token-only.

Configure your MCP client

Replace /path/to/t3-code-agent-mcp with where you cloned it. Ready-made files are in examples/.

Claude Code

claude mcp add --scope user t3 -- node /path/to/t3-code-agent-mcp/dist/cli.js

or in .mcp.json / ~/.claude.json:

{
  "mcpServers": {
    "t3": { "command": "node", "args": ["/path/to/t3-code-agent-mcp/dist/cli.js"] }
  }
}

Codex CLI (~/.codex/config.toml)

[mcp_servers.t3]
command = "node"
args = ["/path/to/t3-code-agent-mcp/dist/cli.js"]

Cursor (.cursor/mcp.json)

{
  "mcpServers": {
    "t3": { "command": "node", "args": ["/path/to/t3-code-agent-mcp/dist/cli.js"] }
  }
}

Any other MCP client

Command node, argument /path/to/t3-code-agent-mcp/dist/cli.js, transport stdio. Optional environment variables are listed below.

Typical agent flow

t3_list_projects                       → pick a project id
t3_list_worktrees  {project}           → pick a worktreePath (or use the project root)
t3_list_harnesses                      → pick harnessId + model slug
t3_create_thread   {project, worktreePath, harness, model, title, prompt,
                    idempotencyKey, wait: true}      → reply text + thread url
t3_send_message    {threadId, prompt, wait: true}  → next reply
t3_get_thread      {threadId}                      → status + recent messages
t3_cancel_turn     {threadId}                      → stop a running turn

Every thread result includes url, which opens the thread in the T3 web UI, and turn.state (running, completed, interrupted, error).

Tool reference

t3_list_projects

No input. Returns [{ id, title, workspaceRoot, defaultModelSelection }].

t3_list_worktrees

Input

Notes

project

Project id, exact title, or workspace root path

Returns the project root (always a valid worktreePath), every other worktree with its branch, and the local branch list.

t3_list_harnesses

Input

Notes

includeUnusable

Also list harnesses that cannot start threads, with a reason

Returns [{ harnessId, driver, displayName, usable, reason, status, auth, version, models: [{ model, name, aliases, isDefault, isLegacy }] }]. T3 calls harnesses "providers"; harnessId is the provider instance id (claudeAgent, codex, cursor, …).

t3_list_threads

Input

Notes

project

Optional filter

includeArchived

Default false

limit

Default 25, max 200

t3_create_thread

Input

Notes

project

Project id, exact title, or workspace root

harness

Harness id exactly as listed

model

Model slug or alias exactly as listed for that harness

title

Thread title shown in T3

prompt

First user message

context

Optional [{ label?, text }] blocks appended below the prompt

worktreePath

Existing worktree from t3_list_worktrees, or the project root (default)

newWorktree

{ baseBranch, branch?, runSetupScript? }: ask T3 to create a fresh worktree. Mutually exclusive with worktreePath

runtimeMode

approval-required, auto-accept-edits, auto, full-access (default)

interactionMode

default or plan

idempotencyKey

Stable key; retries reuse the same thread

wait

Wait for the first turn and return the reply (default false)

timeoutSeconds

Max wait, default 300

Returns the thread summary plus reused (true when the key matched an existing thread) and, with wait, reply and timedOut.

t3_send_message

Input

Notes

threadId

prompt

context

Optional blocks as above

runtimeMode, interactionMode

Default: the thread's current modes

idempotencyKey

Stable key; retries do not start a second turn

wait, timeoutSeconds

As above

Refuses if a different turn is still running so an in-flight turn is never clobbered. A retry with the same key is always safe.

t3_get_thread

Input

Notes

threadId

messageLimit

Default 10, max 200

maxChars

Truncate each message, default 20000

t3_wait_for_turn

Input

Notes

threadId

timeoutSeconds

Default 300

Prefer wait: true on t3_create_thread / t3_send_message, which know exactly which turn to wait for.

t3_cancel_turn

Input

Notes

threadId

Returns cancelled: false with a reason when nothing is running.

Environment variables

Put these under env in your MCP client config when needed.

Variable

Meaning

T3_SERVER_URL

Skip discovery and use this origin, e.g. http://127.0.0.1:3773

T3CODE_HOME

T3 data directory to search for server-runtime.json. Default: ~/.t3

T3_ACCESS_TOKEN

Bearer token to use instead of the stored one

T3_MCP_CREDENTIALS

Path of the credentials file. Default ~/.t3-code-agent-mcp/credentials.json

CLI commands: serve (default), pair <url-or-code>, status, help.

How it works

  • Discovery. Reads <T3 home>/userdata/server-runtime.json (then dev/), checks the pid is alive, and probes /.well-known/t3/environment for the environment id and version.

  • Auth. Bearer token from T3's pairing flow (POST /oauth/token token exchange), sent as an Authorization header on HTTP and on the WebSocket upgrade.

  • Reads. GET /api/orchestration/shell (projects + thread list) and GET /api/orchestration/threads/:id (thread detail, windowed by turn).

  • Commands. orchestration.dispatchCommand over T3's WebSocket RPC with T3's typed commands: thread.turn.start with bootstrap.createThread (and optional prepareWorktree), and thread.turn.interrupt. The socket handler is the one that expands bootstrap and returns typed errors. Thread, command, and message ids are SHA-256 of your idempotencyKey.

  • RPC client. server.getConfig (harnesses + models) and vcs.listRefs (worktrees) are socket-only in T3, so a small client speaks the Effect RPC JSON envelope: Request, Chunk + Ack back-pressure, Exit, Ping/Pong, Interrupt. Failures are scoped to the socket that carried the request.

  • Waiting. One thread subscription stays open for the whole wait. On session/settle events the HTTP snapshot is re-read a few times (it lags the event by a tick). After a dispatch the wait only accepts the turn that carries your own message id, so a retry or a lagging projection cannot return the previous turn.

Compatibility

Wired against upstream pingdotgg/t3code main at 8419238 (server 0.0.40, 2026-09-14). Every touch point was checked against that source:

Touch point

Upstream

Pairing exchange

POST /oauth/token, grant urn:ietf:params:oauth:grant-type:token-exchange, subject type urn:t3:params:oauth:token-type:environment-bootstrap

Pairing link

<origin>/pair#token=<code> (t3 pair, t3 auth pairing create, Settings → Connections); hosted form …/pair?host=<origin>#token=<code>

Socket auth

Authorization: Bearer on the /ws upgrade (server falls back to it when no wsTicket is present)

Discovery

$T3CODE_HOME or ~/.t3, then userdata/ or dev/ server-runtime.json (pid, origin, devUrl), default port 3773, GET /.well-known/t3/environment

Reads

GET /api/orchestration/shell, GET /api/orchestration/threads/:threadId?turnLimit=

Commands

RPC orchestration.dispatchCommand: thread.turn.start (+ bootstrap.createThread / prepareWorktree), thread.turn.interrupt

Config + git

RPC server.getConfig, vcs.listRefs (limit ≤ 200, cursor paging)

Waiting

RPC orchestration.subscribeThread with afterSequence + turnLimit

Scopes

orchestration:read for reads and config, orchestration:operate for dispatch (both in T3's standard client scopes)

Thread link

Web route /$environmentId/$threadId

Forks that keep these surfaces work unchanged; a fork that moves its data directory only needs T3CODE_HOME.

Troubleshooting

Symptom

Fix

No running T3 server found

Start T3 Code, or set T3_SERVER_URL. If your T3 data lives elsewhere, set T3CODE_HOME

No T3 token for … / rejected the stored token (401)

Create a pairing link in T3 → Settings → Connections and run node dist/cli.js pair …

harness "…" is not usable right now

Install, enable, or sign in to that harness inside T3; check t3_list_harnesses {includeUnusable: true} for the reason

model "…" is not offered by harness "…"

Use a slug or alias from t3_list_harnesses; nothing is substituted on purpose

already has a running turn

Wait with t3_wait_for_turn or stop it with t3_cancel_turn

This idempotencyKey was rejected before

The command failed once and T3 remembers it; fix the cause and use a new key

T3 thread snapshot is missing …

Your T3 is newer than this server's contract mirror; update t3-code-agent-mcp

Development

npm test                 # unit tests against a fake WebSocket server; no T3 needed
npm run typecheck
npm run build

Live smoke test (creates one real thread in your T3, visible in the UI):

npx tsx test/smoke.live.mts <projectIdOrRoot> [harness] [model]

Layout:

src/cli.ts          entry point: serve | pair | status
src/discovery.ts    find the running T3 server
src/credentials.ts  pairing exchange + token store
src/http.ts         HTTP snapshot reads
src/rpc.ts          WebSocket RPC client (Effect RPC envelope)
src/t3.ts           typed T3 API + wait loop
src/resolve.ts      strict project / harness / model / worktree lookup
src/ids.ts          idempotency-key → deterministic ids
src/tools.ts        MCP tool definitions
src/types.ts        wire shapes mirrored from T3's contracts

Security

  • The stored token carries T3's standard client scopes (orchestration:read/operate, terminal:operate, review:write, relay:read). Revoke it in T3 → Settings → Connections.

  • The credentials file is written with mode 0600 where the OS supports it. Treat it like a password.

  • Anything reachable through your T3 (its projects, its harness credentials) is reachable through this server. Only expose it to MCP clients you trust.

  • The server never opens or writes T3's SQLite database.

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables MCP clients to spawn and control Codex CLI and Claude Code sessions on the host machine, with session management and filesystem access.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude Code to delegate coding implementation and testing to a local pi agent via MCP tools, including dispatching task books, monitoring status, steering or aborting runs mid-execution, and retrieving results and transcripts.
    26 npm
    2
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables agent managers to launch and supervise Antigravity CLI, Claude Code, CodeBuddy Code, or Grok CLI as subagents through local MCP tools for starting, waiting on, and cancelling invocations.
    4
    MIT