Skip to main content
Glama
DJ-Huang
by DJ-Huang
README.md
# tuanjie-mcp

[English](README.md) | [中文](README.zh.md)

`tuanjie-mcp` is a stdio MCP server for the existing `cn.tuanjie.codely.bridge` TCP server. It runs outside Unity/Tuanjie and does not add or modify Unity package code.

The adapter supports multiple open editors. You can pin it to a process at startup, select an instance at runtime, or point it at a project/port. It does not depend on the MCP client's working directory.

## Quick setup for AI tools

Build the server once, then register the same **stdio** command in your AI client's MCP settings:

```bash
cd /path/to/tuanjie-mcp
npm install
npm run build
```

The command is always `node /absolute/path/to/tuanjie-mcp/dist/index.js`. Use an absolute path so the client can start the server from any workspace.

### Codex

Add this to `~/.codex/config.toml` (the active local configuration uses this layout):

```toml
[mcp_servers.tuanjie-mcp]
command = "node"
args = ["/absolute/path/to/tuanjie-mcp/dist/index.js"]
```

Or register the identical server from the command line:

```bash
codex mcp add tuanjie-mcp -- node /absolute/path/to/tuanjie-mcp/dist/index.js
```

### Cursor

Add this entry to `~/.cursor/mcp.json` under `mcpServers` (the local Cursor configuration uses this layout):

```json
{
  "mcpServers": {
    "tuanjie": {
      "command": "node",
      "args": ["/absolute/path/to/tuanjie-mcp/dist/index.js"],
      "cwd": "/absolute/path/to/tuanjie-mcp",
      "trust": true
    }
  }
}
```

### Other common MCP clients

Any client that supports local stdio MCP servers can use this adapter, including Claude Desktop, VS Code MCP-capable extensions, Windsurf, Cline, Roo Code, OpenCode, and similar tools. In that client's MCP settings, create a local server and supply the same values:

| Field | Value |
|---|---|
| transport | `stdio` |
| command | `node` |
| arguments | `[/absolute/path/to/tuanjie-mcp/dist/index.js]` |
| working directory | optional; `/absolute/path/to/tuanjie-mcp` is safe |

Client configuration file names and JSON/TOML schema vary, but the launch command does not. Restart or reload the client after saving its MCP settings.

## Requirements

- Node.js 20 or newer
- A Unity/Tuanjie project with `cn.tuanjie.codely.bridge` running
- `lsof` on macOS/Linux when selecting by PID (`Get-NetTCPConnection` is used on Windows)

## Install and build

```bash
cd /path/to/tuanjie-mcp
npm install
npm run build
```

## Select one editor process

Pin the server to a running Unity/Tuanjie PID:

```bash
node /path/to/tuanjie-mcp/dist/index.js --unity-pid 57250
```

Equivalent MCP client configuration:

```json
{
  "mcpServers": {
    "tuanjie": {
      "command": "node",
      "args": [
        "/path/to/tuanjie-mcp/dist/index.js",
        "--unity-pid",
        "57250"
      ]
    }
  }
}
```

The PID resolver first maps the process's listening ports and verifies the Codely `WELCOME UNITY-TCP ... FRAMING=1` handshake. `unity_ping` then calls `manage_editor/get_project_root` so a live but incorrect endpoint is not accepted as the intended project.

You can also configure a project without setting the MCP process `cwd`:

```json
{
  "mcpServers": {
    "tuanjie": {
      "command": "node",
      "args": [
        "/path/to/tuanjie-mcp/dist/index.js"
      ],
      "env": {
        "TUANJIE_UNITY_PROJECT": "/absolute/path/to/MyUnityProject"
      }
    }
  }
}
```

Startup selectors, in precedence order when supplied explicitly:

| CLI | Environment | Meaning |
|---|---|---|
| `--unity-pid 57250` | `TUANJIE_UNITY_PID=57250` | Resolve the Bridge owned by one editor process |
| `--unity-project /path/project` | `TUANJIE_UNITY_PROJECT=/path/project` | Read the project's `.com-unity-codely.json` |
| `--unity-port 50206` | `TUANJIE_UNITY_PORT=50206` | Connect directly to a Bridge port |
| `--unity-host 127.0.0.1` | `TUANJIE_UNITY_HOST=127.0.0.1` | Override the Bridge host |
| `--workspace-root /path/ws` | `TUANJIE_WORKSPACE_ROOTS` (`;`-separated; preferred) or `WORKSPACE_FOLDER_PATHS` | In auto mode, prefer editors related to this workspace |

