Skip to main content
Glama
README.md
# Runner MCP

<!-- mcp-name: io.github.Blacksp1d3r/runner-mcp -->

[![Runner MCP validation](https://github.com/Blacksp1d3r/runner-mcp/actions/workflows/validation.yml/badge.svg?branch=main)](https://github.com/Blacksp1d3r/runner-mcp/actions/workflows/validation.yml)
[![GitHub release](https://img.shields.io/github/v/release/Blacksp1d3r/runner-mcp?include_prereleases)](https://github.com/Blacksp1d3r/runner-mcp/releases)
[![PyPI](https://img.shields.io/pypi/v/aifordable-runner-mcp)](https://pypi.org/project/aifordable-runner-mcp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/Python-3.12%2B-blue.svg)](pyproject.toml)

**Let an AI run tests and controlled staging operations on your own server without giving it a general-purpose remote shell.**

Runner MCP is a security-first, self-hosted Model Context Protocol service. You configure the projects and operations that exist; the AI selects from those bounded capabilities instead of supplying arbitrary shell commands, executables, filesystem paths or service names.

_An AIfordable project — secure software. Built with AI. Fairly priced._

Runner MCP is currently **alpha**. The canonical public distribution is available on [PyPI](https://pypi.org/project/aifordable-runner-mcp/), the [official MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.Blacksp1d3r%2Frunner-mcp) and [GitHub Releases](https://github.com/Blacksp1d3r/runner-mcp/releases). The first fully aligned cross-registry release is v0.1.2.

**Start here:** [5-minute demo](docs/DEMO.md) · [Quickstart](QUICKSTART.md) · [Security model](SECURITY.md) · [Threat model](security/THREAT_MODEL.md)

### The difference in one table

| Approach | AI can inspect/run configured work | Arbitrary shell is the normal interface | Explicit audit/safety boundary |
| --- | --- | --- | --- |
| SSH / broad remote-control tool | Yes | Yes | Depends on the surrounding setup |
| Runner MCP | Yes | **No** | **Yes — allow-lists, bounded output, emergency stop and approval gates** |

Runner MCP is intentionally not a sandbox for untrusted code and does not claim to replace every operator maintenance tool. Its goal is narrower: routine AI-assisted development and staging operations should not require handing the AI an unrestricted shell.

## Why Runner MCP exists

AI-assisted development becomes much more useful when the assistant can verify changes against real projects. But routine tasks such as reading a safe file, running a known test suite or checking a staging service do not require the authority of a general-purpose remote shell.

Runner MCP turns those routine operations into explicit capabilities. The operator configures projects and named actions locally; the AI client selects from those capabilities instead of supplying arbitrary commands, executable paths or private infrastructure values.

The original motivation was practical: reduce the day-to-day dependency on broad remote-control tooling while keeping useful development and staging automation.

## How it works

```mermaid
flowchart LR
    A[AI client] -->|private MCP transport| R[Runner MCP]
    A -->|optional bounded requests| G[GitHub mailbox]
    G -->|strict allow-listed bridge| R
    H[Human operator] -->|approval / emergency stop| R
    R --> P[Configured projects]
    R --> T[Predefined test profiles]
    R --> O[Controlled staging operations]
```

Runner MCP is the local safety boundary. GitHub can be used for source collaboration and, optionally, as a bounded mailbox transport; it is not turned into a mechanism for sending arbitrary shell commands.

The normal authority model is deliberately asymmetric: read-only inspection is easier, mutating staging actions are narrower, higher-risk actions require short-lived local approval, and production mutations remain disabled.

## I just want to use it

You do not need to understand the Python source code for the basic workflow.

Starting with v0.1.1, the shortest persistent install is:

```bash
uv tool install aifordable-runner-mcp
runner-mcp setup
runner-mcp doctor
runner-mcp guide
runner-mcp status
```

`uvx aifordable-runner-mcp ...` is also suitable for package discovery and short-lived evaluation, but a persistent tool install is the clearer choice for a self-hosted service with private configuration and autostart.

To install directly from source instead:

```bash
git clone https://github.com/Blacksp1d3r/runner-mcp.git
cd runner-mcp
./install.sh
```

Start with [QUICKSTART.md](QUICKSTART.md) for the guided installation.

Connectivity remains loopback-first. `runner-mcp setup` in `public` mode records an external HTTPS resource/auth identity only; it does not expose a bind address, install TLS, edit DNS/firewalls, configure a reverse proxy or create a tunnel. `runner-mcp guide` reports only a generic connectivity category without printing the configured hostname or private URL. For supported OpenAI products, private access can use [Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels); an external HTTPS reverse proxy remains an operator-managed alternative.

If Runner MCP runs under a dedicated service account while you log in with a separate operator account, install a local operator wrapper. Skip this step when Runner MCP runs under the same account you use interactively:

```bash
./install-operator.sh SERVICE_USER
runner-mcp guide
```

The wrapper keeps the private configuration with the service account and delegates through `sudo`; it does not copy credentials into the operator account.

For a user-to-developer path, see [docs/USING_AND_EXTENDING.md](docs/USING_AND_EXTENDING.md). Contributors can start with [CONTRIBUTING.md](CONTRIBUTING.md).

For the zero-additional-service-cost GitHub mailbox pattern, see [docs/GITHUB_MAILBOX_BRIDGE.md](docs/GITHUB_MAILBOX_BRIDGE.md). The public package now includes both a transport-neutral processor and a fixed-host GitHub transport; completion feedback and watcher resilience are documented in [docs/COMPLETION_FEEDBACK.md](docs/COMPLETION_FEEDBACK.md) and [docs/WATCHER_RESILIENCE.md](docs/WATCHER_RESILIENCE.md). Bounded multi-project scheduling and capacity controls are documented in [docs/CONCURRENCY.md](docs/CONCURRENCY.md).

Dependency/build/interpreter contract changes are deliberately refused by self-update and require a local bootstrap/manual upgrade; see [self-update compatibility](docs/SELF_UPDATE_COMPATIBILITY.md).

Runner MCP is developed as an [AIfordable project](docs/AIFORDABLE.md). Public launch readiness is tracked in [docs/LAUNCH_READINESS.md](docs/LAUNCH_READINESS.md). See also the [changelog](CHANGELOG.md), [release checklist](docs/RELEASE_CHECKLIST.md) and prepared [launch copy](docs/LAUNCH_COPY.md).

Useful commands:

```text
runner-mcp setup
runner-mcp doctor
runner-mcp guide
runner-mcp status
runner-mcp emergency-stop on
runner-mcp emergency-stop status
runner-mcp emergency-stop off
runner-mcp project list
runner-mcp project add ...
runner-mcp test-profile list PROJECT
runner-mcp test-profile add PROJECT NAME --preset pytest
runner-mcp service-config list PROJECT
runner-mcp service-config add PROJECT ALIAS --unit UNIT
runner-mcp database-config list
runner-mcp database-config add PROJECT
runner-mcp retention preview PROJECT
runner-mcp database restore-plan PROJECT BACKUP_ID
runner-mcp migration-config add PROJECT --preset alembic
runner-mcp deployment-config list
runner-mcp deployment-config add PROJECT --release-root PATH --service ALIAS
runner-mcp github-mailbox status
runner-mcp github-watcher once
runner-mcp serve

# MCP/mailbox clients can also use:
# runtime_status
# runtime_doctor
# self_update <full-main-commit>
# self_update_status <job-id>
```

The emergency stop is intentionally easy to activate and harder to clear.

## What works today

Current implemented foundations include:

- authenticated MCP over Streamable HTTP;
- project allow-listing;
- safe project file listing, metadata and paged reads;
- path traversal, symlink and secret-file protection;
- request IDs, rate limiting and audit logging;
- DNS-rebinding protection;
- external operator emergency stop;
- rollback-retention policy using both minimum count and minimum age;
- local read-only retention preview with strict release/backup validation and no deletion authority;
- explicit separation between code rollback and database restore;
- controlled asynchronous test jobs;
- commit-pinned self-update for the canonical Runner MCP project, gated by an unchanged Python/build/dependency compatibility contract, fixed lint/unit validation and internal self-reexec;
- bounded fair multi-project test scheduling with per-project opt-in parallelism;
- safe queue, worker and job observability without infrastructure disclosure;
- allow-listed systemd-user staging service status/start/stop/restart;
- optional private service health checks;
- private PostgreSQL backups with safe metadata listing;
- local read-only PostgreSQL restore preflight without database mutation;
- controlled migration status/apply with mandatory pre-migration backup;
- staging-only release planning and asynchronous deployment jobs;
- clean-Git release archives, atomic activation and health-gated rollback;
- safe release history plus one-step asynchronous staging rollback;
- built-in allow-listed project adapters with safe capability inspection;
- strict MCP tool arguments: unknown fields are rejected rather than ignored;
- short-lived human approval gates for migration, deploy and rollback;
- staging-only mutation policy; production remains read-only;
- private ChatGPT connectivity can use OpenAI Secure MCP Tunnel without an inbound public port;
- predefined test profiles only;
- test timeout, cancellation and process-group cleanup;
- scrubbed, bounded test logs;
- recovery of interrupted test-job metadata after restart;
- interactive setup, status and doctor commands;
- CLI project management without manual YAML editing;
- CLI test-profile management with pytest, Ruff and custom presets;
- non-root local installer and guided Quickstart.

## What Runner MCP deliberately does not do

Runner MCP is not intended to provide:

- a general remote shell;
- arbitrary commands supplied by an AI client;
- automatic production database restore;
- database restore execution in the current implementation;
- automatic multi-release rollback cascades;
- unrestricted service control;
- untrusted public-fork execution on a privileged persistent runner.

Production actions remain out of scope until stronger approval and isolation controls are implemented.

## Safety model

Runner MCP is built around:

- deny by default;
- explicit project, service and test-profile allow-lists;
- no arbitrary shell as a normal interface;
- no secrets in MCP tool output;
- strict path validation;
- auditable actions;
- least-privilege runtime permissions;
- explicit risk classes for operational tools;
- external operator emergency stop;
- retention confirmation before operator actions;
- one code rollback step per approved action;
- database restore always requiring explicit human approval;
- DNS-rebinding protection tied to the configured MCP resource URL.

See:

- [security/SECURITY_BASELINE.md](security/SECURITY_BASELINE.md)
- [security/THREAT_MODEL.md](security/THREAT_MODEL.md)
- [security/OPERATOR_SAFETY.md](security/OPERATOR_SAFETY.md)
- [security/TEST_EXECUTION.md](security/TEST_EXECUTION.md)

## Public repository rule

This repository must never contain real infrastructure details.

Do not commit:

- real IP addresses or hostnames;
- internal domains;
- private service endpoints or ports;
- usernames;
- absolute deployment paths from a real installation;
- database endpoints;
- credentials or tokens;
- private keys;
- database dumps or backups.

Public examples use placeholders only. Real values belong in private local configuration or an appropriate secret store.

## Controlled test execution

An MCP client may choose only a configured project and named test profile.

A test profile defines the exact executable, exact argument array, project-relative working directory, timeout, log limit and explicitly allowed environment variables.

Commands are launched with `shell=False`.

Running a test still executes project code. Until stronger sandboxing exists, only trusted repository revisions should be tested.

## Rollback philosophy

Code rollback and database recovery are separate operations.

Code releases are retained using both:

- a minimum number of releases;
- a minimum age.

A release is eligible for cleanup only when both conditions permit it.

A single approved rollback action may move back exactly one code release. Runner MCP must stop, health-check and reassess before another rollback.

Database restore is never an automatic side effect of code rollback and always requires explicit human approval.

## Development

Target runtime: Python 3.12+.

Core technologies:

- official MCP Python SDK;
- Pydantic;
- PyYAML;
- Starlette;
- Uvicorn;
- pytest;
- Ruff.

The implementation uses Streamable HTTP for MCP.

Do not connect a privileged persistent self-hosted runner to untrusted public pull-request code.

## Project status

The current implementation state is tracked in:

- [handover/CURRENT_STATE.md](handover/CURRENT_STATE.md)
- [roadmap/ROADMAP.md](roadmap/ROADMAP.md)

Runner MCP v0.1.0 is the first public alpha release. The project remains under active development. The public GitHub mailbox stack now includes protocol-v1 validation, replay lifecycle, fixed-host transport, an incremental restart-safe watcher, a loopback-only MCP executor, bounded concurrent request handling, fail-closed missing-result recovery and a private-config runtime/CLI. Shared-watcher migration, exactly-once completion feedback, clean-Linux demo validation, non-root autostart packaging and privacy-safe connectivity guidance are complete. Ongoing alpha hardening and post-release work are tracked in the roadmap and release checklist.