Metadata-Version: 2.4
Name: agent-easy-framework
Version: 0.0.3
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)

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

Locked-down environments (no `uvx`):

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

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

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

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

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

</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
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 |

</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"]
  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
```

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