Skip to main content
Glama

Flotilla MCP is a fleet of Model Context Protocol servers that can read GitHub issues, edit its own source, open pull requests, and — once a human merges the change — redeploy itself, without ever being able to take the fleet down or disarm its own safety controls. The parts of the system that could do real damage (the deploy pipeline, the permission layer, the rule that defines what's off-limits) are structurally walled off from the part that writes code, and enforced at more than one independent layer.

This repository is the foundation of that system: the protected-core enforcement engine, the Self-Dev MCP server, and the Deploy Watcher's blue/green deploy and rollback machinery. It is real, tested code, not a prototype — see Status below for exactly what's built and what isn't yet.

Install

Self-Dev MCP only:

pip install flotilla-mcp

Self-Dev MCP plus the Deploy Watcher (needs the Docker SDK):

pip install "flotilla-mcp[watcher]"

Or run it without installing anything, via uvx:

uvx flotilla-mcp

This installs three console scripts:

  • flotilla-mcp and flotilla-self-dev (identical — two names for the same entry point) — the Self-Dev MCP server: flotilla-self-dev --transport stdio|http (default stdio; --transport http serves /health on port 8080 for container health checks); --version prints the installed version.

  • flotilla-watcher — the Deploy Watcher. Needs pip install "flotilla-mcp[watcher]"; without the docker package installed, it prints flotilla-watcher needs the Docker SDK. Install it with: pip install "flotilla-mcp[watcher]" and exits rather than crashing with an import traceback.

Self-Dev MCP reads its configuration from environment variables (see .env.example and flotilla_mcp/self_dev_mcp/config.py). SELF_DEV_GITHUB_TOKEN is the only variable you have to set — run it from inside a git checkout with a GitHub origin remote and everything else is detected:

Variable

Required

Meaning

SELF_DEV_GITHUB_TOKEN

yes

fine-grained token (or bot token): contents, pull requests, and issues read/write on the target repo

SELF_DEV_REPO_REMOTE

no (auto-detected)

git remote URL used for the clone/branch/commit/push workflow. When unset, detected by running git remote get-url origin in the server's working directory.

GITHUB_REPO_FULL_NAME

no (auto-detected)

owner/repo. When unset, parsed from SELF_DEV_REPO_REMOTE (explicit or detected). A non-GitHub remote (or a local path) parses to nothing — the editing tools (start_issue, read_file, write_file, run_tests) still work; the GitHub-backed tools (list_assigned_issues, check_pr_status, submit_pr) return an ERROR: no GitHub repository configured string instead of failing to start.

FLEET_MANIFEST_PATH

no

path to the fleet manifest. When unset, resolved in order: fleet_manifest.yaml in the current directory, then fleet_manifest.yaml at the git repo root. If none of those exist either, the server starts with an empty manifest (no services declared) and logs one warning — only the built-in always-protected paths apply until a manifest exists. An explicit FLEET_MANIFEST_PATH that doesn't exist is still a hard error.

SELF_DEV_MAX_ATTEMPTS

no (default 5)

per-issue write attempt cap

SELF_DEV_TEST_TIMEOUT_SECONDS

no (default 600)

run_tests timeout, in seconds

An explicitly set environment variable always wins over auto-detection. If SELF_DEV_REPO_REMOTE is unset and no origin remote can be detected, the server exits with a one-line error naming both fixes: run it inside a git repository with an origin remote, or set SELF_DEV_REPO_REMOTE.

Read SECURITY.md#preconditions-before-pointing-a-live-agent-at-a-repo before pointing this at a repository you care about.

Related MCP server: GitPilot MCP

Use with an MCP client

Both snippets below point uvx at the flotilla-mcp PyPI package and pass configuration through environment variables — see SECURITY.md#preconditions-before-pointing-a-live-agent-at-a-repo first.

Claude Desktop

Add to your Claude Desktop config (claude_desktop_config.json). The token is the only variable that's required — as long as the server's working directory is inside a git checkout with a GitHub origin remote, the repo remote and owner/repo are auto-detected (see Install above):

{
  "mcpServers": {
    "flotilla-mcp": {
      "command": "uvx",
      "args": ["flotilla-mcp"],
      "env": {
        "SELF_DEV_GITHUB_TOKEN": "<fine-grained token>"
      }
    }
  }
}

If your client doesn't run the server with a working directory inside the target repo (or you want to be explicit), set SELF_DEV_REPO_REMOTE (and optionally GITHUB_REPO_FULL_NAME, FLEET_MANIFEST_PATH) in env the same way as before -- an explicit value always overrides auto-detection.

Claude Code

The claude CLI wasn't available in the environment this doc was written in, so its exact claude mcp add ... -e KEY=VALUE flag syntax couldn't be verified against a real claude mcp add --help; run that yourself before scripting the command form. The JSON form above is not client-specific — paste the same mcpServers block into whatever configuration surface your claude CLI version reads for MCP servers.

Tools

Self-Dev MCP exposes these 7 tools. Each is documented (description and per-parameter descriptions) so an MCP client can surface them to the model without extra context; handlers return a string starting OK, REFUSED:, EXHAUSTED:, or ERROR: instead of raising, so a caller can branch on the prefix.

Tool

Summary

start_issue

Clone the target repo into a fresh per-issue workspace and create/resume its selfdev/issue-N branch; one active workspace per issue.

read_file

Read a file from the issue workspace; paths outside it, with a drive letter, or touching .git are refused.

write_file

Write a file in the issue workspace; also checked against the fleet manifest's protected paths and a per-issue attempt cap (default 5).

run_tests

Run the repo's own pytest inside the workspace with a timeout and return the exit status and output; commits nothing.

submit_pr

Commit everything in the workspace, push the branch, open or reuse a PR, then destroy the workspace; never merges, never force-pushes.

list_assigned_issues

List open issues carrying the given label, with pull requests excluded.

check_pr_status

Get the combined CI state for a PR from the Checks API: pending, success, or failure.

Why Flotilla MCP

Most "self-modifying agent" demos either can't touch production or can touch too much of it. Flotilla MCP is built around one design principle: the agent reasons, MCP servers provide capabilities, and guardrails sit in between, independent of the agent's own judgment.

  • The agent (any LLM-backed orchestrator, via the MCP gateway) decides what to build or fix.

  • MCP servers like Self-Dev MCP expose narrow, auditable primitives — read a file, write a file, run tests, open a PR — not blanket shell access.

  • Guardrails (the fleet manifest, workspace containment, the attempt cap, GitHub branch protection, credential scoping) sit between the agent's intent and anything irreversible. They work in two layers:

    • the tool-level checks stop a cooperative agent, one that only edits through write_file, from touching protected paths or .git/;

    • GitHub branch protection plus a separate bot identity is the real backstop against a hostile (e.g. prompt-injected) agent. run_tests executes code the agent wrote, with the self-dev token, so that code can write protected files into its PR branch or call the GitHub API directly. What stops it from reaching main is a required CI check and a required human (code-owner) review that the bot identity can't give itself. In either case Self-Dev MCP never holds a Docker socket.

The result is an agent that can fix its own bugs and extend its own fleet, while every change that could take the system down or weaken its own oversight has to pass a human review on GitHub, provided the preconditions are in place.

Key features

Implemented today:

  • Protected-core enforcement (flotilla_mcp/common/manifest.py): a fleet manifest defines which services and paths are off-limits. A hardcoded core is protected no matter what the manifest says: the manifest, its loader, flotilla_mcp/__init__.py, requirements.txt, requirements-dev.txt, docker-compose.yml, pyproject.toml, .gitattributes, .gitignore, and the whole flotilla_mcp/common/ and .github/ trees. Path checks canonicalize separators, .. segments, NTFS aliases and case, and are applied to the symlink-resolved target too.

  • Self-Dev MCP server: a FastMCP server exposing start_issue, read_file, write_file, run_tests, submit_pr, list_assigned_issues, and check_pr_status. Every write is checked against the fleet manifest and confined to an ephemeral, per-issue workspace before it touches disk. Absolute paths, drive letters, UNC paths, .. escapes and any .git path are refused, and each refusal is audit-logged. Every git call runs with hooks and fsmonitor disabled and pushes with an explicit, non-forcing refspec. A per-issue attempt cap (default 5) stops runaway writes; a refused write never consumes an attempt. These checks bind a cooperative agent; see the safety model for what backs them up.

  • Limited blast radius: the Self-Dev MCP has no Docker socket access, no deploy credentials, and no merge code path. It can open and update PRs. Making them live takes a human review enforced by GitHub branch protection, which is a precondition, not something this code can enforce.

  • Deploy Watcher — polls main for new commits, builds each non-protected service that has a container entry in the manifest from a fresh checkout of that commit, and performs a blue/green deploy: the new container must pass 3 consecutive health checks before it's promoted, and then survives a 30-minute probation window during which a single failed check triggers an automatic rollback to the last proven image. An image is only recorded as known-good after it clears probation, so a rollback can never target a build that hasn't actually been proven to work.

  • Resumable, non-destructive self-dev cycles — re-invoking start_issue for an issue that already has an open PR resumes the same selfdev/issue-N branch instead of branching again, so follow-up commits land on the same PR. There is no force-push anywhere in the pipeline.

  • Docker Compose + per-service Dockerfilesdocker-compose.yml brings up the fixture service, Self-Dev MCP, and the Deploy Watcher on a dedicated mcp-fleet network, each with its own non-root Dockerfile and only the credentials/mounts it actually needs (see Quickstart).

  • Self-Dev MCP HTTP transport: --transport http serves Self-Dev MCP over SSE (/sse, /messages/) plus GET /health on port 8080, which the compose healthcheck probes. Tools run in worker threads, so a long run_tests never blocks /health. --transport stdio (the default) is unchanged for local/CLI use. For this release self-dev-mcp is compose-managed (docker compose up --build), not redeployed by the Deploy Watcher.

Roadmap (not built yet — see Status):

  • MCP gateway and permission manager (the layer that sits between an orchestrating agent and every capability server, including Self-Dev MCP)

  • model-adapters-mcp and credentials-manager, and the chat-side "Model Manager" flow for adding support for a new LLM backend on request

How it fits together

flowchart TD
    subgraph gh["GitHub (system of record)"]
        issue["Issue labeled self-dev"]
        pr["Pull Request"]
        ci["CI status checks"]
        branchprot["Branch protection + CODEOWNERS"]
        main["main branch"]
    end

    subgraph host["Fleet host"]
        selfdev["Self-Dev MCP<br/>(git/PR ops only —<br/>no Docker, no deploy creds)"]
        watcher["Deploy Watcher<br/>(PROTECTED — Docker socket,<br/>blue/green, rollback)"]
        gateway["MCP Gateway +<br/>Permission Manager<br/>(PROTECTED — planned)"]
        registry["Service registry +<br/>known-good store"]
    end

    subgraph fleet["Watcher-deployed containers"]
        svc1["fixture-hello-mcp"]
        svcN["... other unprotected services<br/>with a container entry"]
    end

    issue -->|start_issue| selfdev
    selfdev -->|read_file / write_file<br/>manifest-checked| selfdev
    selfdev -->|run_tests, informational| selfdev
    selfdev -->|submit_pr| pr
    pr --> ci
    ci --> branchprot
    branchprot -->|human merge only| main
    main -->|poll| watcher
    watcher -->|build + health-check +<br/>blue/green swap| fleet
    watcher --> registry
    gateway -.orchestrates calls to.-> selfdev
    gateway -.orchestrates calls to.-> svcN

See ARCHITECTURE.md for the full component breakdown, trust boundaries, and the rollback state machine.

The protected core and the safety model

A small set of things can never be edited by the Self-Dev MCP, no matter what an agent's reasoning concludes it should do:

  • The fleet manifest (fleet_manifest.yaml), the manifest loader (flotilla_mcp/common/manifest.py) and everything else in flotilla_mcp/common/, plus the build/dependency files (flotilla_mcp/__init__.py, requirements.txt, requirements-dev.txt, docker-compose.yml, pyproject.toml, .gitattributes, .gitignore) and CI/CODEOWNERS (.github/). These are hardcoded-protected, so write_file refuses them even if the manifest were rewritten to claim they're safe.

  • Git metadata (.git/): no tool can read or write it, and every git call runs with hooks and fsmonitor disabled and an explicit push refspec.

  • The Deploy Watcher, permission manager (planned), and MCP gateway (planned) services — marked protected: true in the manifest. These hold real authority (Docker socket access, routing, auth), so they are off-limits at the tool layer and would additionally require CODEOWNERS sign-off at the GitHub layer — the workflow and CODEOWNERS file exist; enforcement requires branch protection, which the repo admin enables — see CONTRIBUTING.md#enabling-branch-protection.

On top of that:

  • Workspace containment: every read_file/write_file/run_tests call is resolved against the current issue's ephemeral workspace. Absolute paths, drive letters, UNC paths, .. segments, and symlinks or junctions that lead to a protected or outside path are refused before anything touches disk.

  • No merge code path: Self-Dev MCP can open and update a pull request, and nothing in this codebase calls a merge API. The self-dev token could merge through the API, though, so merge-by-a-human-only is enforced by GitHub branch protection and CODEOWNERS. The workflow and CODEOWNERS file exist; the repo admin enables branch protection (see CONTRIBUTING.md#enabling-branch-protection).

  • No deploy authority in Self-Dev MCP — it holds no Docker socket, no deploy credentials, and never imports docker. Only the Deploy Watcher — a separate, protected service — can build an image or swap a container.

  • Known-good floor — the Deploy Watcher only records an image as known-good after it survives a full probation window with zero failed checks. Rollback always targets that proven image, never a build that merely passed its first three health checks.

This is defense in depth, not a single check: even a bug in the manifest parser doesn't expose the manifest file or the parser itself, because those paths are hardcoded rather than manifest-driven.

What the tool checks do not stop. They bind a cooperative agent. run_tests executes code the agent wrote, with the self-dev token. That code can write any file (protected ones included), which submit_pr's git add -A then commits to the PR branch, and it can call the GitHub API directly. The backstop is GitHub branch protection (required test check, required review, code-owner review, enforce_admins) plus a separate bot identity for self-dev. With the owner's own PAT, self-dev PRs are authored by the owner, and a sole owner can't approve their own PR under enforce_admins. See SECURITY.md.

Quickstart

Run the test suite (works today)

git clone https://github.com/OmPrakashSingh1704/flotilla-mcp.git
cd flotilla-mcp
python -m venv .venv && source .venv/bin/activate   # or .venv\Scripts\activate on Windows
pip install -r requirements-dev.txt
python -m pytest tests -m "not docker" -v -W error::DeprecationWarning -W error::pytest.PytestUnhandledCoroutineWarning

requirements-dev.txt pulls in requirements.txt plus the packaging tools (build, twine, hatchling, hatch-fancy-pypi-readme) that tests/test_packaging.py needs to build a wheel as part of the suite.

(-m docker runs the Docker integration test separately; it needs a reachable Docker daemon.)

This runs the full suite for the protection engine, the Self-Dev MCP tools, and the Deploy Watcher — including the adversarial tests that assert a protected-path write is refused and a probation failure triggers rollback.

Run the fleet locally

Precondition before pointing a live agent at a repo: enable branch protection on main (required test check, required review, code-owner review, enforce_admins) and give self-dev its own bot identity (a machine user or GitHub App), not your own PAT. On a private repo, branch protection needs GitHub Pro, Team or Enterprise. See SECURITY.md. Running the stack with placeholder values to look around is fine.

cp .env.example .env
# edit .env: set SELF_DEV_GITHUB_TOKEN, WATCHER_GITHUB_TOKEN,
# GITHUB_REPO_FULL_NAME, REPO_REMOTE, SELF_DEV_REPO_REMOTE
docker compose up --build

SELF_DEV_GITHUB_TOKEN (fine-grained: contents, pull requests and issues read/write on this repo) and WATCHER_GITHUB_TOKEN (contents read-only) are separate tokens. The old shared GITHUB_TOKEN variable is no longer read. Git authenticates with them through a credential helper, so never put a token in a remote URL.

This brings up three containers on the mcp-fleet network:

  • fixture-hello-mcphttp://localhost:8081/health — a minimal Flask service used as the Deploy Watcher's local smoke-test target.

  • self-dev-mcphttp://127.0.0.1:8082/health (bound to loopback only, not published to other hosts — see SECURITY.md) — the Self-Dev MCP server over --transport http. Compose-managed: after merging a change to it, update it with docker compose up --build self-dev-mcp. The Deploy Watcher does not redeploy it.

  • deploy-watcher — no published port; it only talks outbound to GitHub and to the Docker daemon via the mounted docker.sock.

With placeholder .env values (or real ones that just don't resolve), fixture-hello-mcp and self-dev-mcp still start and their /health checks still pass — GitHub credentials are only resolved lazily, on the first tool call that actually needs them. Any Self-Dev MCP tool that talks to GitHub (list_assigned_issues, submit_pr, check_pr_status, ...) will return an "ERROR: ..." string until SELF_DEV_GITHUB_TOKEN and GITHUB_REPO_FULL_NAME are set to real values.

Repo layout

flotilla_mcp/
  common/manifest.py        fleet manifest loader + protected-path engine
  self_dev_mcp/              Self-Dev MCP: git ops, workspace, tools, server,
                                Dockerfile
  deploy_watcher/             Deploy Watcher: checkout, build, health, blue/green,
                                rollback, service registry, known-good store,
                                Dockerfile, entrypoint.sh
  fixture_hello_mcp/          fixture Flask service + Dockerfile, used as the
                                Deploy Watcher's local smoke-test target
tests/                      unit tests, mirroring the flotilla_mcp/ layout
docs/design/                design documents (historical / planned; code and
                              ARCHITECTURE.md are authoritative)
fleet_manifest.yaml         the fleet manifest (protected)
docker-compose.yml          local fleet: mcp-fleet network + all three services (protected)
.env.example                template for the .env docker-compose reads secrets from

Status / Roadmap

Component

Status

Fleet manifest + protected-path engine

Built

Self-Dev MCP (7 tools, workspace containment, attempt cap)

Built

Deploy Watcher (blue/green, probation, rollback, known-good floor)

Built

Docker Compose + per-service Dockerfiles

Built

Self-Dev MCP HTTP transport (--transport http)

Built

CI workflow + CODEOWNERS

Built (CODEOWNERS names a real owner, @OmPrakashSingh1704; branch protection must still be enabled by the repo admin for that review to be enforced, rather than advisory; see CONTRIBUTING.md#enabling-branch-protection)

MCP gateway

Planned

Permission manager

Planned

model-adapters-mcp

Planned

credentials-manager

Planned

Model Manager chat flow

Planned

Nothing in this table is aspirational marketing — if it says "Built," it has passing tests in this repository today. If it says "Planned" or "In progress," there is no working code for it yet.

The one thing "Built" doesn't cover automatically: a real run against your own GitHub repo (a live PR, CI, and merge). See docs/acceptance-checklist.md for that manual verification pass.

Documentation

License

Apache License 2.0 — see LICENSE and NOTICE.

Available Tools

7 tools
check_pr_statusA

Get the combined CI status for a pull request's head commit, from GitHub's Checks API. Returns exactly one of "pending" (no checks yet, or some still running), "success" (all checks completed without failure), or "failure" (at least one check reported a non-success conclusion: failed, cancelled, timed out, required action, or failed to start) -- or a string starting "ERROR:" if the status can't be retrieved (never raises).

ParametersJSON Schema
NameRequiredDescriptionDefault
pr_numberYesThe pull request number to check.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden. It discloses exact return values (pending/success/failure), the error signal ('ERROR:'), and the guarantee that it never raises. This is substantial transparency, though it omits details like authentication or rate-limit behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and immediately gives precise outcome semantics. Every clause contributes useful information; there is no repetition or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple one-parameter read-only tool with thorough return-value documentation and explicit failure behavior. Even without an output schema or annotations, an agent has everything needed to call it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter pr_number is already described as 'The pull request number to check.' The description adds context about the head commit but no additional parameter-level meaning, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Get'), a precise resource ('combined CI status for a pull request's head commit'), and the data source ('GitHub's Checks API'). This clearly distinguishes it from sibling tools like run_tests or submit_pr.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the use case clear: check a PR's combined CI status without running tests or modifying anything. It doesn't explicitly name alternatives or exclusions, but the context is unambiguous enough for selection among the listed siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_assigned_issuesA

List open GitHub issues carrying the given label; pull requests are excluded even though GitHub's issues API would otherwise include them. Use this to discover work before calling start_issue. Returns one "# " line per matching issue, a "No open issues labeled " message if none match, or a string starting "ERROR:" on failure -- never raises.

ParametersJSON Schema
NameRequiredDescriptionDefault
labelNoIssue label to filter by.self-dev

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it does so thoroughly. It discloses that PRs are excluded, defines the exact output format for matches and empty results, specifies the 'ERROR:' prefix on failure, and guarantees the tool never raises. This is exemplary behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-ordered: purpose, exclusion, usage context, then return behavior. Every sentence contributes a distinct piece of information with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter list tool with no output schema and no annotations, the description covers everything an agent needs: what it lists, what it excludes, when to use it, what it returns, and how failures present. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The schema already documents 'label' as 'Issue label to filter by', and the description adds only the context that the label applies to open issues and is used in the empty-result message. This is adequate but not additive beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), a specific resource ('open GitHub issues carrying the given label'), and an important exclusion ('pull requests are excluded'). This clearly distinguishes it from sibling tools like start_issue or submit_pr without needing to inspect their schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says 'Use this to discover work before calling start_issue', giving a clear workflow context. It does not enumerate when-not-to-use cases for every sibling, but the sequential relationship to start_issue is sufficient guidance for the primary use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_fileA

Read a file's contents from the workspace start_issue created for this issue. relative_path is resolved relative to that workspace and is refused if it is absolute, has a drive letter, is a UNC path, escapes the workspace via '..', or touches '.git'. Returns the file contents as a plain string on success, "REFUSED: ..." if the path is blocked, or "ERROR: ..." for other failures (e.g. no active workspace, file not found) -- never raises.

ParametersJSON Schema
NameRequiredDescriptionDefault
issue_numberYesThe issue number whose active workspace to read from; must have been started with start_issue first.
relative_pathYesPath to the file, relative to the issue workspace root. Absolute paths, drive letters, UNC paths, '..'-escaping paths, and any path touching '.git' are refused.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure, and it does so thoroughly. It explains path refusal rules, return value formats ('REFUSED: ...', 'ERROR: ...'), and the guarantee that it never raises. This is exactly the kind of non-obvious behavior an agent needs to know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, followed by path constraints and return contracts. Every sentence earns its place; there is no fluff or repetition of unrelated details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given two required parameters, no output schema, and no annotations, the description is complete: it covers the prerequisite, path resolution rules, refusal/error behavior, and success return format. An agent has everything needed to call the tool correctly and anticipate its outcomes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, which sets a baseline of 3, but the description adds meaningful value beyond the schema by specifying that relative_path is resolved against the issue workspace, explaining the refusal categories, and clarifying the error/refusal return strings. This helps the agent understand the actual runtime behavior for each parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Read a file's contents from the workspace start_issue created for this issue.' It clearly identifies the operation, the scope, and the relationship to sibling tools like write_file and start_issue, so an agent can distinguish it without ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: to read a file within an issue-specific workspace, and it states the prerequisite that start_issue must have been run first for the issue_number. It does not explicitly name alternatives or state when not to use it, but the context is strong enough for correct selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_testsA

Run the target repository's own pytest suite for one service, inside the issue's workspace, subject to a timeout. This only executes tests and reports the result -- it never commits or modifies anything. Returns a string starting "OK" or "FAILED" followed by the exit code and captured stdout/stderr, "REFUSED: ..." if the path is option-like, escapes the workspace, or touches '.git', or "ERROR: ..." if the run times out or fails to start -- never raises.

ParametersJSON Schema
NameRequiredDescriptionDefault
issue_numberYesThe issue number whose active workspace to run tests in; must have been started with start_issue first.
service_relative_pathYesPath to the service or test target, relative to the issue workspace root, passed to `pytest -- <path>`. Refused if it starts with '-' (could be parsed as a pytest option), escapes the workspace, or touches '.git'.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden, and it does so thoroughly. It discloses that the tool never mutates, specifies the exact response prefixes including REFUSED and ERROR cases, and states that it never raises.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description uses three focused sentences and front-loads the action. Every sentence earns its place: what it does, that it is non-mutating, and the exact result contract.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even without an output schema, the description documents return value behavior, error handling, refusal conditions, and timeout semantics. Combined with fully described parameters, the definition provides everything an agent needs to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters, including the pytest path usage and refusal conditions for service_relative_path. The description adds only marginal parameter-related context, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: run the repository's own pytest suite for one service inside the issue workspace. It also distinguishes itself from mutating siblings by explicitly saying it never commits or modifies anything.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly conveys when to use the tool: after the issue workspace exists, to execute that service's tests with a timeout. It does not name alternative tools or explicit when-not conditions, but the context is clear enough that an agent can select it safely.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

start_issueA

Begin work on a GitHub issue: clone the target repository into a fresh, isolated per-issue workspace and create (or, if one already exists, resume) a selfdev/issue-<issue_number> branch there. Call this first, before read_file, write_file, run_tests, or submit_pr -- those tools all operate on the workspace this creates. Only one active workspace is allowed per issue; calling this again for an issue that already has one returns an error instead of clobbering it. Returns the branch name as a plain string on success, or a string starting "ERROR:" on failure (never raises).

ParametersJSON Schema
NameRequiredDescriptionDefault
issue_numberYesThe GitHub issue number to start work on.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full disclosure burden and meets it thoroughly. It describes workspace isolation, branch creation/resume behavior, the single-active-workspace constraint, the success/error return contract, and the fact that it never raises an exception.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three purposeful sentences with no filler. It front-loads the core action, then provides ordering guidance, idempotency/error behavior, and the return contract. Every sentence contributes operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema and no annotations, it is nearly complete: return format, failure behavior, workspace semantics, and ordering are all specified. It does not explicitly state how 'target repository' is determined, but in an issue-scoped workflow this is largely inferable from context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already describes issue_number as 'The GitHub issue number to start work on.' The description adds extra meaning by showing exactly how issue_number is used in the branch name selfdev/issue-<issue_number>, which helps the agent understand the parameter's effect.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: 'Begin work on a GitHub issue: clone the target repository into a fresh, isolated per-issue workspace and create... a branch.' It also distinguishes itself from siblings by explaining that read_file, write_file, run_tests, and submit_pr all operate on the workspace this tool creates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call this first, before read_file, write_file, run_tests, or submit_pr, and explains why: those tools operate on the workspace this tool creates. It also warns that calling it again for an already-active issue returns an error instead of clobbering the existing workspace, giving clear when-to and when-not-to conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

submit_prA

Finish work on an issue: commit everything currently in the workspace, push the selfdev/issue-<issue_number> branch, and open a new pull request or reuse an already-open one for that branch -- then destroy the workspace. It can never merge a pull request and never force-pushes. Requires a GitHub repository to be configured. Returns "opened PR #" on success, or a string starting "ERROR:" on failure (the workspace is kept on failure so a retry doesn't need start_issue again) -- never raises.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesPull request description body.
titleYesCommit message and pull request title.
issue_numberYesThe issue number whose active workspace to submit; must have been started with start_issue first.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it declares the destructive workspace cleanup, the no-merge/no-force-push guarantees, the GitHub repository prerequisite, exact return strings, and the error path that preserves the workspace. This is well beyond a minimal 'submits a PR' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four or five dense sentences each carry essential information: action sequence, safety constraints, prerequisite, return/error behavior. There is no fluff or repetition, and the most important lifecycle information appears first.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, destructive terminal tool with no output schema, the description covers prerequisites, effects, failure semantics, and return format. An agent can call submit_pr correctly and predict consequences without needing additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all three parameters and their meanings. The description adds no extra parameter-level detail beyond what the input schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific workflow with a concrete verb and resource: commit the workspace, push the selfdev/issue-<issue_number> branch, and open/reuse a PR, then destroy the workspace. This clearly distinguishes it from sibling tools like start_issue or check_pr_status, which only start or inspect work.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The opening 'Finish work on an issue' establishes the intended point in the workflow, and the issue_number parameter notes the workspace must have been started with start_issue first. It does not explicitly name alternatives or state when not to call it, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_fileA

Create or overwrite a file inside the workspace start_issue created for this issue. relative_path is checked the same way as read_file (no absolute/drive/UNC/'..'/'.git' paths) and is additionally checked against the fleet manifest's protected paths. Writes are capped per issue (default 5 attempts, configurable via SELF_DEV_MAX_ATTEMPTS); a refused write does not count against that cap. Returns "OK" on success, "REFUSED: ..." for a blocked path, "EXHAUSTED: ..." once the attempt cap is reached, or "ERROR: ..." for other failures -- never raises.

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesFull text content to write to the file, replacing any existing content.
issue_numberYesThe issue number whose active workspace to write into; must have been started with start_issue first.
relative_pathYesPath to the file to write, relative to the issue workspace root. Absolute paths, drive letters, UNC paths, '..'-escaping paths, '.git' paths, and paths protected by the fleet manifest are refused.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It fully discloses write caps (default 5, configurable), that refused writes don't count against the cap, and all possible return values ('OK', 'REFUSED', 'EXHAUSTED', 'ERROR') including the guarantee that it never raises. Path restrictions are also detailed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, front-loaded with the core purpose, then path validation, then caps and return behavior. Every sentence adds unique value with no repetition or filler. The structure is logical and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write tool with no output schema and no annotations, the description covers all essential operational aspects: what it does, how paths are validated, attempt limits, exact return values, and the guarantee of not raising exceptions. It also ties into start_issue as a prerequisite. Nothing critical is missing for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% – all three parameters (content, issue_number, relative_path) are already described with sufficient detail in the schema. The description adds a cross-reference to read_file for relative_path validation and mentions the fleet manifest check, but these are essentially re-statements of schema content. It adds no new semantic meaning beyond the schema, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Create or overwrite a file') with a clear resource (file inside the issue workspace) and distinguishes itself from read_file by its write semantics. It also references the prerequisite start_issue, leaving no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for writing files and references read_file for path-check consistency, but it does not explicitly state 'use this for writing, read_file for reading' or mention any exclusions. The start_issue prerequisite is noted, providing clear context, but alternatives are not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.1.2
    • Changedcheck_pr_status1 field changed
      • addedInput schema / properties / pr_number / description
        Added value: +"The pull request number to check."
    • Changedlist_assigned_issues1 field changed
      • addedInput schema / properties / label / description
        Added value: +"Issue label to filter by."
    • Changedread_file2 fields changed
      • addedInput schema / properties / issue_number / description
        Added value: +"The issue number whose active workspace to read from; must have been started with start_issue first."
      • addedInput schema / properties / relative_path / description
        Added value: +"Path to the file, relative to the issue workspace root. Absolute paths, drive letters, UNC paths, '..'-escaping paths, and any path touching '.git' are refused."
    • Changedrun_tests2 fields changed
      • addedInput schema / properties / issue_number / description
        Added value: +"The issue number whose active workspace to run tests in; must have been started with start_issue first."
      • addedInput schema / properties / service_relative_path / description
        Added value: +"Path to the service or test target, relative to the issue workspace root, passed to `pytest -- <path>`. Refused if it starts with '-' (could be parsed as a pytest option), escapes the workspace, or touches '.git'."
    • Changedstart_issue1 field changed
      • addedInput schema / properties / issue_number / description
        Added value: +"The GitHub issue number to start work on."
    • Changedsubmit_pr3 fields changed
      • addedInput schema / properties / body / description
        Added value: +"Pull request description body."
      • addedInput schema / properties / issue_number / description
        Added value: +"The issue number whose active workspace to submit; must have been started with start_issue first."
      • addedInput schema / properties / title / description
        Added value: +"Commit message and pull request title."
    • Changedwrite_file3 fields changed
      • addedInput schema / properties / content / description
        Added value: +"Full text content to write to the file, replacing any existing content."
      • addedInput schema / properties / issue_number / description
        Added value: +"The issue number whose active workspace to write into; must have been started with start_issue first."
      • addedInput schema / properties / relative_path / description
        Added value: +"Path to the file to write, relative to the issue workspace root. Absolute paths, drive letters, UNC paths, '..'-escaping paths, '.git' paths, and paths protected by the fleet manifest are refused."
  2. 7 tool updatesv0.1.0
    • First observedcheck_pr_status
    • First observedlist_assigned_issues
    • First observedread_file
    • First observedrun_tests
    • First observedstart_issue
    • First observedsubmit_pr
    • First observedwrite_file

TDQS

A4.4/5.0

Scored across 7 tools

Disambiguation5/5

Each tool owns a distinct stage of the issue-to-PR workflow: discovery, workspace setup, file read/write, test execution, PR submission, and CI status. There is no meaningful overlap between read_file and write_file or between run_tests and check_pr_status.

Naming Consistency5/5

All seven tools follow a consistent snake_case verb_noun pattern: start_issue, read_file, write_file, run_tests, list_assigned_issues, submit_pr, check_pr_status. The naming is predictable and immediately signals what each tool does.

Tool Count5/5

Seven tools is well-scoped for the server's stated purpose of working through GitHub issues from discovery to PR submission. Each tool earns its place and there are no redundant or filler entries.

Completeness3/5

The core workflow is covered: discover issues, start an isolated workspace, edit files, run tests, submit a PR, and check CI status. However, there is no way to read issue bodies/comments or list the workspace directory structure, which leaves notable gaps for agents that need to understand requirements or navigate an unfamiliar repository. There is also no explicit abort/discard tool for abandoning work.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • -
    license
    B
    quality
    Not graded
    maintenance
    Enables AI-driven orchestration of GitHub development workflows including automated issue analysis, code generation, code review, and PR creation through multiple specialized agents. Integrates with GitHub Actions to automate the complete development process from issue to pull request.
    7
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to automate GitHub repository management, issue tracking, and commits using natural language.
    2 npm
    Apache 2.0