Skip to main content
Glama
khuber
by khuber

dangerzone-mcp

A Python example of a self-modifying MCP server, built on the official MCP Python SDK. The agent connected to it can write a new tool, call it, fix it, and find it still there in the next session.

The server has three permanent tools: add_tool, edit_tool, and remove_tool. Everything else in the catalog is Python that arrived at runtime, usually written by the agent, saved in a JSON file in your project.

The name is a reminder that this runs model-written Python on your machine with your permissions. Read Trust before pointing it at anything you care about.

What it looks like

Claude Code creating a square tool, editing it to cube, and calling it again after a restart

Register the server, then ask for a tool:

Use dangerzone to create a tool that squares a number. Call it with 7, then edit it to cube numbers and call it again.

The agent calls add_tool with Python source and an input schema. The server saves the definition and notifies the client that its tool list changed. Calling square with 7 returns 49; after edit_tool changes it to cube numbers, the same call returns 343. Restarting the server restores the edited tool. remove_tool takes it out of the catalog when it is no longer needed.

Each call validates its arguments and runs the Python code in a fresh worker, with a 30-second timeout by default (--timeout SECONDS). Failures return tool errors so the session can continue.

Related MCP server: JIT Tool Synthesis

Register

Install uv and Git, then clone the repository and read it. The server runs on your machine with your permissions, and there is no install path that skips that step on purpose.

git clone https://github.com/khuber/dangerzone-mcp.git
cd dangerzone-mcp && uv sync

Claude Code

From the checkout:

claude mcp add --transport stdio --scope user dangerzone -- \
  uv run --project "$PWD" dangerzone-mcp

This makes the server available across your projects. Run /mcp in Claude Code to check the connection. Each project keeps its own catalog as described under Persistence. Updating is a git pull in the checkout followed by a reconnect; nothing changes until you do that.

Other MCP clients

For clients that accept mcpServers JSON and refresh tools after change notifications, replace the path with your checkout:

{
  "mcpServers": {
    "dangerzone": {
      "command": "uv",
      "args": [
        "run",
        "--project", "/absolute/path/to/dangerzone-mcp",
        "dangerzone-mcp"
      ]
    }
  }
}

See client compatibility for the Codex limitation. The setup guide covers registration scopes, server options, updates, and troubleshooting.

Persistence

Tools survive restarts in a project-local dangerzone.tools.json. The server uses the containing Git root, or the starting directory outside Git. Clients start it in the project directory; --project-dir PATH overrides the starting point. Add --no-persist to the server command to keep tools in memory for one process.

Keep personal catalogs out of Git, or deliberately commit reviewed tools to share them. See the catalog reference for the file format, recovery behavior, and ignore entries.

Trust

Workers are process separation, not a sandbox. Tool code has the server user's file, network, and process access. That is fine for tools I asked for on my own laptop and not fine for much else. To run code you do not trust, put the workers under a different OS user or in a container with the server package read-only.

Persistence adds a second consideration. A repository you clone can arrive with a dangerzone.tools.json already in it, written by whoever committed it, and the agent uses the tool descriptions in that file to decide what to call. Treat a catalog you did not write the way you would treat a Makefile from a stranger: read the source and the descriptions before enabling it, or start the server with --no-persist so it never loads.

Client compatibility

The add-then-call workflow requires a client that refreshes its tool list after change notifications. Codex has a reported issue where tools added after initial discovery never become callable in the task, including in later turns: openai/codex#43642. Codex setup examples are omitted until this workflow is verified to work there.

For implementation details and limitations, see the reference. For development setup and checks, see the setup guide.

Built on the MCP Python SDK 2.2 against the 2026-07-28 spec. MIT licensed.

Available Tools

3 tools
add_toolA

Add a new Python tool. Use edit_tool to change an existing tool. source must define main(arguments), sync or async, returning JSON. input_schema describes the arguments object using JSON Schema 2020-12. The add_tool, edit_tool and remove_tool built-ins are permanent. Code executes with the server user's OS permissions.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
sourceYes
descriptionYes
input_schemaYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
statusYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already indicate readOnlyHint=false, so mutation is expected. The description adds meaningful behavioral context: source must define main(arguments), be sync or async, return JSON, and code executes with the server user's OS permissions. It also discloses that add_tool, edit_tool, and remove_tool are permanent built-ins.

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 with no filler. The core purpose is front-loaded, followed by the sibling distinction and then the key technical constraints, making it highly scannable.

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 tool-definition operation with four required parameters and a nested input_schema, the description covers the critical contract: function signature, sync/async support, return type, JSON Schema version, OS permissions, and built-in permanence. With an output schema present, return-value documentation is not needed. It lacks an explicit note about name uniqueness but is otherwise substantial.

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 0%, so the description must compensate. It does add essential semantics for source and input_schema: source must define main(arguments) and return JSON, and input_schema uses JSON Schema 2020-12. However, it provides no additional meaning for the name or description parameters beyond their schema constraints.

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: 'Add a new Python tool.' It clearly distinguishes itself from siblings by explicitly saying 'Use edit_tool to change an existing tool,' so an agent can tell add_tool apart from edit_tool and remove_tool.

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?

The description gives explicit guidance: use this tool to add a new tool, and use edit_tool to change an existing one. It also notes that built-in tools are permanent, which warns against attempting to remove or edit them.

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

edit_toolA
DestructiveIdempotent

Replace an existing custom tool's description, input_schema, and Python source. Supply all fields; the name identifies the tool. Invalid edits leave the old tool intact. The add_tool, edit_tool and remove_tool built-ins cannot be edited.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
sourceYes
descriptionYes
input_schemaYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
statusYes

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, and the description adds a real behavioral guarantee: 'Invalid edits leave the old tool intact,' implying atomic replacement. It also discloses that the management built-ins cannot be edited, which is beyond the schema and helps prevent failed calls. There is no contradiction with the annotations.

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 action and followed by the key caveats. It contains no filler and keeps the important guarantees (atomic invalid edits, protected built-ins) compactly grouped.

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

Completeness3/5

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

For a mutation tool with four required parameters and a nested object, the description covers the core replace semantics and failure atomicity, and the presence of an output schema reduces the need to explain return values. It still leaves gaps around the exact form of `input_schema` and what constitutes a 'valid' edit versus an invalid one, as well as what happens if the named tool does not exist. Given the tool's complexity, these gaps prevent a higher score.

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?

With 0% schema description coverage, the description must work harder. It connects three parameters to the operation ('description, input_schema, and Python source') and clarifies that `name` identifies the tool and all fields are required ('Supply all fields'). It does not, however, explain the expected structure of `input_schema` or the Python source format, so a meaningful parameter burden remains.

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 'Replace an existing custom tool's description, input_schema, and Python source,' a specific verb-plus-resource statement that names exactly what changes. It also states the name's identifying role and explicitly notes the built-in tools it cannot touch, which differentiates it from add_tool and remove_tool.

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 scopes the tool to existing custom tools ('Replace an existing custom tool's...'), giving the agent a context for when to invoke it, and explicitly excludes the built-ins add_tool, edit_tool, and remove_tool from being edited. It does not, however, name add_tool or remove_tool as alternatives for create/delete cases, so the guidance is mostly contextual rather than a full when/when-not matrix.

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

remove_toolA
Destructive

Remove a custom tool. The add_tool, edit_tool and remove_tool built-ins can never be removed.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
statusYes

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true, so the agent knows this is a destructive operation. The description adds the important behavioral constraint that built-in tools cannot be removed, which is valuable context beyond the annotations. However, it doesn't disclose what happens if the tool doesn't exist or whether removal is reversible.

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 a single sentence that states the core action and the key constraint. It is front-loaded with the verb and resource, and every word earns its place. No fluff or redundancy.

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 simple one-parameter destructive tool, the description plus annotations cover the essential context: what it does, what it cannot remove, and that it is destructive. The output schema exists, so return values are presumably documented there. The only minor gap is lack of error behavior (e.g., nonexistent tool), but this is not critical for a simple removal tool.

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 0%, so the description carries the burden for parameter semantics. The description mentions 'custom tool' and the schema says 'The exact name of a custom tool to remove,' which together clarify that the 'name' parameter must be the exact name of a custom tool. However, the description itself doesn't add much beyond the schema's own description, and the schema's description is the primary source of parameter meaning.

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

Purpose4/5

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

The description clearly states the action ('Remove a custom tool') and identifies the resource being acted upon. It also distinguishes itself from siblings by noting that built-in tools (add_tool, edit_tool, remove_tool) are protected from removal, which helps an agent understand the tool's scope and limitations.

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 this tool (to remove a custom tool) and explicitly states an exclusion: built-in tools can never be removed. It doesn't explicitly name alternatives, but the sibling list (add_tool, edit_tool) makes the context clear. The protected built-ins note serves as a when-not-to-use guideline.

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. 3 tool updatesv0.1.0
    • First observedadd_tool
    • First observededit_tool
    • First observedremove_tool

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool targets a distinct lifecycle stage: add_tool creates, edit_tool modifies an existing tool, and remove_tool deletes one. There is no realistic overlap or ambiguity between these operations.

Naming Consistency5/5

All three tool names follow the same verb_noun pattern in lowercase snake_case: add_tool, edit_tool, remove_tool. The naming is perfectly consistent and immediately indicates each tool's purpose.

Tool Count5/5

Three tools is minimal but exactly right for a self-modifying tool server: create, update, and delete. There is no unnecessary duplication or bloat.

Completeness4/5

The core add/edit/remove lifecycle is covered, and tool discovery is available through MCP's normal tool-listing mechanism. The only minor gap is that there is no way to retrieve a custom tool's Python source after it has been added, which can make edit_tool awkward if the source was not retained externally.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to programmatically create, manage, and execute independent Python workflow scripts with full CRUD operations, allowing AI to build and modify automation workflows themselves rather than just executing pre-built ones.
    6
    2
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Provides persistent SQLite-based memory and unified tool abstraction for AI agents to support long-term context and complex tool chaining. It enables automated code analysis, file operations, and environment discovery through a standardized interface.
    5
    1
    MIT