# How to Use Soup’s MCP Server for Programmatic Model Interactions

> Learn to use Soup's MCP server for programmatic model interactions. Start the server with `soup mcp serve` to drive Soup using any MCP-compatible client.

- Repository: [Alpamys Makazhan/Soup](https://github.com/MakazhanAlpamys/Soup)
- Tags: how-to-guide
- Published: 2026-08-16

---

**Use `soup mcp serve` to start a JSON-RPC server over `stdio` that exposes read-only and plan-execution tools, enabling any MCP-compatible client to drive Soup programmatically.**

Soup's **Model Context Protocol (MCP) server** turns the CLI into a programmatic service that coding agents, IDEs, and automation scripts can control. This guide covers installation, configuration, security boundaries, and practical code examples based on the `MakazhanAlpamys/Soup` source code.

## What the MCP Server Provides

The MCP server implements four architectural layers defined in `src/soup_cli/mcp_server/`:

| Component | Source File | Responsibility |
|-----------|-------------|----------------|
| **Server Launcher** | [`server.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/server.py) | Parses CLI flags, creates the `Server` instance, runs the JSON-RPC loop over stdin/stdout |
| **Tool Registry** | [`registry.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/registry.py) | Declares **read-only** tools (`advise`, `data_inspect`) and **plan-only** mutating tools (`train_start`, `export`) |
| **Execution Manager** | [`execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/execution.py) | Generates confirmation tokens, tracks subprocess lifecycles, enforces single-run concurrency |
| **Configuration Snapshotting** | [`execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/execution.py) | Copies [`soup.yaml`](https://github.com/MakazhanAlpamys/Soup/blob/main/soup.yaml) to `.soup/mcp-runs/<run_id>/config.yaml` and validates input hashes before execution |

By default, the server only exposes **read-only** tools. Mutating operations require explicit flags that enable planning and, separately, execution.

## Installation and Server Startup

Install the MCP-enabled distribution of Soup:

```bash
pip install "soup-cli[mcp]"

```

Start the server in one of three modes:

```bash

# Read-only mode (default): safe for any environment

soup mcp serve

```

```bash

# Plan-only mode: mutating tools visible but never execute subprocesses

soup mcp serve --allow-mutating

```

```bash

# Full execution mode: enables background training and export runs

soup mcp serve --allow-execute

```

The `--allow-execute` flag implies `--allow-mutating`. Without it, tools like `train_start` return only execution plans and **never** spawn subprocesses.

## Client Interaction Pattern

MCP clients communicate via JSON-RPC over the server's stdin/stdout. The protocol distinguishes three tool categories:

- **Read-only tools** — Immediate responses, zero side effects
- **Plan-only tools** — Return a token and execution plan; subprocess deferred
- **Execution tools** — Consume the token to trigger the actual subprocess

### Example Client Implementation

```python
from mcp import Client  # Provided by `pip install "soup-cli[mcp]"`

# Connect to a local server with execution enabled

client = Client(command=["soup", "mcp", "serve", "--allow-execute"])

# 1️⃣ Call a read-only advisory tool

result = client.call("advise", {
    "data": "Explain back-propagation in transformers"
})
print(result)  # → {"response": "...", "tool": "advise"}

# 2️⃣ Plan a training run (does NOT start training yet)

plan = client.call("train_start", {"config": "/path/to/soup.yaml"})
token = plan["token"]  # Required for next step

run_id = plan["run_id"]

print(f"Planned run {run_id}, token: {token[:8]}...")

# 3️⃣ Confirm and execute with the token

exec_result = client.call("train_execute", {"token": token})
print(exec_result)  # → {"run_id": "...", "status": "started"}

```

The two-step **plan-then-execute** flow ensures human or automated review before any resource-intensive operation begins.

## Security Architecture

The [`src/soup_cli/mcp_server/execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/mcp_server/execution.py) module implements four safety mechanisms:

### 1. Flag-Driven Capability Gates

| Flag | Effect |
|------|--------|
| *(none)* | Read-only tools only |
| `--allow-mutating` | Adds `train_start`, `export` as plan-only tools |
| `--allow-execute` | Enables `train_execute`, `export_execute` with full subprocess spawning |

Accidental execution is impossible without `--allow-execute`.

### 2. One-Time Confirmation Tokens

When `train_start` or `export` is called, [`execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/execution.py) generates a **cryptographically random token** with a ~5-minute TTL. The token must be returned verbatim in the subsequent execution call. This prevents replay attacks and ensures the client explicitly intends to proceed.

Token generation and validation logic resides in [`execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/execution.py) with TTL enforcement via timestamp comparison.

### 3. Process Isolation

Subprocesses launch with these constraints:

- `shell=False` — No shell interpretation of arguments
- `stdin=subprocess.DEVNULL` — Isolated input stream
- Locked working directory prevents concurrent directory mutations
- All child stdout/stderr redirect to `.soup/mcp-runs/<run_id>.log`, keeping the JSON-RPC channel clean

### 4. Concurrency Control

Only **one active execution** is permitted system-wide. The server:

1. Persists run records including PID to `.soup/mcp-runs/`
2. Verifies child process existence before accepting new execution requests
3. Survives server restarts without orphaning or duplicating runs

This guarantees that a restarted `soup mcp serve` will not launch a second training job while the first remains active.

## Debugging and Monitoring

Inspect execution logs for any active or completed run:

```bash

# Real-time log tail

tail -f .soup/mcp-runs/<run_id>.log

# Full log review

cat .soup/mcp-runs/<run_id>/config.yaml  # Snapshot of config at plan time

ls .soup/mcp-runs/                        # All runs with metadata

```

The configuration snapshot in `.soup/mcp-runs/<run_id>/config.yaml` ensures reproducibility: even if [`soup.yaml`](https://github.com/MakazhanAlpamys/Soup/blob/main/soup.yaml) changes on disk, the executed run uses the exact configuration from planning time.

## Key Source Files Reference

| Path | Purpose |
|------|---------|
| [`src/soup_cli/commands/mcp.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/commands/mcp.py) | CLI entry point, argument parsing for `soup mcp serve` |
| [`src/soup_cli/mcp_server/server.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/mcp_server/server.py) | Core `Server` class, JSON-RPC message handling |
| [`src/soup_cli/mcp_server/registry.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/mcp_server/registry.py) | `ToolEntry` definitions and static tool table |
| [`src/soup_cli/mcp_server/execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/mcp_server/execution.py) | Token lifecycle, subprocess management, safety checks |
| [`docs/commands.md`](https://github.com/MakazhanAlpamys/Soup/blob/main/docs/commands.md) | User-facing MCP documentation and security model |
| [`tests/test_mcp_execute.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/tests/test_mcp_execute.py) | Automated verification of execution flow and concurrency |

## Summary

- **Install** with `pip install "soup-cli[mcp]"` to get the MCP SDK dependency
- **Start** read-only with `soup mcp serve` or enable execution via `--allow-execute`
- **Interact** via JSON-RPC: call tools immediately, plan mutating operations, confirm with tokens
- **Trust** the security model: flags gate capabilities, tokens prevent replays, and process isolation protects the host

## Frequently Asked Questions

### What MCP clients work with Soup's server?

Any MCP-compatible client can connect. Verified options include **Claude Code**, **Cursor**, **Cline**, and **Continue**. All communicate over stdin/stdout using the JSON-RPC protocol defined in the MCP specification.

### Why does training require a two-step plan-and-execute flow?

The design prevents accidental resource consumption and enables audit trails. The `train_start` tool snapshots the configuration, computes resource estimates, and returns a token. Only `train_execute` with that specific token spawns the actual training subprocess, allowing human review or automated policy checks between stages.

### How does the server handle crashes or restarts during a training run?

The execution manager in [`src/soup_cli/mcp_server/execution.py`](https://github.com/MakazhanAlpamys/Soup/blob/main/src/soup_cli/mcp_server/execution.py) persists run metadata including the subprocess PID. On restart, the server checks whether the recorded PID is still alive. If a run is active, new execution requests are rejected until the current run completes, preventing duplicate training jobs.

### Can I use the MCP server without installing the full Soup package?

No. The `soup-cli` package with the `[mcp]` extra is required. This installs both the server implementation and the MCP SDK client libraries. The server depends on internal Soup modules for configuration parsing and subprocess management that are not available separately.