# Local Swarm Mcp

> MCP server that delegates mechanical tasks to local OpenAI-compatible inference backends (llama.cpp, Ollama, etc.) and provides context-management tools (compaction, scratch store, token estimation).

- **Type:** MCP server
- **Install:** `agentstack add mcp-jhonsferg-local-swarm-mcp`
- **Verified:** Pending review
- **Seller:** [jhonsferg](https://agentstack.voostack.com/s/jhonsferg)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [jhonsferg](https://github.com/jhonsferg)
- **Source:** https://github.com/jhonsferg/local-swarm-mcp

## Install

```sh
agentstack add mcp-jhonsferg-local-swarm-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 🐝 local-swarm-mcp

  
  
  
  
  

  
  
  
  

  
  
  

An MCP server that delegates mechanical, low-judgment tasks to local or
remote OpenAI-compatible inference backends (llama.cpp's `llama-server`,
Ollama, vLLM, or any hosted provider exposing the same API shape), and gives
an MCP client full control over that delegated work: fire-and-forget
background tasks, multi-turn sessions, a persistent scratch store, and
context-budgeting helpers - the same primitives an agent orchestration
system offers for its own subagents, backed by a model running on your own
hardware. 🖥️⚡

## 🧠 Why

Judgment-heavy work (architecture decisions, deciding whether a finding is a
false positive, writing meaningful tests) needs a strong model. Mechanical
work (boilerplate generation, log summarization, formatting, repetitive
transforms) doesn't. This server lets an MCP client offload the latter to
whatever hardware you already have running a local model, keeping its own
token budget for the former - and treat that offloaded work like its own
background agents rather than a single blocking request/response call. 💸

## 🗺️ Architecture

```mermaid
flowchart LR
    subgraph Client["🤖 MCP Client"]
        A["AI Agent(e.g. Claude Code)"]
    end

    subgraph Server["🐝 local-swarm-mcp"]
        direction TB
        B["MCP Tools(stdio / HTTP)"]
        C["Backend Registry"]
        D["Task Registry(async + agent loop)"]
        E["Session Registry(multi-turn)"]
        F["Scratch Store(bbolt)"]
        M["Downstream MCPclient manager"]
        B --> C
        B --> D
        B --> E
        B --> F
        D --> M
    end

    subgraph Backends["⚙️ Inference Backends"]
        G["llama.cppllama-server"]
        H["Ollama"]
        I["vLLM /remote provider"]
    end

    subgraph Downstream["🧩 Downstream MCP servers"]
        J["codebase-memory-mcp"]
        K["...other configured servers"]
    end

    A |"MCP protocol"| B
    C -->|"OpenAI-compatible API"| G
    C -->|"OpenAI-compatible API"| H
    C -->|"OpenAI-compatible API"| I
    M |"stdio MCP client"| J
    M |"stdio MCP client"| K
```

Every backend just speaks the OpenAI `/v1/chat/completions` + `/v1/models`
shape, so the server never hardcodes vLLM/llama.cpp/Ollama-specific logic.
Adding a new provider is a config-file edit, not a code change. The downstream
MCP client manager lets a `spawn_agent_task` agent call other MCP servers'
tools autonomously, in a loop, the same way a host application calls its
own tools - see [Tool-using agents](#-tool-using-agents-autonomous-like-a-host-applications-own-agents).

## 🤝 Expected client behavior: check availability, then prefer this over native agents

This server is meant to sit alongside, not replace, an MCP client's own
native agent/subagent capability.

```mermaid
sequenceDiagram
    participant Agent as 🤖 AI Agent
    participant MCP as 🐝 local-swarm-mcp
    participant LLM as 🧩 Local Model

    Agent->>MCP: health_check()
    alt backend healthy
        Agent->>MCP: classify_task_risk(description)
        MCP-->>Agent: risk = low
        Agent->>MCP: spawn_task(prompt)
        MCP-->>Agent: task_id
        MCP->>LLM: POST /v1/chat/completions
        LLM-->>MCP: completion
        Agent->>MCP: wait_task(task_id)
        MCP-->>Agent: result ✅
    else backend unreachable
        Agent->>Agent: fall back to native agent 🔁
    end
```

1. **At the start of a task that could be delegated**, call `list_backends`
   and/or `health_check` to confirm at least one backend is actually
   reachable right now - a configured backend whose `llama-server`/Ollama
   process isn't running, or a remote HTTP transport instance that's
   offline, should not silently block work.
2. **If a backend is healthy**, prefer `spawn_task`/`create_session`
   over the client's own native subagent mechanism for mechanical,
   low-judgment work (use `classify_task_risk` first if unsure whether a
   task qualifies) - this is what actually saves tokens/cost, since the
   work runs on hardware you already own instead of the client's own paid
   model.
3. **If no backend is healthy**, fall back to the client's native agents
   for that work rather than failing the task - this server is a
   cost-saving optimization, not a hard dependency.

Nothing in the server enforces this - it's a client-side policy this
project is designed to support. See a specific client's own configuration
(rules file, memory, system prompt, etc.) for how it's told to apply it.

## ⚙️ Prerequisites

**1. An OpenAI-compatible inference backend, running somewhere reachable.**
local-swarm-mcp does not embed or bundle an inference engine itself - it's a
thin client in front of one. Pick whichever fits your hardware; both were
verified end-to-end against this server during development.

### 🦙 Ollama (easiest - recommended if you just want something working)

Ollama bundles model management and an OpenAI-compatible API, and
auto-detects your GPU backend (CUDA/ROCm/Metal/CPU) with no manual backend
selection.

**Windows:**
```powershell
winget install --id Ollama.Ollama -e
```
**macOS:** download from [ollama.com/download](https://ollama.com/download),
or `brew install ollama`.
**Linux:**
```bash
curl -fsSL https://ollama.com/install.sh | sh
```

Then pull a small model and start serving (Ollama also auto-starts as a
background service on Windows/macOS after install - `ollama serve` is only
needed if it isn't already running):
```
ollama pull qwen2.5-coder:1.5b   # ~1GB, comfortable on 4-6GB VRAM laptops
ollama serve                      # if not already running as a service
```
Verify it's up:
```
curl http://localhost:11434/v1/models
```
Ollama's OpenAI-compatible endpoint is `http://localhost:11434/v1`.

### 🔧 llama.cpp (better for mixed NVIDIA/AMD hardware)

More manual, but its Vulkan backend runs on both NVIDIA and AMD GPUs without
depending on ROCm's maturity - useful if you have, say, an NVIDIA laptop and
an AMD desktop and want one build that works on both.

```
# build from source (https://github.com/ggml-org/llama.cpp), or grab a
# release binary for your platform, then:
llama-server -m /path/to/model.gguf --host 0.0.0.0 --port 8080
```
Its OpenAI-compatible endpoint is `http://:8080/v1`.

### 🌐 Anything else

**vLLM**, or any hosted provider with an OpenAI-compatible
`/v1/chat/completions` endpoint, also work - just point a backend entry
at it.

**2. local-swarm-mcp itself** - either grab a release binary or build from
source. See [Installing](#-installing) below.

## 📦 Installing

### Linux / macOS

```sh
curl -fsSL https://raw.githubusercontent.com/jhonsferg/local-swarm-mcp/main/install/install.sh | sh
```

### Windows

```powershell
irm https://raw.githubusercontent.com/jhonsferg/local-swarm-mcp/main/install/install.ps1 | iex
```

Both scripts detect your OS/arch, download the matching release archive
and its `checksums.txt`, verify the SHA-256 checksum, and install
`local-swarm-mcp` (`.exe` on Windows) to `~/.local/bin` (Linux/macOS) or
`%USERPROFILE%\.local\bin` (Windows). Set `LSM_INSTALL_DIR`/`LSM_VERSION`
(`$env:LSM_INSTALL_DIR`/`$env:LSM_VERSION` on Windows) before piping to
override the install location or pin a specific version instead of
`latest`.

Releases are built by [goreleaser](https://goreleaser.com) for
`{linux,darwin,windows} x {amd64,arm64}` and published automatically on
every merge to `main` whose commits since the last tag warrant a version
bump (Conventional Commits: `feat:` -> minor, `fix:`/`perf:`/`refactor:`
-> patch, `feat!:`/`BREAKING CHANGE` -> major). See [releases](https://github.com/jhonsferg/local-swarm-mcp/releases).

### From source

```sh
go build -o local-swarm-mcp ./cmd/local-swarm-mcp
```
Requires Go 1.26 or newer.

## 🛠️ Configuring backends

There's no config file to maintain: run as the persistent daemon and add
backends via the CLI or the web UI, both of which take effect immediately
with no restart.

```sh
# Start the daemon once, with the dashboard on
local-swarm-mcp -transport http -insecure-no-auth -ui

# Then, from the CLI (a separate terminal, or a script) - or from the
# dashboard's "Register host" form instead:
local-swarm-mcp -register-host -name local-llama -host-base-url http://localhost:11434
```

`-register-host` either talks to the daemon you just started (if one's
already running at `-http-addr`) or, if none is running yet, becomes the
daemon itself - see [Host discovery](#-host-discovery---add-inference-hardware-without-editing-config-or-restarting)
below for the full mechanics. A single ad-hoc backend from flags alone
(no daemon, no registration) still works too, e.g. for a quick one-off
`-transport stdio` run:

```
local-swarm-mcp -backend-name local-llama -backend-url http://localhost:8080/v1 -backend-model qwen2.5-coder
```

### Flags that matter most

| Flag | Default | Purpose |
|---|---|---|
| `-transport` | `stdio` | `"stdio"` (spawned as a local subprocess) or `"http"` (the persistent daemon) |
| `-ui` | `false` | Serve the embedded dashboard at `/` - only meaningful for `-transport=http` |
| `-http-addr` | `:8090` | Listen address when `-transport=http`, e.g. `:8090` or `0.0.0.0:8090` |
| `-api-key` | *(none)* | Bearer token HTTP clients must present when `-transport=http`; required unless `-insecure-no-auth` is set |
| `-insecure-no-auth` | `false` | Allow `-transport=http` with no `-api-key` - only on a trusted, isolated network |
| `-register-host` | `false` | Register an inference host for background discovery - see `-name`/`-host-base-url`/`-host-api-key` |
| `-backend-name`/`-backend-url`/`-backend-model`/`-backend-key` | *(none)* | A single ad-hoc backend, for a quick run without the daemon |
| `-store-path` | `/local-swarm-mcp/scratch.db` | Override the scratch-store file location |

Run `local-swarm-mcp -h` for the full, grouped flag reference (host
discovery, downstream MCP servers, storage locations, and more).

Legacy: YAML/JSON config file

A `-config path/to/config.yaml` (or `.json`) file with `backends:` and
`mcp_servers:` lists still works and is still auto-detected at
`/local-swarm-mcp/config.yaml` if present - this predates
host discovery and dynamic downstream MCP server registration, and is no
longer the recommended way to configure anything covered by those
features. It remains useful for exactly one thing: a fixed, version-
controllable starting point loaded once at daemon startup (or for a
`-transport stdio` run where a persistent daemon isn't wanted at all).

```yaml
backends:
  - name: local-llama
    base_url: http://localhost:8080/v1
    model: qwen2.5-coder
mcp_servers:
  - name: codebase-memory-mcp
    command: /path/to/codebase-memory-mcp
store_path: C:\Users\you\.cache\local-swarm-mcp\scratch.db
```

⚠️ **This file auto-loads even if you never pass `-config`** - the flag's
*default value* is that same `` path, so if it exists
from an earlier setup, its `backends:` list gets loaded every time and
sits alongside anything registered dynamically, permanently, since a
static entry is never touched by the discovery poller (it isn't the
poller's to manage). If you've moved to host discovery and still see an
old model that no longer exists on some host, this file - not a bug in
discovery - is almost certainly why: either delete it, or empty out its
`backends:` list, and restart the daemon.

## 🔌 Registering with an MCP client

### 💻 Local (stdio) - the common case

Add an entry to your client's MCP config (e.g. Claude Code's `.mcp.json`)
pointing `command` at the built binary:

```json
{
  "mcpServers": {
    "local-swarm-mcp": {
      "command": "/path/to/local-swarm-mcp"
    }
  }
}
```

Keep this path **unversioned** (`local-swarm-mcp`, not
`local-swarm-mcp-v2`): rebuilding to the same fixed path means your
client's config never needs to change and you never need to restart it
just to pick up a new build. Windows won't let you overwrite a `.exe`
its own running process has open, but it *will* let you rename one out
of the way first - so on Windows, rebuild like this instead of building
straight over it:

```powershell
Rename-Item local-swarm-mcp.exe local-swarm-mcp.exe.old -ErrorAction SilentlyContinue
go build -o local-swarm-mcp.exe ./cmd/local-swarm-mcp
```

The already-running process keeps working fine off the renamed file
(Windows processes hold an open handle, not a path) until it's next
restarted, at which point it picks up the new build from the same
stable path - no config edit required.

### 🌍 Remote (HTTP) - running on a separate GPU machine

If your inference hardware lives on a different machine than your MCP
client (e.g. a DGX Spark, or any other PC with a GPU on your network), run
local-swarm-mcp *there* instead, then register that machine's own local
inference server as a host once it's up (from another machine, or from
the dashboard):

```
local-swarm-mcp -transport http -http-addr 0.0.0.0:8090 -api-key  -ui
```

Then point your MCP client at it over HTTP (exact config syntax depends on
your client - check whether it supports a `url` + `headers` style MCP
entry, e.g.):

```json
{
  "mcpServers": {
    "local-swarm-mcp": {
      "url": "http://gpu-host:8090/mcp",
      "headers": { "Authorization": "Bearer " }
    }
  }
}
```

🔒 `-api-key` is required unless you pass `-insecure-no-auth` - anyone who
can reach the port can otherwise spawn tasks and read/write the scratch
store, so treat it like any other network-exposed service.
`-insecure-no-auth` is only reasonable on a network you fully trust and
isolate (e.g. a home LAN with no other untrusted devices).

### 🛰️ Host discovery - add inference hardware without editing config or restarting

Once running with `-transport http`, local-swarm-mcp becomes a small
service-discovery daemon for your inference hosts: register a host once
(a desktop GPU, a DGX Spark, an AMD AI box - anything speaking Ollama's
API) and it's polled in the background forever after. New models pulled
on that host show up automatically as `/` backends - no
YAML/JSON edit, no client restart.

```
local-swarm-mcp -register-host -name rx9070 -host-base-url http://192.168.18.29:11434
```

- If a daemon is already running at the default address, this is a thin
  HTTP client: it forwards the registration and exits.
- If no daemon is running yet, this invocation *becomes* the daemon (same
  process, same leader-election mechanism `-transport http` normally goes
  through) and keeps the registration.

Exactly one process ever wins: every invocation probes `-http-addr` first,
and if nothing answers there, falls back to a PID lockfile
(`/local-swarm-mcp/daemon.lock`) with a health check as a
second, independent confirmation - a stale lock from a crashed daemon is
reclaimed automatically (its PID is checked for liveness), but a live PID
that isn't actually answering as a real local-swarm-mcp daemon is
reported as a genuine conflict rather than silently overridden.

The same operations are also available as MCP tools
(`register_backend_host`, `unregister_backend_host`,
`list_backend_hosts`) so an agent - or you, through your MCP client - can
manage hosts directly over the existing connection. `list_backend_hosts`
reports whether each host is currently reachable (`up`), so you (or an
agent orchestrating work) can tell a host that's merely registered but
powered off from one that's actually available before dispatching a task
to it.

### 🔌 Downstream MCP servers, dynamically

The `mcp_servers:` config-file list works the same way it always has, but
it's legacy now: `register_downstream_mcp_server` (and its
`unregister_downstream_mcp_server` / `list_downstream_mcp_servers`
counterparts) registers a server like `codebase-memory-mcp` at runtime -
spawned and connected immediately, persisted so it reconnects
automatically across daemon restarts, no config file or restart needed.
The same three operations are also exposed over the admin HTTP surface
(`POST /admin/register-mcp-server`, `POST /admin/unregister-mcp-server`,
`GET /admin/

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [jhonsferg](https://github.com/jhonsferg)
- **Source:** [jhonsferg/local-swarm-mcp](https://github.com/jhonsferg/local-swarm-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-jhonsferg-local-swarm-mcp
- Seller: https://agentstack.voostack.com/s/jhonsferg
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
