Skip to main content
Glama
achieveonepark

ach-mcp

README.md
# Ach MCP

An in-editor **MCP (Model Context Protocol) server** that exposes Unity
convenience tools to AI assistants such as Claude. The server runs entirely
inside the Unity Editor in C# (no separate process, no external bridge) and
speaks MCP over HTTP.

## Tools

| Tool | What it does |
|------|--------------|
| `get_console_logs` | Read Console entries — Debug logs, warnings, errors, and script **compile errors**. Filterable by severity. Closes the "did my change work?" loop. |
| `execute_menu_item` | Run any Editor menu item by path (e.g. `GameObject/Create Empty`, `Assets/Refresh`). One tool that unlocks most built-in and custom actions. |
| `get_scene_hierarchy` | Dump the GameObject tree of the open scene(s) as JSON — names, active state, tag, layer, and component types. |
| `take_screenshot` | Render the Game or Scene view camera to a PNG and return it inline. Lets the assistant *see* the result. |

## Requirements

- Unity **2021.3+**
- `com.unity.nuget.newtonsoft-json` (declared as a package dependency, installed automatically)

## Installation

Add the package to your project's `Packages/manifest.json`:

```json
{
  "dependencies": {
    "com.achieveone.ach-mcp": "https://github.com/achieveonepark/ach-mcp.git"
  }
}
```

Or use **Window ▸ Package Manager ▸ + ▸ Add package from git URL** and paste the
repository URL.

## Usage

1. Open **Tools ▸ Ach MCP ▸ Control Panel**.
2. Set a **Port** (default `8790`) and click **Start**. Enable **Auto-start on
   load** to have it come up with the editor.
3. In the **AI Client Setup** section, click **Configure** next to a client (or
   **Configure Detected** to do all installed ones at once). Restart the client.

Once connected, ask the assistant to call the tools, e.g. *"check the Unity
console for errors"*, *"show me the scene hierarchy"*, or *"take a screenshot of
the game view."*

## One-click client setup

The control panel writes this server into each client's config file, resolving
the correct location for **macOS / Windows / Linux** automatically. Existing
configs are merged (your other servers are preserved) and backed up once as
`*.ach-mcp.bak` before the first change.

| Client | Transport | Config file |
|--------|-----------|-------------|
| Claude Code | HTTP (native) | `~/.claude.json` |
| Claude Desktop | stdio via `mcp-remote` | macOS `~/Library/Application Support/Claude/…` · Windows `%APPDATA%\Claude\…` · Linux `~/.config/Claude/…` |
| Codex CLI | stdio via `mcp-remote` | `~/.codex/config.toml` |
| Cursor | HTTP (native) | `~/.cursor/mcp.json` |
| Windsurf | HTTP (native) | `~/.codeium/windsurf/mcp_config.json` |

Clients that don't support HTTP MCP directly are bridged through
[`mcp-remote`](https://www.npmjs.com/package/mcp-remote), invoked as
`npx -y mcp-remote <url>`. Those rows are marked *"mcp-remote"* and require
**Node.js (npx)** on your PATH.

### Manual configuration

If you'd rather edit config by hand, the server is a standard Streamable-HTTP
MCP endpoint:

```
http://127.0.0.1:8790/mcp
```

Native-HTTP client (Claude Code, Cursor, …):

```json
{ "mcpServers": { "ach-unity": { "type": "http", "url": "http://127.0.0.1:8790/mcp" } } }
```

stdio-only client (Claude Desktop, Codex):

```json
{ "mcpServers": { "ach-unity": { "command": "npx", "args": ["-y", "mcp-remote", "http://127.0.0.1:8790/mcp"] } } }
```

## How it works

- **Transport** — a loopback `HttpListener` (`127.0.0.1`, so no admin/urlacl is
  needed) accepts JSON-RPC 2.0 POSTs at `/mcp` and returns a single JSON
  response (Streamable HTTP).
- **Threading** — HTTP requests are served on background threads; every tool
  marshals its Unity API calls onto the main thread via `MainThreadDispatcher`.
- **Lifecycle** — `McpServerManager` stops the listener before every domain
  reload and on editor quit, so the port is always released.

## Adding your own tool

1. Implement `IMcpTool` in `Editor/Tools/`.
2. Declare `Name`, `Description`, and an `InputSchema` (JSON Schema).
3. Register it in `ToolRegistry`'s static constructor.

```csharp
internal sealed class MyTool : IMcpTool
{
    public string Name => "my_tool";
    public string Description => "What it does.";
    public JObject InputSchema => new JObject { ["type"] = "object" };

    public ToolResult Execute(JObject arguments)
    {
        var value = MainThreadDispatcher.Run(() => /* Unity API here */ 42);
        return ToolResult.Ok("Result: " + value);
    }
}
```