ddx-term-mcp

ddx-term-mcp

Enables AI agents to execute commands in a shared tmux session that is simultaneously visible to a human via a web-based terminal UI.

Category
Visit Server

README

dudoxx-ai-terminal

Shared multi-terminal bridge — one tmux session, many addressable terminals, attached by a human (web / xterm.js) and an AI agent (MCP) simultaneously, both looking at the exact same terminals. Architecture in one line: a single pinned-size tmux session is the shared state; a NestJS broker owns the canonical terminal registry and fans output to the web UI per-terminal over WebSocket; an MCP server lets Claude shell out to the same tmux session (it holds no PTY); a Next.js web app renders the terminals with xterm.js.

Packages

Package Role Port / transport
@ddx/term-contract (packages/ddx-term-contract) Shared zod types — WS frames, MCP tool I/O, terminal/session descriptors library (ESM+CJS+types)
ddx-term-broker Human channel + canonical state: tmux control-mode attach, registry, REST CRUD, per-terminalId WS HTTP/WS 13330 (DDX_TERM_BROKER_PORT)
@dudoxx/ddx-term-mcp Agent channel: MCP stdio server, thin tmux client (no PTY) stdio (node dist/server.js)
ddx-term-web Next.js 16 xterm.js UI, one tab per terminalId HTTP 13340 (DDX_TERM_WEB_PORT)

Ports default to the high 133XX band on purpose — clear of 3000/5173/8080 so the bridge never collides with your own running codebases. Override via env or a .env file (see Configuration).

ddx-cli-py / ddx-cli-ts are interactive e2e-target fixtures, not workspace packages — they are never built or published from here.

Bring-up

The normal path is agent-driven — you do not start a dev server by hand. Build once, register the MCP (below), then call any term_* verb: the MCP server's supervisor spawns the broker (13330) and web (13340) automatically and attaches to them.

pnpm install
pnpm build                                   # builds all packages incl. ddx-term-mcp/dist/server.js
# or just the MCP server + its contract dep:
pnpm --filter @dudoxx/ddx-term-mcp... build

Then open the web UI at http://localhost:13340 to watch the same terminals the agent drives. Lock files at ~/.ddx-term/{broker,web}.lock make the stack a machine-wide singleton; set DDX_TERM_WEB=0 to run broker-only (headless).

Hacking on the broker/web themselves? pnpm dev still runs both concurrently via turbo (broker 13330 + web 13340) for a live edit loop — but it is no longer required for normal agent use. See SETUP.md.

Register the MCP server (agent channel)

Add this to a Claude Code project's .mcp.json (or your Claude Desktop config). A copy lives in .mcp.json.example — replace /abs/path with this repo's absolute path:

{
  "mcpServers": {
    "ddx-term": {
      "command": "node",
      "args": ["/abs/path/dudoxx-ai-terminal/ddx-term-mcp/dist/server.js"],
      "env": {
        "DDX_TERM_SOCKET": "/tmp/ddx-term.sock",
        "DDX_TERM_SESSION": "ddx-shared",
        "DDX_TERM_DEFAULT": "t01",
        "DDX_TERM_BROKER_PORT": "13330",
        "DDX_TERM_WEB_PORT": "13340"
      }
    }
  }
}
Env Default Purpose
DDX_TERM_SOCKET /tmp/ddx-term.sock tmux -S socket of the shared session
DDX_TERM_SESSION ddx-shared session hosting all terminals (windows)
DDX_TERM_DEFAULT t01 terminalId used when a verb omits terminalId
DDX_TERM_BROKER_PORT 13330 broker HTTP/WS port
DDX_TERM_WEB_PORT 13340 web UI HTTP port
DDX_TERM_HOST 127.0.0.1 bind/connect host (loopback by design)
DDX_TERM_WEB (unset → web on) set 0 to run broker-only (no web spawn)

The env: block is the per-client override layer — it wins over .env files. The full table (read caps, allow-list, supervisor-written URLs) is in DEPENDENCIES.md.

Global install (every Claude Code session)

The package is bin-shaped (ddx-term-mcpdist/server.js) with a prepare script that builds on install. To register it for all projects, add it to your user-scope MCP config via the CLI (run from this repo so $PWD resolves):

