Metadata-Version: 2.4
Name: agent-easy-framework
Version: 0.0.5
Summary: Enterprise golden-path framework for scaffolding MCP-first agent servers in Python.
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.110.0
Requires-Dist: mcp>=1.2.0
Requires-Dist: pydantic>=2.6.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: uvicorn>=0.29.0
Provides-Extra: all
Requires-Dist: asyncpg>=0.29.0; extra == 'all'
Requires-Dist: grpcio>=1.62.0; extra == 'all'
Requires-Dist: httpx>=0.27.0; extra == 'all'
Requires-Dist: neo4j>=5.18.0; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
Requires-Dist: vulture>=2.11; extra == 'dev'
Provides-Extra: grpc
Requires-Dist: grpcio>=1.62.0; extra == 'grpc'
Provides-Extra: neo4j
Requires-Dist: neo4j>=5.18.0; extra == 'neo4j'
Provides-Extra: oidc
Requires-Dist: httpx>=0.27.0; extra == 'oidc'
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'oidc'
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
Description-Content-Type: text/markdown

# 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)](https://modelcontextprotocol.io). 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:

```bash
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):**

```bash
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:

```bash
cd my-service
uvx agent-easy-framework mcp add-tool echo_reply
make check
```

Or from the project Makefile (same command, requires network):

```bash
cd my-service
make add-tool TOOL=echo_reply
make check
```

Full options:

```bash
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`):

```bash
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](GOLDEN_PATH.md) — the contract every generated server follows |
| **Copy-paste examples** | [examples/README.md](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:

```bash
make setup
make example          # Flow 1: ping in-process — no server (~5 seconds)
```

Call the tool over HTTP MCP (two terminals):

```bash
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](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.

```mermaid
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
```

<details>
<summary><strong>Step 1 — Generate your server</strong></summary>

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:**

```bash
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:

```bash
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:

```bash
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`):

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

</details>

<details>
<summary><strong>Step 2 — Configure profiles and secrets</strong></summary>

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:

```bash
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:

```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):

```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
      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`.

</details>

<details>
<summary><strong>Step 3 — Install and run</strong></summary>

```bash
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 |

</details>

<details>
<summary><strong>Step 4 — Add your tools</strong></summary>

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):

```python
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`:

```python
from billing_agent.core.tools import invoice as invoice
```

Restart the server. Your tool appears in `make docs` and every transport automatically.

</details>

<details>
<summary><strong>Step 5 — Verify and ship</strong></summary>

Every generated project includes the same quality gates:

```bash
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.

</details>

---

## How a request flows

When an MCP client calls your server, everything funnels through one registry — transports are thin adapters.

```mermaid
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.

```mermaid
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)

```mermaid
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)

```bash
uvx agent-easy-framework mcp graph-agent \
  --datasources neo4j \
  --transports stdio,http \
  --auth oidc \
  --idp custom
```

```bash
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 docs** — `make 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:

```bash
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](GOLDEN_PATH.md) for the full architectural contract.

---

## License

MIT — see [LICENSE](LICENSE).
