📝 plain-English description
│
▼
🤖 Groq (llama-3.3-70b) designs a structured tool spec (JSON)
│
▼
✅ spec validated — identifiers, param types, tool count
│
▼
⚙️ codegen renders server.py (official `mcp` SDK / FastMCP),
requirements.txt, README.md, and a test stub
│
▼
📦 CLI project folder — or downloadable .zip from the web UI
Every generated tool is a stub that raises NotImplementedError with a # TODO describing what to build — MCP Maker designs the interface, you fill in the logic.
Add --implement to have a second LLM pass write an actual implementation for each tool instead of leaving a stub:
python cli/mcp_maker.py generate \
--desc "A weather tool that fetches current conditions and a 5-day forecast for a city" \
--out ./weather-mcp \
--implement🔒 Six gates per attempt (up to 3 attempts, feeding failures back to the LLM each time):
| # | Gate | What it catches |
|---|---|---|
| 1️⃣ | Generate | LLM writes a candidate function body |
| 2️⃣ | Policy check 🛡️ | AST-walk allowlist (not denylist) — only os, requests, json, re, time, datetime, math, typing, urllib; no eval/exec/open/os.system/subprocess/socket |
| 3️⃣ | Syntax check ✔️ | ast.parse() on the assembled function |
| 4️⃣ | Semantic check 🔍 | Generated params must exactly match the spec (catches silent renames like city → zip_code) |
| 5️⃣ | Sandboxed smoke test 🧪 | Runs the function in a subprocess with requests mocked, dummy args, 5s timeout — catches real bugs like resp.json()["temperature"] on a missing key |
| 6️⃣ | Self-review 🕵️ | A second LLM call reviews the code against the description and can reject it even if it runs cleanly |
If a tool never clears all six after 3 attempts, it falls back to the original NotImplementedError stub with the failure reason in a comment — nothing broken or unsafe ships silently.
⚠️ Not a full correctness guarantee. The sandbox mocks the network and only exercises one input; self-review is an LLM opinion, not proof. Treat--implementoutput as a reviewed, smoke-tested first draft — read it and test it against the real API before production.
|
💻 CLI pip install -r requirements.txt
export GROQ_API_KEY="your_key"
python cli/mcp_maker.py generate \
--desc "A weather tool: current \
conditions + 5-day forecast" \
--out ./weather-mcp |
🌐 Web UI cd web/backend
export GROQ_API_KEY="your_key"
uvicorn main:app --reload --port 8001Open |
| Layer | Tech |
|---|---|
| 🤖 LLM | Groq llama-3.3-70b-versatile — designs the spec only, never writes code directly |
| 🔌 MCP SDK | Official mcp Python package (FastMCP) |
| ⚡ Backend | FastAPI |
| 🎨 Frontend | Static HTML / JS, no build step |
core/
spec_generator.py 📝 plain-English → validated JSON tool spec (via Groq)
codegen.py ⚙️ spec → server.py, README.md, requirements.txt, tests
implementer.py 🔒 --implement: 6-gate checked code generation
cli/
mcp_maker.py 🖥️ CLI entry point
web/
backend/main.py ⚡ FastAPI: /generate, /download/{id}
frontend/index.html 🎨 UI
tests/ ✅ pytest suite (no live LLM call required)
The LLM only produces the spec (tool names, params, descriptions) — a small, easily validated JSON object. The actual Python skeleton is rendered deterministically from that spec by codegen.py, so generated servers are always syntactically valid (checked via compile() in CI) even though the tool design comes from an LLM. The --implement pass is the one place raw LLM-written code enters the pipeline, and it's the part gated by all six checks above.
export GROQ_API_KEY=dummy
pytest tests/ -vCovers spec validation, code generation, and all six --implement gates (policy, syntax, semantic, sandbox, review) — no live LLM call required, everything is mocked.
- The sandboxed smoke test mocks the network with a generic
{}response — it proves the code runs, not that it matches the real API's exact response shape (e.g. a missing required query param can still pass the sandbox but silently return empty data against the real API). - No persistent state — tools that need to "remember" things across calls (todo lists, counters) need storage wired in manually.
- OAuth-based APIs (Gmail, Slack, etc.) aren't supported — the pipeline assumes simple key-based or keyless REST APIs.