Enterprise golden-path framework for scaffolding MCP-first agent servers in Python.
Project description
agent-easy
Scaffold production-ready MCP servers in Python — without inventing the plumbing.
You want agents to call your tools over the Model Context Protocol (MCP). You do not want to wire up transports, config, secrets, auth, health checks, and lint gates from scratch every time.
This framework generates a complete, typed, testable MCP server project you own. Run one command, configure YAML profiles, add your tools, ship.
PyPI package:
agent-easy-framework· CLI:agent-easy(pip install agent-easy-framework, thenagent-easy mcp …)
You do not import this as a library at runtime. It is a generator (like JHipster or
npx create-*). The output is a standalone repo your team maintains.
Quickstart (no clone)
uvx agent-easy-framework mcp my-service
cd my-service && make setup && make example
That scaffolds a stdio MCP server with a sample ping tool and runs it in-process (~5 seconds). Attach an MCP client with make run when ready.
Add another tool endpoint:
cd my-service
uvx agent-easy-framework mcp add-tool echo_reply
make check
Or from the project Makefile (same command, requires network):
cd my-service
make add-tool TOOL=echo_reply
make check
Full options:
uvx agent-easy-framework mcp billing-agent \
--datasources postgres,neo4j \
--transports stdio,http \
--auth oidc
Locked-down environments (no uvx):
pip install agent-easy-framework
agent-easy mcp billing-agent --datasources neo4j --auth oidc
At a glance
| What it generates | An MCP-first Python server with tools, data sources, auth, and ops endpoints |
| Who it is for | Engineers shipping agent tools to Claude Desktop, IDEs, or internal platforms |
| Config model | YAML profiles (Spring-style). No environment variables |
| Quality bar | mypy --strict, ruff, dead-code detection, golden-path fact-checks baked in |
| Deep reference | GOLDEN_PATH.md — the contract every generated server follows |
| Copy-paste examples | examples/README.md — call ping, curl ops, browse live docs |
Try it now (reference server)
For contributors or anyone exploring the generator source, clone this repo:
make setup
make example # Flow 1: ping in-process — no server (~5 seconds)
Call the tool over HTTP MCP (two terminals):
make run-http # terminal 1
make example-http # terminal 2 — Streamable HTTP client, not curl
./examples/smoke_ops.sh # optional: ops REST at :8080
Full walkthrough: examples/README.md.
Your journey (start to shipped)
Follow this path whether you are new to MCP or just do not want to rebuild the same skeleton again.
flowchart LR
subgraph step1 [1. Generate]
gen["uvx agent-easy-framework mcp …"]
end
subgraph step2 [2. Configure]
yaml["YAML profiles + secrets"]
end
subgraph step3 [3. Run]
run["make run / make docs"]
end
subgraph step4 [4. Extend]
tools["Add @tool handlers"]
end
subgraph step5 [5. Ship]
ci["make check + CI"]
end
gen --> yaml --> run --> tools --> ci
Step 1 — Generate your server
Pick only what you need. Unused providers and transports are pruned so dependencies stay minimal.
uvx agent-easy-framework mcp billing-agent \
--datasources postgres,neo4j \
--transports stdio,http \
--auth oidc
| Flag | Options | Default | When to use |
|---|---|---|---|
--output, -o |
directory path | . |
Parent folder for the new project |
--package |
Python identifier | derived from name | Override the import package name |
--datasources |
postgres, neo4j |
none | Your tools need a database |
--transports |
stdio, http, grpc |
stdio |
stdio = local/IDE; http = deployed; grpc = custom adapter |
--auth |
none, oidc, basic |
none |
oidc for SSO in prod; basic is testing only (runtime API key) |
--profile |
any name | local |
Default active profile in config/base.yaml |
Add a tool to an existing project
Run from the project root (or pass -C). Requires uvx and the published agent-easy-framework package:
cd my-service
uvx agent-easy-framework mcp add-tool echo_reply
uvx agent-easy-framework mcp add-tool send_invoice -d "Create and send a customer invoice."
make check
Or use the Makefile wrapper:
make add-tool TOOL=echo_reply
make check
Profile note:
make runuses the active profile (localby default). Thelocalprofile forces stdio + no auth. UsePROFILE=prodormake run-httpfor HTTP/OIDC settings from generate flags.
Locked-down environments (no uvx):
pip install agent-easy-framework
agent-easy mcp billing-agent --datasources neo4j --auth oidc
Step 2 — Configure profiles and secrets
Generated layout:
billing-agent/
config/
base.yaml # shared defaults + active_profile
profiles/
local.yaml # deep-merged on top of base
prod.yaml
secrets/ # file-based secret provider (gitignored)
neo4j/password
Profiles — Spring-style. One knob at runtime:
billing-agent run # uses active_profile from base.yaml
billing-agent run --profile prod # override
Secrets — never committed as raw values. Reference them in YAML:
password: ${secret:neo4j/password}
Create the file: secrets/neo4j/password (or plug in Vault / cloud providers later).
OIDC example (config/profiles/prod.yaml):
server:
auth:
provider: oidc
options:
issuer: https://login.your-idp.com/
audience: billing-agent
jwks_uri: https://login.your-idp.com/.well-known/jwks.json
Step 3 — Install and run
cd billing-agent
make setup # venv + minimal deps for your selection
make run # serve with default profile
make run PROFILE=prod
make docs # live docs site from your tool registry (nothing committed)
Ops endpoints (for load balancers / k8s) — default 127.0.0.1:8080:
| Endpoint | Purpose |
|---|---|
GET /health |
Liveness — process is up |
GET /ready |
Readiness — all data sources healthy |
GET /admin/tools |
Registered tools and descriptions |
Other default ports:
| Surface | Default | Notes |
|---|---|---|
| MCP (HTTP) | 8000 at /mcp |
Streamable HTTP when --transports http |
| Live docs | 8090 |
make docs — registry-generated, not committed |
Step 4 — Add your tools
A tool is an async function with a typed Pydantic input model. The docstring becomes the MCP description.
Create src/billing_agent/core/tools/invoice.py (requires --datasources postgres in Step 1):
from pydantic import BaseModel, Field
from billing_agent.core.context import AppContext
from billing_agent.core.registry import tool
class LookupInput(BaseModel):
invoice_id: str = Field(description="Invoice ID to fetch.")
class LookupOutput(BaseModel):
total: float
status: str
@tool
async def lookup_invoice(params: LookupInput, ctx: AppContext) -> LookupOutput:
"""Fetch an invoice total and status from the primary database."""
db = ctx.datasource("primary") # name from config/server.datasources
rows = await db.fetch("SELECT total, status FROM invoices WHERE id = $1", params.invoice_id)
row = rows[0]
return LookupOutput(total=row["total"], status=row["status"])
Register it in src/billing_agent/core/tools/__init__.py:
from billing_agent.core.tools import invoice as invoice
Restart the server. Your tool appears in make docs and every transport automatically.
Step 5 — Verify and ship
Every generated project includes the same quality gates:
make check # lint + type + deadcode + golden-path fact-checks
make test # unit + smoke tests
CI in this repo runs the same checks on pull requests. Your generated project ships with pre-commit hooks ready to enable.
How a request flows
When an MCP client calls your server, everything funnels through one registry — transports are thin adapters.
sequenceDiagram
participant Client as MCP Client
participant Transport as Transport adapter
participant Auth as Auth provider
participant Registry as Tool registry
participant Tool as Your @tool handler
participant DS as Data source
Client->>Transport: call_tool(name, arguments)
alt HTTP or gRPC
Transport->>Auth: validate Bearer token
Auth-->>Transport: Principal
end
Transport->>Registry: invoke_tool(name, args)
Registry->>Tool: handler(params, ctx)
Tool->>DS: query (optional)
DS-->>Tool: result
Tool-->>Registry: Pydantic output
Registry-->>Transport: JSON payload
Transport-->>Client: MCP response
stdio skips auth (trusted local channel). HTTP and gRPC enforce the configured provider.
Architecture inside your generated server
One core, multiple ways in. You write tools once; every transport exposes them.
flowchart TB
subgraph adapters [Transport adapters]
stdio[stdio]
http["Streamable HTTP"]
grpc[gRPC adapter]
end
subgraph ops [FastAPI surfaces]
health["/health · /ready · /admin"]
docs["Live docs server"]
end
subgraph core [Transport-agnostic core]
tools[Tool registry]
ds[Data source registry]
ctx[AppContext]
end
subgraph cfg [Config layer]
yaml[YAML profiles]
sec[Secret providers]
auth[Auth providers]
end
stdio --> core
http --> core
grpc --> core
ops --> core
core --> cfg
ds --> postgres[(PostgreSQL)]
ds --> neo4j[(Neo4j)]
FastAPI powers ops endpoints and the live docs server (make docs). MCP traffic uses the official mcp SDK (stdio) or Starlette (Streamable HTTP). gRPC is a custom adapter over the same tool registry.
Choose your stack (decision guide)
flowchart TD
start([I need an MCP server]) --> local{Local dev only?}
local -->|Yes| stdio["transports: stdio"]
local -->|No| http["transports: stdio,http"]
http --> db{Need a database?}
db -->|Postgres| pg["--datasources postgres"]
db -->|Graph| neo["--datasources neo4j"]
db -->|Both| both["--datasources postgres,neo4j"]
db -->|No| none["--datasources omitted"]
http --> auth{Production auth?}
auth -->|SSO| oidc["--auth oidc"]
auth -->|Quick local test| noneAuth["--auth none"]
auth -->|Never prod| basic["--auth basic · testing only"]
stdio --> done([make setup && make run])
pg --> done
neo --> done
both --> done
none --> done
oidc --> done
noneAuth --> done
basic --> done
Example: Neo4j + OIDC (production-shaped)
uvx agent-easy-framework mcp graph-agent \
--datasources neo4j \
--transports stdio,http \
--auth oidc
cd graph-agent
mkdir -p secrets/neo4j
echo 'your-password' > secrets/neo4j/password
make setup && make run PROFILE=prod
Point config/profiles/prod.yaml at your IdP and Neo4j bolt URI. HTTP clients send Authorization: Bearer <jwt>.
What you get out of the box
- MCP-first — official
mcpSDK; tools registered via@toolwith enforced typing and docstrings - Minimal deps — generator prunes what you did not select
- YAML profiles — no environment variables;
--profileCLI override - Pluggable providers — same pattern for secrets, auth, and data sources
- Live docs —
make docsserves a registry-generated site; nothing committed - Quality gates — ruff,
mypy --strict, vulture, custom fact-checks, pytest smoke test
Generated project commands
| Command | What it does |
|---|---|
make setup |
Create venv, install deps |
make example |
Call ping in-process (fast validation, no server) |
make run |
Run server (PROFILE=prod to override) |
make run-http |
Run HTTP MCP transport (when generated with --transports http) |
make example-http |
Call ping over HTTP MCP (when generated with --transports http) |
make docs |
Serve live documentation |
make check |
Lint + type + deadcode + golden-path fact-checks |
make factcheck |
Golden-path invariants only |
make test |
Run tests |
make fmt |
Auto-format |
make all |
check + test |
Contributing to this framework
For maintainers working on the generator itself:
git clone https://github.com/KazzyAPI/agent-easy.git
cd agent-easy
make setup # sync templates + venv + dev deps
make check && make test
make sync-templates # refresh bundled templates before publishing
See GOLDEN_PATH.md for the full architectural contract.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_easy_framework-0.0.4.tar.gz.
File metadata
- Download URL: agent_easy_framework-0.0.4.tar.gz
- Upload date:
- Size: 160.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1b4c383f5e0f429c9a9b5fce619758eed1e49834b8a8c7b68ae97bba2abbc1d
|
|
| MD5 |
eef1a3bea49587353e7aecccdd33e4ed
|
|
| BLAKE2b-256 |
cd842a517f336ac6543c7a21e3969e229e7a32adebf593049ed1f931ee9e5ae5
|
File details
Details for the file agent_easy_framework-0.0.4-py3-none-any.whl.
File metadata
- Download URL: agent_easy_framework-0.0.4-py3-none-any.whl
- Upload date:
- Size: 72.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61d0e55cde1a451f6a5c81908ec3b1e5ae814682f755d37f47e30133ce6b13b2
|
|
| MD5 |
8e1abad0abed4888d20621b1198a320e
|
|
| BLAKE2b-256 |
7c9bf45cc9cda6169456ff41218f9410bd8c857a09380e17ae9f4ee67ebde70e
|