When no selector is set, the server checks the current directory for backward compatibility, then discovers per-project status files under `~/.unity-tcp`. One reachable instance is selected automatically. If several are reachable:

1. When workspace roots are configured and exactly **one** reachable instance is related to the workspace (project inside workspace, or workspace inside project) → that instance is selected;
2. Otherwise the tool returns an explicit ambiguity error asking the agent/user to choose (`unity_select_instance`), instead of guessing.

Port `25916` remains the final compatibility fallback.

Recommended project-level `mcp.json` env:

```json
"env": {
  "TUANJIE_WORKSPACE_ROOTS": "${workspaceFolder}"
}
```

## Runtime instance selection

The MCP client can switch editors without restarting the server:

1. Call `unity_list_instances` to see project paths, ports, reachability, and PIDs when available.
2. Call `unity_select_instance` with exactly one of `pid`, `project`, or `port`.
3. Call `unity_ping` to see the selected endpoint and the project identity returned by the Bridge.

The selection persists for the lifetime of that MCP server process.

### Switching instances through conversation

The screenshot below shows a typical workflow: with multiple Unity/Tuanjie editors open, the user simply asks the model to test the connection. The model discovers all running instances, selects the one matching the current repository, and pings it to confirm — all through natural-language conversation.

![Switch project via LLM](docs/switch-project.png)

You can ask the model to switch processes for you in plain language instead of calling the tools manually. The model performs the same two steps: it first calls `unity_list_instances` (which reports each instance's `pid`, `projectRoot`, `port`, and reachability), then calls `unity_select_instance`.

For example, in the chat you can say:

> List all current Tuanjie processes, then switch to my Unity project.

or:

> Switch to the Tuanjie process with PID 57250, then read the Console.

The model calls `unity_list_instances`, identifies the target from the returned `projectRoot` / `pid`, and then calls `unity_select_instance`. After a successful switch, subsequent Unity tool calls (`unity_ping`, `read_console`, `manage_scene`, etc.) are routed to that instance until you call `unity_select_instance` again or restart the MCP server.

Example `unity_select_instance` arguments:

```json
{ "pid": 57250 }
```

Or by project path / port:

```json
{ "project": "/path/to/MyUnityProject" }
```

```json
{ "port": 50206 }
```

If your description is not enough to uniquely identify an instance — for example when two project names are similar — the model should list the candidate PIDs and project paths and ask you to confirm before switching.

## Tools

- `unity_initialize_bridge` — install the Bridge into a project that does not have it yet
- `unity_list_instances`
- `unity_select_instance`
- `unity_ping`
- `unity_bridge_call` — raw `{ type, params }` passthrough
- `read_console`
- `manage_editor`
- `manage_scene`
- `manage_gameobject`
- `execute_menu_item`
- `execute_csharp_script`

The thin wrappers only map MCP arguments to the existing Bridge command. Bridge responses are returned unchanged, including `{ success, message, data, state, ... }`. A Bridge error is marked as an MCP tool error while retaining the original JSON payload.

### Initialize a project without Bridge

Call `unity_initialize_bridge` with a Unity/Tuanjie project root. If the project already lists `cn.tuanjie.codely.bridge` in `Packages/manifest.json`, the tool is a no-op. Otherwise it starts that project in batch mode and executes `PackageManager.Client.Add("cn.tuanjie.codely.bridge")`; it then verifies the resulting manifest and removes its temporary Editor bootstrap script.

On macOS, the tool automatically matches `ProjectSettings/ProjectVersion.txt` to `/Applications/Tuanjie/Hub/Editor/<version>/Tuanjie.app/Contents/MacOS/Tuanjie`. For another installation layout or platform, pass `unity_executable` or set `TUANJIE_UNITY_EXECUTABLE`.

## Connection settings

- `TUANJIE_UNITY_TIMEOUT_MS` / `--timeout-ms`: connect and frame timeout, default `10000`
- `TUANJIE_UNITY_STATUS_DIR` / `--status-dir`: override instance status discovery
- `UNITY_TCP_STATUS_DIR`: legacy Bridge-compatible status directory override

The TCP client validates the welcome line and uses an unsigned 64-bit big-endian payload length followed by UTF-8 JSON. Connections are reused and calls are serialized. A failed connection is discarded so the next tool call can reconnect; commands are not automatically replayed because a lost response does not prove that a Unity-side write failed.

## Verify

```bash
npm test
node dist/index.js --help
```

For a live editor, start the MCP server with a PID/project selector and call `unity_ping`, followed by `read_console` with `action: "get"` and a small `count`.