Skip to main content

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, then agent-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)

Interactive (terminal): run with no arguments and use arrow keys to pick options:

uvx agent-easy-framework mcp
# after pip install agent-easy-framework:
agent-easy mcp
# or pick scaffold vs add-tool first:
agent-easy

One-liner (stdio + sample tool):

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 \
  --idp google

When --auth oidc, use --idp to pre-fill IdP URLs and ship setup docs:

--idp Use when
custom Any OIDC provider (default)
google Google / Google Cloud Identity
entra Microsoft Entra ID (Azure AD)
okta Okta

Generated projects include docs/auth/<idp>.md with copy-paste steps and a tailored config/profiles/prod.yaml.

Profile vs runtime: Generated servers default to the local profile (stdio, no auth). HTTP and OIDC settings apply when you run make run-http or make run PROFILE=prod — not plain make run.

Locked-down environments (no uvx):

pip install agent-easy-framework
agent-easy mcp billing-agent --datasources neo4j --auth oidc --idp custom

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.

Interactive: In a terminal, run uvx agent-easy-framework mcp (or agent-easy mcp after pip install agent-easy-framework) and use arrow keys to pick transports, auth, and IdP.

Flags:

uvx agent-easy-framework mcp billing-agent \
  --datasources postgres,neo4j \
  --transports stdio,http \
  --auth oidc \
  --idp google
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)
--idp custom, google, entra, okta custom Requires --auth oidc; fills OIDC URLs + docs/auth/<idp>.md
--profile any name local Default active profile in config/base.yaml; use PROFILE=prod at runtime or pass --profile prod here for prod-shaped defaults

Generate vs run: --profile sets the default in config/base.yaml. At runtime, override with make run PROFILE=prod or use make run-http (HTTP MCP uses the local-http profile).

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 run uses the active profile (local by default). The local profile forces stdio + no auth. Use PROFILE=prod or make run-http for 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 --idp custom
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 — or use --idp google|entra|okta at generate time):

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
      resource: https://mcp.example.com/mcp
      authorization_servers:
        - https://login.your-idp.com/

See generated docs/auth/<idp>.md for provider-specific OAuth client setup. Remote MCP clients discover auth via RFC 9728 metadata at /.well-known/oauth-protected-resource/mcp.

Step 3 — Install and run
cd billing-agent
make setup          # venv + minimal deps for your selection
make run            # serve with default profile (local = stdio, no auth)
make run PROFILE=prod   # HTTP/OIDC settings from generate flags
make run-http       # HTTP MCP only (local-http profile)
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 --idp google|entra|okta|custom"]
  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 \
  --idp custom
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 mcp SDK; tools registered via @tool with enforced typing and docstrings
  • Minimal deps — generator prunes what you did not select
  • YAML profiles — no environment variables; --profile CLI override
  • Pluggable providers — same pattern for secrets, auth, and data sources
  • Live docsmake docs serves 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_easy_framework-0.0.5.tar.gz (174.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_easy_framework-0.0.5-py3-none-any.whl (83.9 kB view details)

Uploaded Python 3

File details

Details for the file agent_easy_framework-0.0.5.tar.gz.

File metadata

  • Download URL: agent_easy_framework-0.0.5.tar.gz
  • Upload date:
  • Size: 174.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for agent_easy_framework-0.0.5.tar.gz
Algorithm Hash digest
SHA256 56579f3809a901700469fe3fd1436c5aa8d2a6135ae947190bd0bd4479a8992d
MD5 20dc357b8ad2e175f254b3d622377734
BLAKE2b-256 3ea3136767b04741c405b09be462da255bcd5c6ab58790959f61d016bc373eaf

See more details on using hashes here.

File details

Details for the file agent_easy_framework-0.0.5-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_easy_framework-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 fc4a33303d7ffa2bbf6e596efa3e933193b04a491e9fb7c41407ec58b3388650
MD5 4289a6ede5a937d43ddddbf466c93cf4
BLAKE2b-256 ecd7f49e7f3f21699b0217983caace96e670f3fa9bcc0534e83e7848ace11bb8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page