Mcp Forge — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Mcp Forge (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
New here? Start with the Getting Started Guide.
Scaffold, test, and publish Model Context Protocol (MCP) servers in seconds.
Building MCP servers involves too much boilerplate. Every new server needs the same JSON-RPC handling, tool definitions, resource handlers, Dockerfile, tests, and packaging config. You end up copying from old projects, fixing import paths, and wasting time on plumbing instead of building.
MCP Forge fixes this. One command generates a complete, ready-to-develop MCP server project. Another command tests it. Another validates compliance. Another publishes it.
mcp-forge template publish turns any scaffolded project into a registry entry others can installmcp-forge add tool|resource|prompt wires up new capabilities and their testspip install mcp-server-forgemcp-forge new my-server --tools weather,calculatorThat's it. You now have a complete, runnable MCP server:
my-server/
├── Dockerfile
├── README.md
├── pyproject.toml
├── .gitignore
├── src/
│ └── my_server/
│ ├── __init__.py
│ ├── server.py
│ ├── tools.py
│ ├── resources.py
│ └── prompts.py
└── tests/
└── test_my_server.pyProjects grow. Add tools, resources, or prompts to an existing project without hand-editing boilerplate:
cd my-server
mcp-forge add tool forecast alerts
mcp-forge add resource docs://readme
mcp-forge add prompt summarizeEach new tool gets a registry entry with input schema, a dispatch branch, a handler stub, and a generated test. Resources get a registry entry plus read tests; prompts get a definition, dispatch branch, handler stub, and get tests. If the project was scaffolded without resources or prompts, the server capability is wired into server.py automatically (import, initialize capabilities, and dispatch branches). The harness's expected lists are updated too, so pytest keeps passing while you fill in the real logic. Duplicate names, invalid names or URIs, and hand-mangled files are rejected with clear errors instead of corrupted code.
Every scaffolded project ships with a ready-to-run pytest harness in tests/: one mock JSON-RPC call per tool, initialize handshake checks, schema assertions, and error path coverage. It passes out of the box:
cd my-server
pip install -e '.[dev]'
pytest
# 11 passedYou can also exercise the server over real stdio with the black-box test runner:
mcp-forge test --cmd 'python -m my_server.server'┌──────────────────────────────────────────────────┐
│ MCP Forge Test Results │
├──────────────┬────────┬──────────────────────────┤
│ Test │ Status │ Details │
├──────────────┼────────┼──────────────────────────┤
│ server_start │ PASS │ Server started │
│ initialize │ PASS │ initialize response valid │
│ tools/list │ PASS │ Found 2 tools │
│ tools/call │ PASS │ Called 'weather' OK │
│ ping │ PASS │ Ping OK │
│ unknown │ PASS │ Correctly returned error │
│ server_stop │ PASS │ Server stopped cleanly │
├──────────────┴────────┴──────────────────────────┤
│ 7/7 passed All tests passed! │
└──────────────────────────────────────────────────┘mcp-forge dev ./my-serverStarts your server and watches the project for changes. Edit a file, and the server restarts automatically. If the server crashes, it gets revived. Stop with Ctrl+C.
# Custom launch command
mcp-forge dev ./my-server --cmd "uv run server.py"
# Watch different extensions or poll faster
mcp-forge dev ./my-server --ext py,yaml --interval 0.5By default it watches .py, .toml, .json, and .j2 files, skipping __pycache__, hidden directories, virtualenvs, and build output.
# Static structure checks
mcp-forge validate ./my-server
# Also boot the server and validate its live protocol responses
mcp-forge validate ./my-server --cmd 'python -m my_server.server'
# CI-friendly JSON report (exit code 1 on any error)
mcp-forge validate ./my-server --cmd 'python -m my_server.server' --jsonHand edits drift. mcp-forge doctor checks a scaffolded project in place and tells you exactly what to fix:
mcp-forge doctor ./my-server
# CI-friendly JSON report (exit code 1 on any error)
mcp-forge doctor ./my-server --jsonWhat it catches:
requires-python (for example a match statement in a 3.9 project)Every issue prints an actionable fix suggestion. Healthy projects exit 0:
🩹 Doctor: my-server
✗ Generated tests expect tools ['hello'] but the project defines ['hello', 'forecast'].
fix: Update the tools list assertion in test_my_server.py, or use 'mcp-forge add tool ...' next time so tests stay in sync.
19 checks run: 1 error(s), 0 warning(s)mcp-forge publish ./my-server
mcp-forge publish ./my-server --repository testpypi --dry-runmcp-forge register ./my-serverAdds your server to claude_desktop_config.json so Claude Desktop can launch it. The default config location is detected per platform (macOS, Linux, Windows), and everything else in the file is preserved.
# Preview the change without writing
mcp-forge register ./my-server --dry-run
# Custom launch command and server name
mcp-forge register ./my-server --name weather --cmd "uv run server.py"
# Overwrite an existing entry
mcp-forge register ./my-server --force
# Remove the entry again
mcp-forge register ./my-server --removeRestart Claude Desktop after registering to pick up the change.
The new command generates a complete MCP server with:
server.py with JSON-RPC request routingtools.pyresources.pyprompts.py (with --prompts)pyproject.toml configured with hatchlingDockerfile for containerized deploymentREADME.md with usage instructions.gitignoremcp-forge new my-server \
--tools weather,calculator,search \
--resources "file://data,http://api" \
--prompts summarize,code_review \
--description "My awesome MCP server" \
--author "Your Name" \
--output-dir ./projectsMCP Forge uses Jinja2 templates internally. Each generated file comes from a template in the templates/ directory:
| Template | Generates |
|---|---|
server.py.j2 | Main server with JSON-RPC routing |
tools.py.j2 | Tool definitions and handlers |
resources.py.j2 | Resource definitions and handlers |
prompts.py.j2 | Prompt definitions and handlers |
project_pyproject.toml.j2 | Package configuration |
project_readme.md.j2 | Project README |
dockerfile.j2 | Docker container config |
init.py.j2 | Package init file |
Start from a ready-made server template instead of a blank scaffold:
mcp-forge template list # Browse available templates
mcp-forge template show api-client # Inspect one template
mcp-forge template install api-client my-api # Install as a new projectBuiltin templates:
| Template | What you get |
|---|---|
starter | Minimal server with a single hello tool |
api-client | fetch and search tools plus a config resource, for wrapping HTTP APIs |
knowledge-base | lookup tool, doc resources, and summarize plus answer prompts |
Installed projects are normal scaffolded servers: the generated pytest harness passes out of the box, and templates can ship extra files (like setup notes) into the project.
Registries are plain JSON, so you can host your own and point at it with --registry:
mcp-forge template list --registry ./my-registry.json
mcp-forge template install team-server --registry https://example.com/registry.jsonA registry is an object with a templates list; each template has a name, version, description, author, its tools, resources, and prompts, and optional extra_files (relative paths mapped to file content, with {{project_name}} and {{pkg_name}} placeholders). Also available in Python via mcp_forge.marketplace: load_registry, get_template, and install_template.
Turn any scaffolded project into a shareable template without hand-writing registry JSON:
mcp-forge template publish ./my-weather-api -r team-registry.json
mcp-forge template publish ./my-weather-api -r team-registry.json \
-n wx-starter -i NOTES.md -i docs/usage.md # rename + embed extra filespublish reads the project name, version, description, and author from pyproject.toml, scans the source for its tools, resources, and prompts, and writes the entry into the registry file (created if missing). Files passed with --include are embedded with the project name swapped for {{project_name}}/{{pkg_name}} placeholders, so installs re-render them under the new name. Existing entries are preserved; republishing the same name requires --force. Use --json to print the published entry. In Python: build_template_from_project and publish_template.
mcp-forge gives you two layers of testing.
Generated pytest harness. Every mcp-forge new project includes an auto-generated tests/test_<pkg>.py that drives the server in-process with mock JSON-RPC requests: the initialize handshake, tools/list contents, a tools/call per scaffolded tool, input schema assertions, resource reads and prompt gets (when resources or prompts are scaffolded), and error paths for unknown tools, methods, resources, and prompts. Run it with pip install -e '.[dev]' && pytest, then extend the per-tool tests as you implement real logic.
Black-box test runner. mcp-forge test starts your MCP server as a subprocess and sends JSON-RPC requests over stdio, validating:
Add --json for a machine-readable report (pass/fail counts plus every result and raw response), with a nonzero exit code on failures for CI:
mcp-forge test --cmd 'python -m my_server.server' --jsonThe validate command checks your project for:
src/, pyproject.toml, server.py, tools.py)With --cmd, validation goes live: the server is booted over stdio and its actual responses are checked against the MCP schemas:
tools/list, resources/list, and prompts/list payloads match the specendpoint errors is an error; served items without a declared capability are a warning)
Add --json for a machine-readable report with a nonzero exit code on errors, ready for CI gates.
The publish command wraps build and twine for a smooth publishing experience:
# Build and publish to PyPI
mcp-forge publish .
# Dry run (build only)
mcp-forge publish . --dry-run
# Publish to TestPyPI
mcp-forge publish . --repository testpypiMake sure you have build and twine installed:
pip install mcp-server-forge[publish]The scaffolding uses Jinja2 templates internally. To customize the generated code, fork the repo and modify the templates in src/mcp_forge/templates/. The Jinja2 context includes:
project_name - the project name as givenpkg_name - Python package name (snake_case)title - human readable titledescription - project descriptionauthor - author nametools - list of tool namesresources - list of resource URI patternsprompts - list of prompt namesgit clone https://github.com/manasvardhan/mcp-forge.git
cd mcp-forge
pip install -e ".[dev]"
pytestMIT License. See LICENSE for details.
Built with 🔨 by Manas Vardhan
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.