Skip to main content
Glama
README.md
# mcp-toolforge

A **meta-MCP server** that generates new MCP servers from natural-language tool descriptions.

Given a project name, a short description, and a list of natural-language tool
descriptions (e.g. `"fetches the weather for a string city and returns a string summary"`),
mcp-toolforge writes a **complete, runnable MCP server project** — schema, implementation,
tests with real assertions, README, LICENSE — ready to install and run.

<!-- BEGIN-ARCHITECTURE -->
```mermaid
flowchart TD
    subgraph Client_Layer["AI Client / Claude Desktop"]
        A["Client (Claude, Cursor, etc.)"]
    end
    subgraph Meta_Server["mcp-toolforge (this repo)"]
        M["mcp_toolforge.server"]
        G["mcp_toolforge.generator"]
    end
    subgraph Generated["Generated Server Project"]
        P["src/<pkg>/__init__.py"]
        S["src/<pkg>/server.py"]
        T["tests/test_<pkg>.py"]
        R["README.md"]
        L["LICENSE"]
        PP["pyproject.toml"]
    end

    A -- "MCP stdio JSON-RPC" --> M
    M -- "generate_server tool call" --> G
    G -- "writes files" --> P
    G -- "writes files" --> S
    G -- "writes files" --> T
    G -- "writes files" --> R
    G -- "writes files" --> L
    G -- "writes files" --> PP
```
<!-- END-ARCHITECTURE -->

## Architecture

```
┌─────────────────────┐     ┌──────────────────────────┐
│   AI Client         │  stdio  │  mcp-toolforge server  │
│ (Claude, Cursor)    │──JSON──│  (this repo)           │
└─────────────────────┘  RPC    └────────┬───────────────┘
                                          │ generate_server
                                          │  (name, description,
                                          │   tool_descriptions, dest)
                                          ▼
                        ┌────────────────────────────────────┐
                        │  generator.generate_project()      │
                        │  parses NL → ToolSpec → ServerSpec │
                        │  renders: pyproject, server.py,    │
                        │  tests, README, LICENSE            │
                        └────────────────────────────────────┘
                                          │
                        ┌─────────────────┴─────────────────┐
                        │  Example generated servers         │
                        │  • examples/weather_server         │
                        │  • examples/todo_server            │
                        │  • examples/math_server            │
                        └────────────────────────────────────┘
```

## Quickstart

### Install mcp-toolforge

```bash
pip install -e ".[dev]"
```

### Run mcp-toolforge itself (meta-server)

As an MCP server (stdio transport):

```json
{
  "mcpServers": {
    "mcp-toolforge": {
      "command": "python",
      "args": ["-m", "mcp_toolforge.server"],
      "cwd": "/path/to/mcp-toolforge"
    }
  }
}
```

Or as a CLI that generates a standalone server project:

```bash
# Interactive wizard
mcp-toolforge -i

# One-shot
mcp-toolforge \
  --name my_server \
  --description "A server that does X" \
  --tool "fetches the weather for a string city and returns a string summary" \
  --dest ./my_server
```

### Using the `generate_server` tool

When mcp-toolforge is registered as an MCP server, an AI agent can call:

```
generate_server(
  name="my_server",
  description="A server that does X",
  tool_descriptions=[
    "fetches the weather for a string city and returns a string summary",
    "adds a string task and returns a string confirmation"
  ],
  dest="/path/to/output"  # optional, defaults to /tmp/mcp-toolforge-gen
)
```

The tool writes a complete project to `dest/<package_name>/` and returns a
summary string. The generated server can then be installed and registered
with your MCP client independently.

## How natural-language parsing works

Each tool description should follow the pattern:

```
<VERB> [a/an] <type> <name> [, <type> <name>] ... and returns <type> <description>
```

Examples:

| Description | Tool name | Params |
|---|---|---|
| `fetches the weather for a string city and returns a string summary` | `fetch` | `city: string` |
| `adds a string task and returns a string confirmation` | `add` | `task: string` |
| `multiplies two numbers given a number a and number b and returns a number product` | `multiply` | `a: number, b: number` |
| `lists all todos and returns an array of todo items` | `list` | `query: string` (fallback) |

Recognized parameter types: `string`, `integer`, `number`, `boolean`, `array`.
If no typed parameters are detected, a free-form `query: string` parameter is
inferred.

## Examples

Three example servers are generated into `examples/`:

| Server | Package | Tools | Description |
|---|---|---|---|
| WeatherServer | `weather_server` | `fetch`, `forecast` | Fetches weather info |
| TodoServer | `todo_server` | `add`, `list`, `remove` | Manages a todo list |
| MathServer | `math_server` | `add`, `multiply`, `compute` | Arithmetic tools |

Each example is a fully working MCP server with its own tests:

```bash
cd examples/math_server
pip install -e .
pytest
```

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run all tests
pytest

# Run end-to-end test against the meta-server over stdio
python e2e_test.py

# Regenerate examples
python make_examples.py
```

## Testing

- `tests/test_generator.py` — 16 tests for the generator (parsing, schema inference, file rendering, project creation)
- `tests/test_server.py` — 5 tests for the meta-MCP server (tool listing, tool calling, error handling)
- `e2e_test.py` — end-to-end test that runs the meta-server as a real stdio subprocess and connects with an MCP `Client`
- Each example server ships with 4 tests (12 total across 3 examples)

**All tests use real assertions and verify actual file output / tool results.**

## License

MIT — see [LICENSE](LICENSE).