pnpm -F @dudoxx/ddx-term-mcp build      # produces an executable dist/server.js
claude mcp add ddx-term --scope user \
  --env DDX_TERM_SOCKET=/tmp/ddx-term.sock \
  --env DDX_TERM_SESSION=ddx-shared \
  --env DDX_TERM_DEFAULT=t01 \
  --env DDX_TERM_BROKER_PORT=13330 \
  --env DDX_TERM_WEB_PORT=13340 \
  -- node "$PWD/ddx-term-mcp/dist/server.js"

Verify with claude mcp list (look for ddx-term … ✔ Connected).

Configuration

Every setting has a built-in code default and three override layers — highest wins, and override: false means an explicitly-set var always beats a file:

  1. The MCP client env: block (.mcp.json / claude mcp add --env) — per agent / per client.
  2. A project-local .env in the current working directory.
  3. A global ~/.ddx-term/.env — applies to every client on the machine.

Copy .env.example to .env (project) or ~/.ddx-term/.env (global) and edit. The MCP server loads both files (src/load-dotenv.ts) before resolving ports; the broker and web load them too for the standalone pnpm dev path. Example — move the whole stack onto a different band:

# ~/.ddx-term/.env
DDX_TERM_BROKER_PORT=14330
DDX_TERM_WEB_PORT=14340

.env is gitignored; .env.example is the committed template.

Publishing is wired — @dudoxx/ddx-term-mcp ships as a self-contained npm package. Its publish bundle (build:bundle, tsup) inlines @ddx/term-contract from source into a single dist/server.js (noExternal: ['@ddx/term-contract']), keeping only zod + @modelcontextprotocol/sdk as external runtime deps. That bundle is wired as prepublishOnly, so the published tarball carries no workspace:* reference — the contract stays "private": true and is never published separately (by design; it lives in the changeset ignore[]). Once a version is released to the registry (see Release & versioning below), the npx -y @dudoxx/ddx-term-mcp form resolves. Until the first registry release, register by absolute path as above.

The MCP server is a thin tmux client — it never owns a PTY (no node-pty); it shells out to tmux against the same session the broker and the human are attached to. That shared-state property is the whole point: a command the agent types is visible live in the web UI.

Attach natively from a real terminal emulator (human channel, no browser)

Because the bridge IS a standard tmux session, you can also attach with a native tmux control-mode client — iTerm2 and WezTerm render tmux -CC natively:

tmux -CC attach -t ddx-shared

This opens the shared terminals as native tabs/windows in iTerm2 / WezTerm, alongside the web UI and the agent — all three see the same terminals.

Verification

pnpm typecheck      # turbo run typecheck across all packages
pnpm lint
pnpm test           # turbo run test (unit + e2e; e2e spins throwaway tmux on a temp socket)

Release & versioning (Changesets → npm)

Only @dudoxx/ddx-term-mcp publishes to public npm; broker, web, and the contract are "private": true and listed in .changeset/config.json ignore[].

pnpm changeset      # 1. describe the change + pick a bump (patch/minor/major)
git commit && push  # 2. open a PR that includes the .changeset/*.md

On merge to main, .github/workflows/release.yml runs Changesets' action:

  1. It opens (or updates) a "Version Packages" PR that bumps package.json, writes CHANGELOG.md, and consumes the changeset files.
  2. Merging that PR triggers pnpm releasebuild:bundle (tsup, inlines the contract) → changeset publishnpm publish of any package whose version changed.

The publish authenticates via the repo secret NPM_TOKEN (an npm automation token with publish rights to the @dudoxx scope) and emits provenance (NPM_CONFIG_PROVENANCE=true). After the first release lands, the npx -y @dudoxx/ddx-term-mcp registration form resolves.

Verify a tarball before publishing: cd ddx-term-mcp && pnpm build:bundle && npm pack --dry-run — it must list dist/server.js (self-contained, no workspace:*), package.json, README.md, INSTALLATION.md, LICENSE, and the two assets/*.png.

For the full release walkthrough, bump-type guidance, and CI details see CLAUDE_PUBLISHING.md and ddx-documentation/05-publishing/release-flow.md.


Dudoxx UG / Acceleate Consulting - Walid Boudabbous walid@acceleate.com

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured