Skip to main content
Glama
README.md
# Local Coder MCP Agent

This project packages a local coding agent workflow:

1. A Qwen coding model runs locally behind an OpenAI-compatible `/v1/chat/completions` API.
2. A Python worker talks to that local API with the OpenAI SDK.
3. A `local-coder` MCP server exposes `delegate_to_local_coder` to Codex.
4. Codex delegates implementation tasks to the local worker, then reviews tests and diffs itself.

No model weights are included. Use your own local model directory through `MODEL_DIR`.

## Architecture

```text
Codex
  -> MCP tool: delegate_to_local_coder(task, workspace, max_steps, mode, contract)
    -> mcp_servers.local_coder.server
      -> workers.coding.worker.CodingWorker
        -> OpenAI-compatible local model server
        -> restricted file/test/git tools inside the requested workspace
        -> observation layer and finish gate
```

The worker can list files, read files, write files, patch exact text, run pytest,
run a small allowlist of commands, search text, inspect git status, and inspect
git diff. It refuses paths outside the selected workspace.

The worker now supports two execution modes:

- `atomic`: use for one small, bounded task that should finish in a single
  worker run.
- `phase`: use for one phase of a larger multi-file task. Pass a stable
  contract so public interfaces, paths, routes, schemas, and validation
  commands stay consistent across worker calls.

After each tool call, the worker creates a structured observation and sends it
back to the local model. Before `finish`, a final evaluator checks whether
required writes, required files, validation commands, git review, and file-scope
constraints have been satisfied.

## Install

```bash
git clone https://github.com/starmania7/local-coder-mcp-agent.git
cd local-coder-mcp-agent
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e ".[dev,mlx]"
cp .env.example .env
```

Edit `.env`:

```bash
MODEL_DIR=${HOME}/models/Qwen3-Coder-30B-A3B-Instruct-4bit
ALLOWED_WORKSPACE_ROOT=${HOME}/AI/projects
LOCAL_CODER_BASE_URL=http://127.0.0.1:8080/v1
LOCAL_CODER_MODEL=default_model
LOCAL_CODER_API_KEY=local
LOCAL_CODER_MAX_TOKENS=8192
LOCAL_CODER_REQUEST_TIMEOUT=180
```

`ALLOWED_WORKSPACE_ROOT` is the directory tree the worker is allowed to edit.
For multiple roots, use `ALLOWED_WORKSPACE_ROOTS` separated by `:` on macOS/Linux.

## Start The Model Server

For an MLX model on Apple Silicon:

```bash
source .venv/bin/activate
./scripts/start_qwen3_coder_server.sh
```

The script starts:

```bash
python -m mlx_lm.server \
  --model "${MODEL_DIR}" \
  --host 127.0.0.1 \
  --port 8080 \
  --max-tokens 8192 \
  --temp 0
```

Any OpenAI-compatible server works if it exposes
`http://127.0.0.1:8080/v1/chat/completions`, or if you update
`LOCAL_CODER_BASE_URL`.

## Start The MCP Server Manually

```bash
source .venv/bin/activate
./scripts/start_local_coder_mcp.sh
```

Normally Codex starts the MCP server for you from `config.toml`.

## Configure Codex MCP

Copy the `local-coder` block from `config.example.toml` into your Codex
`config.toml`, then replace placeholders with local values:

```toml
[mcp_servers.local-coder]
enabled = true
command = "${PROJECT_ROOT}/.venv/bin/python"
args = ["-m", "mcp_servers.local_coder.server"]
cwd = "${PROJECT_ROOT}"

[mcp_servers.local-coder.env]
LOCAL_CODER_BASE_URL = "http://127.0.0.1:8080/v1"
LOCAL_CODER_MODEL = "default_model"
LOCAL_CODER_API_KEY = "local"
LOCAL_CODER_MAX_TOKENS = "8192"
LOCAL_CODER_REQUEST_TIMEOUT = "180"
LOCAL_CODER_ENABLE_THINKING = "false"
ALLOWED_WORKSPACE_ROOT = "${ALLOWED_WORKSPACE_ROOT}"
```

Use real local paths only in your private Codex config, never in committed files.

## Delegate A Task From Codex

Example prompt to Codex:

```text
Use the local-coder MCP server and specifically call delegate_to_local_coder.

Workspace:
${ALLOWED_WORKSPACE_ROOT}/sandbox

Task:
Add multiply(a: int, b: int) -> int to calculator.py.

Requirements:
- Do not change add(), subtract(), or divide().
- Add pytest coverage for multiply().
- Run all tests.
- Inspect git diff before finishing.

After the local worker completes the task, review its changes yourself.
Do not implement the change yourself unless the local worker fails.
```

The included `examples/sandbox` folder is a tiny pytest project for smoke tests.

## Execution Modes

For small tasks, ask Codex to use `atomic` mode:

```python
delegate_to_local_coder(
    workspace="${ALLOWED_WORKSPACE_ROOT}/sandbox",
    task="Add multiply(a: int, b: int) -> int to calculator.py and test it.",
    mode="atomic",
    max_steps=8,
    max_tokens=3000,
    allowed_files=["calculator.py", "test_calculator.py"],
    required_files=["calculator.py", "test_calculator.py"],
    validation_commands=[["python", "-m", "pytest", "-q"]],
)
```

For larger work, Codex should split the project into phases and reuse the same
`run_id` and architecture contract:

```python
delegate_to_local_coder(
    workspace="${ALLOWED_WORKSPACE_ROOT}/my-api",
    task="Phase 2: implement only auth.py and users.py.",
    mode="phase",
    run_id="my-api-001",
    max_steps=14,
    max_tokens=6000,
    contract={
        "allowed_files": ["src/auth.py", "src/users.py", "tests/test_auth_users.py"],
        "required_files": ["src/auth.py", "src/users.py", "tests/test_auth_users.py"],
        "validation_commands": [["python", "-m", "pytest", "-q", "tests/test_auth_users.py"]],
        "git_review_required": True,
        "public_interfaces": [
            "create_access_token(subject, settings) -> str",
            "decode_access_token(token, settings) -> dict",
            "UserStore.register(username, password) -> dict",
            "UserStore.authenticate(username, password) -> dict | None",
        ],
    },
)
```

See `skills/local-coder-manager/references/EXECUTION_ROUTING.md` for the full
task-routing rules and prompt templates.

## Common Errors

### Workspace is not inside an allowed root

Set `ALLOWED_WORKSPACE_ROOT` or `ALLOWED_WORKSPACE_ROOTS` so the requested
workspace is inside an approved directory. This is intentional: the worker
should not be allowed to edit arbitrary local files.

### Worker exceeded maximum number of steps

Increase `max_steps` for larger tasks only after narrowing the prompt. For
multi-file work, prefer `phase` mode with a stable contract over one large
worker call. Good local-worker tasks are specific and verifiable.

### Model returned no usable text

The local model server returned a response without usable `content`,
`reasoning_content`, `reasoning`, or `thinking`. Try:

- Confirm the server implements OpenAI-compatible chat completions.
- Set `LOCAL_CODER_ENABLE_THINKING=false`.
- Reduce task size.
- Test the server with a direct `/v1/chat/completions` request.

### Connection failed

Confirm the model server is running, the port matches `LOCAL_CODER_BASE_URL`,
and no firewall or proxy is intercepting localhost traffic.

## Security Notes

- Do not commit `.env`, private Codex config files, model weights, logs, keys, or
  generated caches.
- Keep `ALLOWED_WORKSPACE_ROOT` narrow.
- The local worker can edit and run limited commands inside allowed workspaces;
  review every diff before accepting changes.
- Keep the API server bound to `127.0.0.1` unless you have a separate network
  security plan.
- This repository intentionally uses placeholders such as `${HOME}`,
  `${MODEL_DIR}`, `${PROJECT_ROOT}`, and `${ALLOWED_WORKSPACE_ROOT}`.

## Run Checks

```bash
python -m pytest -q
python -m py_compile \
  mcp_servers/local_coder/server.py \
  workers/coding/client.py \
  workers/coding/observation.py \
  workers/coding/parser.py \
  workers/coding/tools.py \
  workers/coding/worker.py
```

To run the live model-client test, start the local model server first and set:

```bash
LOCAL_CODER_RUN_LIVE_TESTS=1 python -m pytest -q workers/coding/tests/test_client.py
```

TDQS

B3.4/5.0

Scored across 1 tool

Disambiguation5/5

There is only one tool, so there are no overlapping purposes or risk of selecting the wrong tool. The tool's purpose is clearly stated and unique within this server.

Naming Consistency5/5

The single tool name uses a clear, descriptive verb-target structure: delegate_to_local_coder. With no other tools to conflict with, there is no naming inconsistency.

Tool Count2/5

A single tool feels too thin for the broad local-coding scope described, which includes inspecting files, patching code, creating files, running tests, and checking diffs. The entire capability set is buried behind one opaque delegation endpoint.

Completeness3/5

The delegate tool covers task handoff and appears to return results for review, but there are no separate tools for status, cancellation, or finer-grained control of coding operations. This makes the surface usable for simple flows but incomplete for managing the full lifecycle of delegated work.

Maintenance

ActivityMaintained
ResponsivenessNo issues