{"slug":"add-atomic-chat-tool","title":"add-atomic-chat-tool","summary":"Add Atomic Chat MCP server so the container agent can call local models served by the Atomic Chat desktop app via its OpenAI-compatible API.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-24T05:37:14.699053Z","repo":{"url":"https://github.com/nanocoai/nanoclaw","stars":30867,"forks":12793,"license":"MIT","updatedAt":"2026-10-01T15:15:04Z"},"bodyHtml":"<hr>\n<h2>name: add-atomic-chat-tool\ndescription: Add Atomic Chat MCP server so the container agent can call local models served by the Atomic Chat desktop app via its OpenAI-compatible API.</h2>\n<h1>Add Atomic Chat Integration</h1>\n<p>This skill adds a stdio-based MCP server that exposes models running in the local <a href=\"https://github.com/AtomicBot-ai/Atomic-Chat\">Atomic Chat</a> desktop app as tools for the container agent. Claude remains the orchestrator but can offload work to local models served by Atomic Chat on <code>http://127.0.0.1:1337/v1</code> (OpenAI-compatible).</p>\n<p>Tools exposed:</p>\n<ul>\n<li><code>atomic_chat_list_models</code> — list models currently available in Atomic Chat (<code>GET /v1/models</code>)</li>\n<li><code>atomic_chat_generate</code> — send a prompt to a specified model and return the response (<code>POST /v1/chat/completions</code>)</li>\n</ul>\n<p>Model management (download, delete) is done through the <strong>Atomic Chat desktop UI</strong> — the app is a fork of Jan and manages its own model library.</p>\n<p>The skill ships the MCP server source (and its test) in this folder and copies them into the agent-runner tree at install time, then registers the server in <code>index.ts</code> and forwards host env vars in <code>container-runner.ts</code>. Registering the server is enough to expose its tools — the agent's allow-pattern (<code>mcp__atomic_chat__*</code>) is derived from the registered server name.</p>\n<h2>Phase 1: Pre-flight</h2>\n<h3>Check if already applied</h3>\n<p>Check if <code>container/agent-runner/src/atomic-chat-mcp-stdio.ts</code> exists. If it does, skip to Phase 3 (Configure).</p>\n<h3>Check prerequisites</h3>\n<p>Verify Atomic Chat is installed and its local API server is running. On the host:</p>\n<pre><code>curl -s http://127.0.0.1:1337/v1/models | head\n</code></pre>\n<p>If the request fails:</p>\n<ol>\n<li>Install Atomic Chat from the <a href=\"https://github.com/AtomicBot-ai/Atomic-Chat/releases\">latest release</a> (macOS only for now — <code>atomic-chat.dmg</code>).</li>\n<li>Open the app.</li>\n<li>Open <strong>Settings → Local API Server</strong> and make sure it's enabled on port <code>1337</code>.</li>\n<li>Go to the <strong>Hub</strong> (or <strong>Models</strong>) tab and download at least one model (e.g. Llama 3.2 3B, Qwen 2.5 Coder 7B).</li>\n<li>Load the model once by sending any message in Atomic Chat's UI to warm it up.</li>\n</ol>\n<h2>Phase 2: Apply Code Changes</h2>\n<h3>Copy the skill's source and tests into both trees</h3>\n<p>This skill reaches into both the container (Bun) tree and the host (Node) tree, so its\nfiles go into both, alongside the integration points they cover.</p>\n<pre><code>S=.claude/skills/add-atomic-chat-tool\n# Container (Bun) tree — the MCP server and the registration wiring test\ncp $S/atomic-chat-mcp-stdio.ts        container/agent-runner/src/atomic-chat-mcp-stdio.ts\ncp $S/atomic-chat-registration.test.ts container/agent-runner/src/atomic-chat-registration.test.ts\n# Host (Node) tree — the env-forwarding helper and the wiring test\ncp $S/atomic-chat-env.ts              src/atomic-chat-env.ts\ncp $S/atomic-chat-wiring.test.ts      src/atomic-chat-wiring.test.ts\n</code></pre>\n<h3>Register the MCP server in the agent-runner</h3>\n<p>Edit <code>container/agent-runner/src/index.ts</code>. Find the <code>mcpServers</code> object that currently looks like this:</p>\n<pre><code>  const mcpServers: Record&lt;string, { command: string; args: string[]; env: Record&lt;string, string&gt; }&gt; = {\n    nanoclaw: {\n      command: 'bun',\n      args: ['run', mcpServerPath],\n      env: {},\n    },\n  };\n</code></pre>\n<p>Add an <code>atomic_chat</code> entry alongside <code>nanoclaw</code>:</p>\n<pre><code>  const mcpServers: Record&lt;string, { command: string; args: string[]; env: Record&lt;string, string&gt; }&gt; = {\n    nanoclaw: {\n      command: 'bun',\n      args: ['run', mcpServerPath],\n      env: {},\n    },\n    atomic_chat: {\n      command: 'bun',\n      args: ['run', path.join(__dirname, 'atomic-chat-mcp-stdio.ts')],\n      env: {\n        ...(process.env.ATOMIC_CHAT_HOST ? { ATOMIC_CHAT_HOST: process.env.ATOMIC_CHAT_HOST } : {}),\n        ...(process.env.ATOMIC_CHAT_API_KEY ? { ATOMIC_CHAT_API_KEY: process.env.ATOMIC_CHAT_API_KEY } : {}),\n      },\n    },\n  };\n</code></pre>\n<p><code>atomic-chat-registration.test.ts</code> asserts this entry is present and points at the server module — the tool only appears to the agent if it is registered here.</p>\n<h3>Forward host env vars into the container</h3>\n<p>The env-forwarding logic lives in the copied <code>src/atomic-chat-env.ts</code> (<code>atomicChatEnv()</code>), so the reach-in into <code>composeSessionSpec</code> is a single spread.</p>\n<p>Import it in <code>src/container-runner.ts</code> (alongside the other local imports):</p>\n<pre><code>import { atomicChatEnv } from './atomic-chat-env.js';\n</code></pre>\n<p>Then, in <code>composeSessionSpec</code>, find the <code>contributedEnv</code> literal and spread the helper at the end. The contributed lane — not the composed <code>env</code> literal — because <code>ATOMIC_CHAT_API_KEY</code> is credential-NAMED and the composed lane's key-name check would refuse the spawn; the contributed lane exempts the name and still refuses credential-shaped values:</p>\n<pre><code>  const contributedEnv: Record&lt;string, string&gt; = {\n    ...(contribution.env ?? {}),\n    ...(gateway.env ?? {}),\n    ...atomicChatEnv(),\n  };\n</code></pre>\n<p><code>atomic-chat-wiring.test.ts</code> asserts this <code>...atomicChatEnv()</code> spread exists inside <code>composeSessionSpec</code>.</p>\n<h3>Surface <code>[ATOMIC]</code> log lines at info level</h3>\n<blockquote>\n<p><strong>Shared block.</strong> This rewrites the driver's container-stderr logger, which other local-model tools (e.g. <code>add-ollama-tool</code> for <code>[OLLAMA]</code>) also edit to surface their own prefix. Touch only the <code>[ATOMIC]</code> branch and leave the rest of the block intact, so the edits coexist and removal restores it cleanly.</p>\n</blockquote>\n<p>Container stderr now lands in the Docker driver: in <code>src/drivers/docker-driver.ts</code>, inside <code>DockerHandle.start()</code>, find the stderr handler:</p>\n<pre><code>    proc.onStderr((line) =&gt; {\n      log.debug(line, { container: this.name });\n      this.#stderrTail.push(line);\n      if (this.#stderrTail.length &gt; 10) this.#stderrTail.shift();\n    });\n</code></pre>\n<p>Replace the <code>log.debug</code> line with a prefix branch (leave the stderr-tail lines intact — they feed the non-zero-exit warning):</p>\n<pre><code>    proc.onStderr((line) =&gt; {\n      if (line.includes('[ATOMIC]')) {\n        log.info(line, { container: this.name });\n      } else {\n        log.debug(line, { container: this.name });\n      }\n      this.#stderrTail.push(line);\n      if (this.#stderrTail.length &gt; 10) this.#stderrTail.shift();\n    });\n</code></pre>\n<h3>Add env-var stubs to <code>.env.example</code></h3>\n<p>Append to <code>.env.example</code>:</p>\n<pre><code># Atomic Chat MCP tool (.claude/skills/add-atomic-chat-tool)\n# Override the host where Atomic Chat exposes its OpenAI-compatible API.\n# Default: http://host.docker.internal:1337 (with fallback to localhost)\n# ATOMIC_CHAT_HOST=http://host.docker.internal:1337\n\n# Optional API key. Leave unset for a local Atomic Chat install — it does not require auth.\n# ATOMIC_CHAT_API_KEY=\n</code></pre>\n<h3>Validate code changes</h3>\n<pre><code>pnpm run build\npnpm exec tsc -p container/agent-runner/tsconfig.json --noEmit\n# Host tree: composeSessionSpec wiring\npnpm exec vitest run src/atomic-chat-wiring.test.ts\n# Container tree: index.ts registration\n(cd container/agent-runner &amp;&amp; bun test src/atomic-chat-registration.test.ts)\n./container/build.sh\n</code></pre>\n<p>All must be clean before proceeding. The wiring and registration tests confirm the two\nintegration points — the <code>composeSessionSpec</code> spread and the <code>index.ts</code> registration — are\nactually in place; a failure means one drifted. (The MCP server's own request/response\nbehavior against Atomic Chat is the author's build-time concern, not part of these tests —\nverify it manually in Phase 4.)</p>\n<h2>Phase 3: Configure</h2>\n<h3>Set Atomic Chat host (optional)</h3>\n<p>By default, the MCP server connects to <code>http://host.docker.internal:1337</code> (Docker Desktop) with a fallback to <code>localhost</code>. To use a custom host, add to <code>.env</code>:</p>\n<pre><code>ATOMIC_CHAT_HOST=http://your-atomic-chat-host:1337\n</code></pre>\n<h3>Set API key (optional)</h3>\n<p>Atomic Chat does <strong>not require authentication</strong> when running locally — leave this unset. Only set it if you've put Atomic Chat behind a reverse proxy that enforces auth:</p>\n<pre><code>ATOMIC_CHAT_API_KEY=sk-...\n</code></pre>\n<h3>Restart the service</h3>\n<p>Run from your NanoClaw project root:</p>\n<pre><code>source setup/lib/install-slug.sh\nlaunchctl kickstart -k gui/$(id -u)/$(launchd_label)  # macOS\n# Linux: systemctl --user restart $(systemd_unit)\n</code></pre>\n<h2>Phase 4: Verify</h2>\n<h3>Test inference</h3>\n<p>Tell the user:</p>\n<blockquote>\n<p>Send a message like: \"use atomic chat to tell me the capital of France\"</p>\n<p>The agent should use <code>atomic_chat_list_models</code> to find available models, then <code>atomic_chat_generate</code> to get a response.</p>\n</blockquote>\n<h3>Check logs if needed</h3>\n<pre><code>tail -f logs/nanoclaw.log | grep -i atomic\n</code></pre>\n<p>Look for:</p>\n<ul>\n<li><code>[ATOMIC] Listing models...</code> — list request started</li>\n<li><code>[ATOMIC] Found N models</code> — models discovered</li>\n<li><code>[ATOMIC] &gt;&gt;&gt; Generating with &lt;model&gt;</code> — generation started</li>\n<li><code>[ATOMIC] &lt;&lt;&lt; Done: &lt;model&gt; | Xs | N tokens | M chars</code> — generation completed</li>\n</ul>\n<h2>Troubleshooting</h2>\n<h3>Agent says \"Atomic Chat is not installed\" or tries to run a CLI</h3>\n<p>The agent is looking for a CLI that doesn't exist instead of using the MCP tools. This means:</p>\n<ol>\n<li>The MCP server wasn't copied — check <code>container/agent-runner/src/atomic-chat-mcp-stdio.ts</code> exists</li>\n<li>The MCP server wasn't registered — check <code>container/agent-runner/src/index.ts</code> has the <code>atomic_chat</code> entry in <code>mcpServers</code> (the allow-pattern is derived from this, so registration is the only thing to check)</li>\n<li>The container wasn't rebuilt — run <code>./container/build.sh</code></li>\n</ol>\n<h3>\"Failed to connect to Atomic Chat\"</h3>\n<ol>\n<li>Verify the host API is reachable: <code>curl http://127.0.0.1:1337/v1/models</code></li>\n<li>Confirm the Local API Server is enabled in Atomic Chat's settings</li>\n<li>Check Docker can reach the host: <code>docker run --rm curlimages/curl curl -s http://host.docker.internal:1337/v1/models</code></li>\n<li>If using a custom host, check <code>ATOMIC_CHAT_HOST</code> in <code>.env</code></li>\n</ol>\n<h3><code>model not found</code> / 404 on generate</h3>\n<p>The model ID passed to <code>atomic_chat_generate</code> must exactly match one of the IDs returned by <code>atomic_chat_list_models</code>. Ask the agent to list models first, then pick one from that list.</p>\n<h3>Slow first response</h3>\n<p>Atomic Chat lazy-loads models into memory on first use. The initial call may take longer while the model warms up. Subsequent calls against the same model are fast.</p>\n<h3>Agent doesn't use Atomic Chat tools</h3>\n<p>The agent may not know about the tools. Try being explicit: \"use the atomic_chat_generate tool with llama3.2-3b-instruct to answer: ...\"</p>\n<h3>Context window or output size issues</h3>\n<p>Atomic Chat respects each model's native context length. If you hit limits, pass <code>max_tokens</code> explicitly when calling <code>atomic_chat_generate</code>, or switch to a model with a larger context window in the Atomic Chat UI.</p>\n","files":[{"path":"atomic-chat-env.ts","sizeBytes":1037,"isText":true},{"path":"atomic-chat-mcp-stdio.ts","sizeBytes":7011,"isText":true},{"path":"atomic-chat-registration.test.ts","sizeBytes":2328,"isText":true},{"path":"atomic-chat-wiring.test.ts","sizeBytes":2173,"isText":true},{"path":"REMOVE.md","sizeBytes":1597,"isText":true},{"path":"SKILL.md","sizeBytes":10442,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"human-reviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"human-reviewed","screen":{"ran":true,"outcome":"flagged-cleared-by-moderator","suspicious":3,"notes":8,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-24T05:38:32.795431Z","sha256":"778286ACCC703342B1CDE4580345430C1BDE8F77E506ED412AAD527301A1DF8B","sizeBytes":10392},"review":null,"source":{"repositoryUrl":"https://github.com/nanocoai/nanoclaw","path":".claude/skills/add-atomic-chat-tool","license":"MIT","commit":"962d527cf20f82d84372ea8cd6ab30e9acbeb868","subtreeSha":"A87B45D599B65A1590C73968EC358304967353D7A2A0B2CDED13F5F87D32CC46","lastSyncedAt":"2026-10-01T15:23:47.22384Z"},"reviewedAt":"2026-08-25T15:12:15.24486Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-atomic-chat-tool"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install nanocoai-nanoclaw@llmmart"},{"target":"git","command":"git clone https://github.com/nanocoai/nanoclaw.git"}]}