Skip to main content
ClaudeWave
Skill29.8k estrellas del repoactualizado yesterday

add-ollama-tool

This skill integrates a local Ollama MCP server into a container agent, enabling Claude to call locally-hosted language models and optionally manage the model library through standardized tools. Use it when you need the agent to offload inference tasks to Ollama models running on the host machine, keeping processing local and avoiding external API calls or credentials while maintaining Claude as the orchestration layer.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/nanocoai/nanoclaw /tmp/add-ollama-tool && cp -r /tmp/add-ollama-tool/.claude/skills/add-ollama-tool ~/.claude/skills/add-ollama-tool
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Add Ollama Integration

This skill adds a stdio-based MCP server that exposes local [Ollama](https://ollama.com) models as tools for the container agent. Claude remains the orchestrator but can offload work to local models served by the Ollama daemon on the host, and can optionally manage the model library directly. Ollama runs locally and is keyless — there are no credentials to thread; the only configuration is the daemon's base URL.

Core tools (always available):
- `ollama_list_models` — list installed models with name, size, and family (`GET /api/tags`)
- `ollama_generate` — send a prompt to a specified model and return the response (`POST /api/generate`)

Management tools (opt-in via `OLLAMA_ADMIN_TOOLS=true`):
- `ollama_pull_model` — pull (download) a model from the Ollama registry (`POST /api/pull`)
- `ollama_delete_model` — delete a locally installed model to free disk space (`DELETE /api/delete`)
- `ollama_show_model` — show model details: modelfile, parameters, and architecture info (`POST /api/show`)
- `ollama_list_running` — list models currently loaded in memory with memory usage and processor type (`GET /api/ps`)

The skill ships the MCP server source (and its tests) in this folder and copies them into the agent-runner tree at install time, then registers the server in `index.ts` and forwards host env vars in `container-runner.ts`. Registering the server is enough to expose its tools — the agent's allow-pattern (`mcp__ollama__*`) is derived from the registered server name.

## Phase 1: Pre-flight

### Check if already applied

Check if `container/agent-runner/src/ollama-mcp-stdio.ts` exists. If it does, skip to Phase 3 (Configure).

### Check prerequisites

Verify Ollama is installed and its daemon is reachable. On the host:

```bash
curl -s http://127.0.0.1:11434/api/tags | head
```

If the request fails:

1. Install Ollama from https://ollama.com/download.
2. Start it (the desktop app runs the daemon, or run `ollama serve`).
3. Confirm the daemon answers: `curl -s http://127.0.0.1:11434/api/tags`.

If no models are installed, suggest pulling one:

> You need at least one model. For example:
>
> ```bash
> ollama pull gemma3:1b        # Small, fast (~1GB)
> ollama pull llama3.2         # Good general purpose (~2GB)
> ollama pull qwen3-coder:30b  # Best for code tasks (~18GB)
> ```

## Phase 2: Apply Code Changes

### Copy the skill's source and tests into both trees

This skill reaches into both the container (Bun) tree and the host (Node) tree, so its
files go into both, alongside the integration points they cover.

```bash
S=.claude/skills/add-ollama-tool
# Container (Bun) tree — the MCP server and the registration wiring test
cp $S/ollama-mcp-stdio.ts       container/agent-runner/src/ollama-mcp-stdio.ts
cp $S/ollama-registration.test.ts container/agent-runner/src/ollama-registration.test.ts
# Host (Node) tree — the env-forwarding helper and the wiring test
cp $S/ollama-env.ts             src/ollama-env.ts
cp $S/ollama-wiring.test.ts     src/ollama-wiring.test.ts
```

### Register the MCP server in the agent-runner

Edit `container/agent-runner/src/index.ts`. Find the `mcpServers` object that currently looks like this:

```ts
  const mcpServers: Record<string, { command: string; args: string[]; env: Record<string, string> }> = {
    nanoclaw: {
      command: 'bun',
      args: ['run', mcpServerPath],
      env: {},
    },
  };
```

Add an `ollama` entry alongside `nanoclaw`:

```ts
  const mcpServers: Record<string, { command: string; args: string[]; env: Record<string, string> }> = {
    nanoclaw: {
      command: 'bun',
      args: ['run', mcpServerPath],
      env: {},
    },
    ollama: {
      command: 'bun',
      args: ['run', path.join(__dirname, 'ollama-mcp-stdio.ts')],
      env: {
        ...(process.env.OLLAMA_HOST ? { OLLAMA_HOST: process.env.OLLAMA_HOST } : {}),
        ...(process.env.OLLAMA_ADMIN_TOOLS ? { OLLAMA_ADMIN_TOOLS: process.env.OLLAMA_ADMIN_TOOLS } : {}),
      },
    },
  };
```

`ollama-registration.test.ts` asserts this entry is present and points at the server module — the tool only appears to the agent if it is registered here.

### Forward host env vars into the container

The container receives `TZ` and OneCLI networking vars by default; any other host env
var the MCP subprocess needs must be forwarded explicitly. The forwarding logic lives in
the copied `src/ollama-env.ts` (`ollamaEnvArgs()`) — `OLLAMA_HOST` (the daemon base URL)
and `OLLAMA_ADMIN_TOOLS` (the library-management opt-in flag). Both are configuration, not
credentials, so they are passed through plainly; Ollama itself is local and keyless.

Import it in `src/container-runner.ts` (alongside the other local imports):

```ts
import { ollamaEnvArgs } from './ollama-env.js';
```

Then, in `buildContainerArgs`, find the `TZ` env line and add the call right after it:

```ts
  args.push('-e', `TZ=${TIMEZONE}`);
  args.push(...ollamaEnvArgs());
```

`ollama-wiring.test.ts` asserts this `args.push(...ollamaEnvArgs())` call exists inside `buildContainerArgs`.

### Surface `[OLLAMA]` log lines at info level

> **Shared block.** This rewrites the `container.stderr` logger, which other local-model tools (e.g. `add-atomic-chat-tool` for `[ATOMIC]`) also edit to surface their own prefix. Touch only the `[OLLAMA]` branch and leave the rest of the block intact, so the edits coexist and removal restores it cleanly.

In the same file, find the stderr logger:

```ts
  container.stderr?.on('data', (data) => {
    for (const line of data.toString().trim().split('\n')) {
      if (line) log.debug(line, { container: agentGroup.folder });
    }
  });
```

Replace it with:

```ts
  container.stderr?.on('data', (data) => {
    for (const line of data.toString().trim().split('\n')) {
      if (!line) continue;
      if (line.includes('[OLLAMA]')) {
        log.info(line, { container: agentGroup.folder });
      } else {
        log.debug(line, { container: agentGroup.folder });
      }
    }
  });
`