agent-easy-framework 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_easy_framework-0.0.3.dist-info/METADATA +499 -0
- agent_easy_framework-0.0.3.dist-info/RECORD +68 -0
- agent_easy_framework-0.0.3.dist-info/WHEEL +4 -0
- agent_easy_framework-0.0.3.dist-info/entry_points.txt +2 -0
- agent_easy_framework-0.0.3.dist-info/licenses/LICENSE +21 -0
- agent_server/__about__.py +3 -0
- agent_server/__init__.py +13 -0
- agent_server/__main__.py +8 -0
- agent_server/auth/__init__.py +1 -0
- agent_server/auth/base.py +67 -0
- agent_server/auth/basic.py +95 -0
- agent_server/auth/none.py +28 -0
- agent_server/auth/oidc.py +114 -0
- agent_server/bootstrap.py +32 -0
- agent_server/checks/__init__.py +12 -0
- agent_server/checks/invariants.py +324 -0
- agent_server/cli.py +56 -0
- agent_server/config/__init__.py +1 -0
- agent_server/config/loader.py +102 -0
- agent_server/config/schema.py +61 -0
- agent_server/config/secrets/__init__.py +1 -0
- agent_server/config/secrets/base.py +53 -0
- agent_server/config/secrets/file_provider.py +46 -0
- agent_server/core/__init__.py +1 -0
- agent_server/core/context.py +54 -0
- agent_server/core/registry.py +155 -0
- agent_server/core/tools/__init__.py +12 -0
- agent_server/core/tools/example.py +28 -0
- agent_server/datasources/__init__.py +1 -0
- agent_server/datasources/base.py +61 -0
- agent_server/datasources/neo4j.py +72 -0
- agent_server/datasources/postgres.py +76 -0
- agent_server/docs/__init__.py +16 -0
- agent_server/docs/server.py +176 -0
- agent_server/ops/__init__.py +1 -0
- agent_server/ops/app.py +59 -0
- agent_server/ops/schemas.py +35 -0
- agent_server/py.typed +0 -0
- agent_server/runtime.py +39 -0
- agent_server/transports/__init__.py +55 -0
- agent_server/transports/dispatch.py +28 -0
- agent_server/transports/grpc/__init__.py +10 -0
- agent_server/transports/grpc/agent_server_pb2.py +45 -0
- agent_server/transports/grpc/agent_server_pb2_grpc.py +153 -0
- agent_server/transports/grpc/server.py +110 -0
- agent_server/transports/http.py +84 -0
- agent_server/transports/mcp_app.py +72 -0
- agent_server/transports/stdio.py +27 -0
- create_agent_server/__about__.py +7 -0
- create_agent_server/__init__.py +17 -0
- create_agent_server/add_tool.py +167 -0
- create_agent_server/cli.py +205 -0
- create_agent_server/generator.py +832 -0
- create_agent_server/py.typed +0 -0
- create_agent_server/template_paths.py +89 -0
- create_agent_server/templates/config/base.yaml +25 -0
- create_agent_server/templates/config/profiles/local-http.yaml +10 -0
- create_agent_server/templates/config/profiles/local.yaml +6 -0
- create_agent_server/templates/config/profiles/prod.yaml +32 -0
- create_agent_server/templates/examples/README.md +125 -0
- create_agent_server/templates/examples/call_ping.py +43 -0
- create_agent_server/templates/examples/call_ping_http.py +52 -0
- create_agent_server/templates/examples/smoke_ops.sh +26 -0
- create_agent_server/templates/gitignore +15 -0
- create_agent_server/templates/pre-commit-config.yaml +42 -0
- create_agent_server/templates/proto/agent_server.proto +35 -0
- create_agent_server/templates/tools/checks/run_checks.py +63 -0
- create_agent_server/templates/tools/checks/validate_typing.py +74 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-easy-framework
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Enterprise golden-path framework for scaffolding MCP-first agent servers in Python.
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: fastapi>=0.110.0
|
|
9
|
+
Requires-Dist: mcp>=1.2.0
|
|
10
|
+
Requires-Dist: pydantic>=2.6.0
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Requires-Dist: uvicorn>=0.29.0
|
|
13
|
+
Provides-Extra: all
|
|
14
|
+
Requires-Dist: asyncpg>=0.29.0; extra == 'all'
|
|
15
|
+
Requires-Dist: grpcio>=1.62.0; extra == 'all'
|
|
16
|
+
Requires-Dist: httpx>=0.27.0; extra == 'all'
|
|
17
|
+
Requires-Dist: neo4j>=5.18.0; extra == 'all'
|
|
18
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'all'
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: vulture>=2.11; extra == 'dev'
|
|
28
|
+
Provides-Extra: grpc
|
|
29
|
+
Requires-Dist: grpcio>=1.62.0; extra == 'grpc'
|
|
30
|
+
Provides-Extra: neo4j
|
|
31
|
+
Requires-Dist: neo4j>=5.18.0; extra == 'neo4j'
|
|
32
|
+
Provides-Extra: oidc
|
|
33
|
+
Requires-Dist: httpx>=0.27.0; extra == 'oidc'
|
|
34
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'oidc'
|
|
35
|
+
Provides-Extra: postgres
|
|
36
|
+
Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# agent-easy
|
|
40
|
+
|
|
41
|
+
**Scaffold production-ready MCP servers in Python — without inventing the plumbing.**
|
|
42
|
+
|
|
43
|
+
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.
|
|
44
|
+
|
|
45
|
+
This framework generates a **complete, typed, testable MCP server project** you own. Run one command, configure YAML profiles, add your tools, ship.
|
|
46
|
+
|
|
47
|
+
> **PyPI package:** `agent-easy-framework` · **CLI:** `agent-easy` (`pip install agent-easy-framework`, then `agent-easy mcp …`)
|
|
48
|
+
|
|
49
|
+
> **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.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quickstart (no clone)
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uvx agent-easy-framework mcp my-service
|
|
57
|
+
cd my-service && make setup && make example
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
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.
|
|
61
|
+
|
|
62
|
+
Add another tool endpoint:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd my-service
|
|
66
|
+
uvx agent-easy-framework mcp add-tool echo_reply
|
|
67
|
+
make check
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or from the project Makefile (same command, requires network):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd my-service
|
|
74
|
+
make add-tool TOOL=echo_reply
|
|
75
|
+
make check
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Full options:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uvx agent-easy-framework mcp billing-agent \
|
|
82
|
+
--datasources postgres,neo4j \
|
|
83
|
+
--transports stdio,http \
|
|
84
|
+
--auth oidc
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Locked-down environments (no `uvx`):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install agent-easy-framework
|
|
91
|
+
agent-easy mcp billing-agent --datasources neo4j --auth oidc
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## At a glance
|
|
97
|
+
|
|
98
|
+
| | |
|
|
99
|
+
|---|---|
|
|
100
|
+
| **What it generates** | An MCP-first Python server with tools, data sources, auth, and ops endpoints |
|
|
101
|
+
| **Who it is for** | Engineers shipping agent tools to Claude Desktop, IDEs, or internal platforms |
|
|
102
|
+
| **Config model** | YAML profiles (Spring-style). No environment variables |
|
|
103
|
+
| **Quality bar** | `mypy --strict`, ruff, dead-code detection, golden-path fact-checks baked in |
|
|
104
|
+
| **Deep reference** | [GOLDEN_PATH.md](GOLDEN_PATH.md) — the contract every generated server follows |
|
|
105
|
+
| **Copy-paste examples** | [examples/README.md](examples/README.md) — call `ping`, curl ops, browse live docs |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Try it now (reference server)
|
|
110
|
+
|
|
111
|
+
For contributors or anyone exploring the generator source, clone this repo:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
make setup
|
|
115
|
+
make example # Flow 1: ping in-process — no server (~5 seconds)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Call the tool over HTTP MCP (two terminals):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
make run-http # terminal 1
|
|
122
|
+
make example-http # terminal 2 — Streamable HTTP client, not curl
|
|
123
|
+
./examples/smoke_ops.sh # optional: ops REST at :8080
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Full walkthrough: [examples/README.md](examples/README.md).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Your journey (start to shipped)
|
|
131
|
+
|
|
132
|
+
Follow this path whether you are new to MCP or just do not want to rebuild the same skeleton again.
|
|
133
|
+
|
|
134
|
+
```mermaid
|
|
135
|
+
flowchart LR
|
|
136
|
+
subgraph step1 [1. Generate]
|
|
137
|
+
gen["uvx agent-easy-framework mcp …"]
|
|
138
|
+
end
|
|
139
|
+
subgraph step2 [2. Configure]
|
|
140
|
+
yaml["YAML profiles + secrets"]
|
|
141
|
+
end
|
|
142
|
+
subgraph step3 [3. Run]
|
|
143
|
+
run["make run / make docs"]
|
|
144
|
+
end
|
|
145
|
+
subgraph step4 [4. Extend]
|
|
146
|
+
tools["Add @tool handlers"]
|
|
147
|
+
end
|
|
148
|
+
subgraph step5 [5. Ship]
|
|
149
|
+
ci["make check + CI"]
|
|
150
|
+
end
|
|
151
|
+
gen --> yaml --> run --> tools --> ci
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
<details>
|
|
155
|
+
<summary><strong>Step 1 — Generate your server</strong></summary>
|
|
156
|
+
|
|
157
|
+
Pick only what you need. Unused providers and transports are pruned so dependencies stay minimal.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
uvx agent-easy-framework mcp billing-agent \
|
|
161
|
+
--datasources postgres,neo4j \
|
|
162
|
+
--transports stdio,http \
|
|
163
|
+
--auth oidc
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Flag | Options | Default | When to use |
|
|
167
|
+
|------|---------|---------|-------------|
|
|
168
|
+
| `--output`, `-o` | directory path | `.` | Parent folder for the new project |
|
|
169
|
+
| `--package` | Python identifier | derived from name | Override the import package name |
|
|
170
|
+
| `--datasources` | `postgres`, `neo4j` | none | Your tools need a database |
|
|
171
|
+
| `--transports` | `stdio`, `http`, `grpc` | `stdio` | `stdio` = local/IDE; `http` = deployed; `grpc` = custom adapter |
|
|
172
|
+
| `--auth` | `none`, `oidc`, `basic` | `none` | `oidc` for SSO in prod; `basic` is **testing only** (runtime API key) |
|
|
173
|
+
| `--profile` | any name | `local` | Default active profile in `config/base.yaml` |
|
|
174
|
+
|
|
175
|
+
### Add a tool to an existing project
|
|
176
|
+
|
|
177
|
+
Run from the project root (or pass `-C`). Requires `uvx` and the published `agent-easy-framework` package:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
cd my-service
|
|
181
|
+
uvx agent-easy-framework mcp add-tool echo_reply
|
|
182
|
+
uvx agent-easy-framework mcp add-tool send_invoice -d "Create and send a customer invoice."
|
|
183
|
+
make check
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Or use the Makefile wrapper:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
make add-tool TOOL=echo_reply
|
|
190
|
+
make check
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
> **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.
|
|
194
|
+
|
|
195
|
+
Locked-down environments (no `uvx`):
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install agent-easy-framework
|
|
199
|
+
agent-easy mcp billing-agent --datasources neo4j --auth oidc
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
</details>
|
|
203
|
+
|
|
204
|
+
<details>
|
|
205
|
+
<summary><strong>Step 2 — Configure profiles and secrets</strong></summary>
|
|
206
|
+
|
|
207
|
+
Generated layout:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
billing-agent/
|
|
211
|
+
config/
|
|
212
|
+
base.yaml # shared defaults + active_profile
|
|
213
|
+
profiles/
|
|
214
|
+
local.yaml # deep-merged on top of base
|
|
215
|
+
prod.yaml
|
|
216
|
+
secrets/ # file-based secret provider (gitignored)
|
|
217
|
+
neo4j/password
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Profiles** — Spring-style. One knob at runtime:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
billing-agent run # uses active_profile from base.yaml
|
|
224
|
+
billing-agent run --profile prod # override
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Secrets** — never committed as raw values. Reference them in YAML:
|
|
228
|
+
|
|
229
|
+
```yaml
|
|
230
|
+
password: ${secret:neo4j/password}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Create the file: `secrets/neo4j/password` (or plug in Vault / cloud providers later).
|
|
234
|
+
|
|
235
|
+
**OIDC example** (`config/profiles/prod.yaml`):
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
server:
|
|
239
|
+
auth:
|
|
240
|
+
provider: oidc
|
|
241
|
+
options:
|
|
242
|
+
issuer: https://login.your-idp.com/
|
|
243
|
+
audience: billing-agent
|
|
244
|
+
jwks_uri: https://login.your-idp.com/.well-known/jwks.json
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
</details>
|
|
248
|
+
|
|
249
|
+
<details>
|
|
250
|
+
<summary><strong>Step 3 — Install and run</strong></summary>
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
cd billing-agent
|
|
254
|
+
make setup # venv + minimal deps for your selection
|
|
255
|
+
make run # serve with default profile
|
|
256
|
+
make run PROFILE=prod
|
|
257
|
+
make docs # live docs site from your tool registry (nothing committed)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Ops endpoints (for load balancers / k8s) — default **`127.0.0.1:8080`**:
|
|
261
|
+
|
|
262
|
+
| Endpoint | Purpose |
|
|
263
|
+
|----------|---------|
|
|
264
|
+
| `GET /health` | Liveness — process is up |
|
|
265
|
+
| `GET /ready` | Readiness — all data sources healthy |
|
|
266
|
+
| `GET /admin/tools` | Registered tools and descriptions |
|
|
267
|
+
|
|
268
|
+
Other default ports:
|
|
269
|
+
|
|
270
|
+
| Surface | Default | Notes |
|
|
271
|
+
|---------|---------|-------|
|
|
272
|
+
| MCP (HTTP) | `8000` at `/mcp` | Streamable HTTP when `--transports http` |
|
|
273
|
+
| Live docs | `8090` | `make docs` — registry-generated, not committed |
|
|
274
|
+
|
|
275
|
+
</details>
|
|
276
|
+
|
|
277
|
+
<details>
|
|
278
|
+
<summary><strong>Step 4 — Add your tools</strong></summary>
|
|
279
|
+
|
|
280
|
+
A tool is an async function with a typed Pydantic input model. The docstring becomes the MCP description.
|
|
281
|
+
|
|
282
|
+
Create `src/billing_agent/core/tools/invoice.py` (requires `--datasources postgres` in Step 1):
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
from pydantic import BaseModel, Field
|
|
286
|
+
|
|
287
|
+
from billing_agent.core.context import AppContext
|
|
288
|
+
from billing_agent.core.registry import tool
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class LookupInput(BaseModel):
|
|
292
|
+
invoice_id: str = Field(description="Invoice ID to fetch.")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class LookupOutput(BaseModel):
|
|
296
|
+
total: float
|
|
297
|
+
status: str
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@tool
|
|
301
|
+
async def lookup_invoice(params: LookupInput, ctx: AppContext) -> LookupOutput:
|
|
302
|
+
"""Fetch an invoice total and status from the primary database."""
|
|
303
|
+
db = ctx.datasource("primary") # name from config/server.datasources
|
|
304
|
+
rows = await db.fetch("SELECT total, status FROM invoices WHERE id = $1", params.invoice_id)
|
|
305
|
+
row = rows[0]
|
|
306
|
+
return LookupOutput(total=row["total"], status=row["status"])
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Register it in `src/billing_agent/core/tools/__init__.py`:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from billing_agent.core.tools import invoice as invoice
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Restart the server. Your tool appears in `make docs` and every transport automatically.
|
|
316
|
+
|
|
317
|
+
</details>
|
|
318
|
+
|
|
319
|
+
<details>
|
|
320
|
+
<summary><strong>Step 5 — Verify and ship</strong></summary>
|
|
321
|
+
|
|
322
|
+
Every generated project includes the same quality gates:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
make check # lint + type + deadcode + golden-path fact-checks
|
|
326
|
+
make test # unit + smoke tests
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
CI in **this** repo runs the same checks on pull requests. Your generated project ships with pre-commit hooks ready to enable.
|
|
330
|
+
|
|
331
|
+
</details>
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## How a request flows
|
|
336
|
+
|
|
337
|
+
When an MCP client calls your server, everything funnels through one registry — transports are thin adapters.
|
|
338
|
+
|
|
339
|
+
```mermaid
|
|
340
|
+
sequenceDiagram
|
|
341
|
+
participant Client as MCP Client
|
|
342
|
+
participant Transport as Transport adapter
|
|
343
|
+
participant Auth as Auth provider
|
|
344
|
+
participant Registry as Tool registry
|
|
345
|
+
participant Tool as Your @tool handler
|
|
346
|
+
participant DS as Data source
|
|
347
|
+
|
|
348
|
+
Client->>Transport: call_tool(name, arguments)
|
|
349
|
+
alt HTTP or gRPC
|
|
350
|
+
Transport->>Auth: validate Bearer token
|
|
351
|
+
Auth-->>Transport: Principal
|
|
352
|
+
end
|
|
353
|
+
Transport->>Registry: invoke_tool(name, args)
|
|
354
|
+
Registry->>Tool: handler(params, ctx)
|
|
355
|
+
Tool->>DS: query (optional)
|
|
356
|
+
DS-->>Tool: result
|
|
357
|
+
Tool-->>Registry: Pydantic output
|
|
358
|
+
Registry-->>Transport: JSON payload
|
|
359
|
+
Transport-->>Client: MCP response
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**stdio** skips auth (trusted local channel). **HTTP** and **gRPC** enforce the configured provider.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Architecture inside your generated server
|
|
367
|
+
|
|
368
|
+
One core, multiple ways in. You write tools once; every transport exposes them.
|
|
369
|
+
|
|
370
|
+
```mermaid
|
|
371
|
+
flowchart TB
|
|
372
|
+
subgraph adapters [Transport adapters]
|
|
373
|
+
stdio[stdio]
|
|
374
|
+
http["Streamable HTTP"]
|
|
375
|
+
grpc[gRPC adapter]
|
|
376
|
+
end
|
|
377
|
+
subgraph ops [FastAPI surfaces]
|
|
378
|
+
health["/health · /ready · /admin"]
|
|
379
|
+
docs["Live docs server"]
|
|
380
|
+
end
|
|
381
|
+
subgraph core [Transport-agnostic core]
|
|
382
|
+
tools[Tool registry]
|
|
383
|
+
ds[Data source registry]
|
|
384
|
+
ctx[AppContext]
|
|
385
|
+
end
|
|
386
|
+
subgraph cfg [Config layer]
|
|
387
|
+
yaml[YAML profiles]
|
|
388
|
+
sec[Secret providers]
|
|
389
|
+
auth[Auth providers]
|
|
390
|
+
end
|
|
391
|
+
stdio --> core
|
|
392
|
+
http --> core
|
|
393
|
+
grpc --> core
|
|
394
|
+
ops --> core
|
|
395
|
+
core --> cfg
|
|
396
|
+
ds --> postgres[(PostgreSQL)]
|
|
397
|
+
ds --> neo4j[(Neo4j)]
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
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.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Choose your stack (decision guide)
|
|
405
|
+
|
|
406
|
+
```mermaid
|
|
407
|
+
flowchart TD
|
|
408
|
+
start([I need an MCP server]) --> local{Local dev only?}
|
|
409
|
+
local -->|Yes| stdio["transports: stdio"]
|
|
410
|
+
local -->|No| http["transports: stdio,http"]
|
|
411
|
+
http --> db{Need a database?}
|
|
412
|
+
db -->|Postgres| pg["--datasources postgres"]
|
|
413
|
+
db -->|Graph| neo["--datasources neo4j"]
|
|
414
|
+
db -->|Both| both["--datasources postgres,neo4j"]
|
|
415
|
+
db -->|No| none["--datasources omitted"]
|
|
416
|
+
http --> auth{Production auth?}
|
|
417
|
+
auth -->|SSO| oidc["--auth oidc"]
|
|
418
|
+
auth -->|Quick local test| noneAuth["--auth none"]
|
|
419
|
+
auth -->|Never prod| basic["--auth basic · testing only"]
|
|
420
|
+
stdio --> done([make setup && make run])
|
|
421
|
+
pg --> done
|
|
422
|
+
neo --> done
|
|
423
|
+
both --> done
|
|
424
|
+
none --> done
|
|
425
|
+
oidc --> done
|
|
426
|
+
noneAuth --> done
|
|
427
|
+
basic --> done
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Example: Neo4j + OIDC (production-shaped)
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
uvx agent-easy-framework mcp graph-agent \
|
|
436
|
+
--datasources neo4j \
|
|
437
|
+
--transports stdio,http \
|
|
438
|
+
--auth oidc
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
cd graph-agent
|
|
443
|
+
mkdir -p secrets/neo4j
|
|
444
|
+
echo 'your-password' > secrets/neo4j/password
|
|
445
|
+
make setup && make run PROFILE=prod
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Point `config/profiles/prod.yaml` at your IdP and Neo4j bolt URI. HTTP clients send `Authorization: Bearer <jwt>`.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## What you get out of the box
|
|
453
|
+
|
|
454
|
+
- **MCP-first** — official `mcp` SDK; tools registered via `@tool` with enforced typing and docstrings
|
|
455
|
+
- **Minimal deps** — generator prunes what you did not select
|
|
456
|
+
- **YAML profiles** — no environment variables; `--profile` CLI override
|
|
457
|
+
- **Pluggable providers** — same pattern for secrets, auth, and data sources
|
|
458
|
+
- **Live docs** — `make docs` serves a registry-generated site; nothing committed
|
|
459
|
+
- **Quality gates** — ruff, `mypy --strict`, vulture, custom fact-checks, pytest smoke test
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Generated project commands
|
|
464
|
+
|
|
465
|
+
| Command | What it does |
|
|
466
|
+
|---------|--------------|
|
|
467
|
+
| `make setup` | Create venv, install deps |
|
|
468
|
+
| `make example` | Call `ping` in-process (fast validation, no server) |
|
|
469
|
+
| `make run` | Run server (`PROFILE=prod` to override) |
|
|
470
|
+
| `make run-http` | Run HTTP MCP transport (when generated with `--transports http`) |
|
|
471
|
+
| `make example-http` | Call `ping` over HTTP MCP (when generated with `--transports http`) |
|
|
472
|
+
| `make docs` | Serve live documentation |
|
|
473
|
+
| `make check` | Lint + type + deadcode + golden-path fact-checks |
|
|
474
|
+
| `make factcheck` | Golden-path invariants only |
|
|
475
|
+
| `make test` | Run tests |
|
|
476
|
+
| `make fmt` | Auto-format |
|
|
477
|
+
| `make all` | `check` + `test` |
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Contributing to this framework
|
|
482
|
+
|
|
483
|
+
For maintainers working on the generator itself:
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
git clone https://github.com/KazzyAPI/agent-easy.git
|
|
487
|
+
cd agent-easy
|
|
488
|
+
make setup # sync templates + venv + dev deps
|
|
489
|
+
make check && make test
|
|
490
|
+
make sync-templates # refresh bundled templates before publishing
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
See [GOLDEN_PATH.md](GOLDEN_PATH.md) for the full architectural contract.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
agent_server/__about__.py,sha256=f2UAInhJ97hsCgt9nUrJAJ4En2kuWxXID3spKvI8c4w,77
|
|
2
|
+
agent_server/__init__.py,sha256=nG5tKfEzWlPdP2O2kGDrmyGNCQAXEU724V5X1g_CXv0,423
|
|
3
|
+
agent_server/__main__.py,sha256=g-7HZK4xWZW80jxQK1HENjjwpOlORa8f30KHrJ3p0LY,169
|
|
4
|
+
agent_server/bootstrap.py,sha256=r4bLc0ksy1KtMjH_uAatWg2lTIl4htq04AwDkuU01To,972
|
|
5
|
+
agent_server/cli.py,sha256=fzNak0QHfwkkgCMPThiaHsY3R6z6OLNGKZ7lNfVTTd8,1785
|
|
6
|
+
agent_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
agent_server/runtime.py,sha256=G4_Jzr4DIMnMPkF7PmrBFvFbXwgx802xl5laTOFDXM0,1327
|
|
8
|
+
agent_server/auth/__init__.py,sha256=4piQimXRW4HH5JMkw8yQk5UYcT-qGrN6Ofq9zXRwGR0,75
|
|
9
|
+
agent_server/auth/base.py,sha256=JFtG2kaL0si9ABLzJCgkf_BzGYPy2a8IGOtLyOmwmNQ,2069
|
|
10
|
+
agent_server/auth/basic.py,sha256=u53AJZO8gN9TA8byNTfP9hhYHzgTvrY1zUFowQGMei8,3370
|
|
11
|
+
agent_server/auth/none.py,sha256=2Lfsp3-q3_6rVYIyVo0I-Fx2QeVItlyS_35eRT3buco,956
|
|
12
|
+
agent_server/auth/oidc.py,sha256=7Z9dT-TCGGeI-5WYK9S3FNCzFCwOAhwIDG5_AiF425I,4090
|
|
13
|
+
agent_server/checks/__init__.py,sha256=Itg9mVnigmI_fAkfOT9gSSz6nBm199cd_wYxdFpRh28,464
|
|
14
|
+
agent_server/checks/invariants.py,sha256=nUNiOJMwyBFI85gm8QbTNRr3xo4clsdQueVNYPwIRGU,11987
|
|
15
|
+
agent_server/config/__init__.py,sha256=d0Rtajz_P1RTDQFqBDtNL4Tpsm4OeILrYfOEl83m5DU,73
|
|
16
|
+
agent_server/config/loader.py,sha256=onSYzcLfN2nOkd3bXe3lnBzAINRuR-5hi5-DwFjTePA,3590
|
|
17
|
+
agent_server/config/schema.py,sha256=CjZ15e6bSnoT2vU8I7UgcWw-SWsITYGiUjpNcqLg-Yo,1540
|
|
18
|
+
agent_server/config/secrets/__init__.py,sha256=RzYTDjhAxq_5B-9fv4X3QTyoXIB2Edcb_cvfhOK061A,75
|
|
19
|
+
agent_server/config/secrets/base.py,sha256=RxzeI4kotio-2PEjgyPfMPyRq-FsgNGySIb6kEU9Aok,1684
|
|
20
|
+
agent_server/config/secrets/file_provider.py,sha256=e6daFFPtWMcid-ScfJvHYvOXTSYA21h42zyjvZA01GE,1678
|
|
21
|
+
agent_server/core/__init__.py,sha256=5cWyG6I_rlRKZiSVmz_8t56SaC6fOSWzw5UdpQ8lUm4,66
|
|
22
|
+
agent_server/core/context.py,sha256=28-3Q1Ii8As6cO-FeSRMcXpGcCP2QfNNzdPP6S-2z5Q,2214
|
|
23
|
+
agent_server/core/registry.py,sha256=tghEL9Do2GTyh6JkisaFA-4WtoeRxYkhRX4j9uBxYpw,4696
|
|
24
|
+
agent_server/core/tools/__init__.py,sha256=PGL-xr__j8X2DHJ7WEnVlJZiGtksq-Oa_LYNQ8jtym0,361
|
|
25
|
+
agent_server/core/tools/example.py,sha256=Z-t7jB29I-00_tjudP2SIh1pRwgsgzdCzZzegZGW11Y,824
|
|
26
|
+
agent_server/datasources/__init__.py,sha256=MLeqADi6p3XoI5iiJs1HmP99UO03wF9NxHkDkCHmj78,66
|
|
27
|
+
agent_server/datasources/base.py,sha256=5uG1Khc24Xj6Du8Ypi-CrVK-s2mLjIHNHrc7PI-c1KU,1943
|
|
28
|
+
agent_server/datasources/neo4j.py,sha256=gguexeIUiP_wiJ2mFTaz9Bti-ZBiJRgXNoVlAB-H3Qo,2601
|
|
29
|
+
agent_server/datasources/postgres.py,sha256=Jcn2oViuz1-dalVNbFs2z00TXBUb2Z_pdimTOBrwwqA,2610
|
|
30
|
+
agent_server/docs/__init__.py,sha256=1oSgPKYnoVLGwaeszCXoLwfVvKJV_8-dEZ0Z738RZeY,469
|
|
31
|
+
agent_server/docs/server.py,sha256=6gcxONb4JJgai0KBtZccJ98LGXjmVvyb3yI4WbnH0Fg,6359
|
|
32
|
+
agent_server/ops/__init__.py,sha256=OskEY-oCyyTv7DZss34Hy_QijGT--BptNlBNim8fwTc,59
|
|
33
|
+
agent_server/ops/app.py,sha256=JK-bICAAYj4aXbCNxwlHYQn1xZatZIHvL7IuV6vox0s,2185
|
|
34
|
+
agent_server/ops/schemas.py,sha256=FHqAGjRSm3rcd0KUysniZUBeiQN60x5DT0nWAhZD7Fs,826
|
|
35
|
+
agent_server/transports/__init__.py,sha256=orGwqKRklMyCflbehWtZyA3QC1_r8vD0Yy3Ci0zcinU,2098
|
|
36
|
+
agent_server/transports/dispatch.py,sha256=TEd7DzhJJr2QsieKtTDsVE0VePq7kI4o_Y0gT8p0PQk,916
|
|
37
|
+
agent_server/transports/http.py,sha256=4DbqE9mt0ykxNGfDYSi4FG-bJYnxGqgS90cWMDS0HQ8,3437
|
|
38
|
+
agent_server/transports/mcp_app.py,sha256=MqtlZ-GHcujGdzk_iqi-WI-HBjDt6FXVkS0kzonMNjE,2526
|
|
39
|
+
agent_server/transports/stdio.py,sha256=GQ2yW4fghJ0snst-hkiQGajAQ7Xrzwc11EfROsrznVU,1018
|
|
40
|
+
agent_server/transports/grpc/__init__.py,sha256=qXDFJLozxdRlYes1mhn8rM4Vz2su4DaNce_jKRcKgGA,431
|
|
41
|
+
agent_server/transports/grpc/agent_server_pb2.py,sha256=bhL2J_oeLZJOasZi5OvJqoxg6516pPsuBMb4BAsvMzE,2490
|
|
42
|
+
agent_server/transports/grpc/agent_server_pb2_grpc.py,sha256=zF56FQnez88HU1cBcIJMXO-ymlIHUt9ViSef5AJvKSY,5158
|
|
43
|
+
agent_server/transports/grpc/server.py,sha256=9Lb5SSl4YYsuRFySZGEXrGrjN_VoSxM3PlMdktlAjlU,4379
|
|
44
|
+
create_agent_server/__about__.py,sha256=WBpOhito9IqvQGvZJhvsEKJI6v-uya2dD7RsKB8pH0w,296
|
|
45
|
+
create_agent_server/__init__.py,sha256=AkESFNYBzrIfxBo4nLgNUMKG7pyKUhbNpex-X3LoKDs,755
|
|
46
|
+
create_agent_server/add_tool.py,sha256=H6BjVGNk3gG99P0_aEyMTtHh4wSkJGYv6NxPlP7b42M,5433
|
|
47
|
+
create_agent_server/cli.py,sha256=PYnuioCpvVKwvPKBY0a7c50_ocf9Sq5UKKbyhIlNGkU,6878
|
|
48
|
+
create_agent_server/generator.py,sha256=bKjWvDGah9tQCeiOgVV4WeywpzE7UCkGH9_d-z6Tb8c,24473
|
|
49
|
+
create_agent_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
+
create_agent_server/template_paths.py,sha256=6Zvdi4v6YfpMKSelHdwJTq-mvNj_qGtN5zXP8HPOMXs,2766
|
|
51
|
+
create_agent_server/templates/gitignore,sha256=l5yEWHmEpIa2tsXI5lDVMLhmX4ir9GHRLc6eL75mhp4,241
|
|
52
|
+
create_agent_server/templates/pre-commit-config.yaml,sha256=JC59NIxXsNRpOsYE2D3dobTqqArsRrm6WdoCsIhlgSs,1191
|
|
53
|
+
create_agent_server/templates/config/base.yaml,sha256=ozsvFKnw8X7WF-ZJrUMm7Dkt2iS14pR3a4omuFwPtdQ,513
|
|
54
|
+
create_agent_server/templates/config/profiles/local-http.yaml,sha256=H_6lFB7pg3cP1a54LseG7B2EC9ncttfcq7Y0jui30JY,279
|
|
55
|
+
create_agent_server/templates/config/profiles/local.yaml,sha256=DXbi3b_pHvxNPTDjhJXI1Sb3Rlk4MOl-eM1RABdtDJY,148
|
|
56
|
+
create_agent_server/templates/config/profiles/prod.yaml,sha256=ZIaSxlJCwce7zPK48siJnDjp5MOBBV7ucfRYzabiy5M,765
|
|
57
|
+
create_agent_server/templates/examples/README.md,sha256=W-2aE3SjXAnJDeVmQIZiT7SYLVf-MkCkpg-WnOUsU0c,2966
|
|
58
|
+
create_agent_server/templates/examples/call_ping.py,sha256=CmC9foogiWQ6dVRS29vQGVJtSAbikPdb73SO3Hgmy6c,1363
|
|
59
|
+
create_agent_server/templates/examples/call_ping_http.py,sha256=ql37877FN2_LJoTEbdJgCSL1tGNWH7wtUIDG94AxVvs,1287
|
|
60
|
+
create_agent_server/templates/examples/smoke_ops.sh,sha256=9rodNHGznSlS4H0rvH03PFKWv-XJN63VGIslLX5cXGE,538
|
|
61
|
+
create_agent_server/templates/proto/agent_server.proto,sha256=cQzfwVBq8LG0XucXtimo-8aKdm_7sippH-r7Gb-ltlo,961
|
|
62
|
+
create_agent_server/templates/tools/checks/run_checks.py,sha256=URB4YFNRtDqjSG-ciZRXFAapf6Vzs5OrsTxmuDivMKI,2151
|
|
63
|
+
create_agent_server/templates/tools/checks/validate_typing.py,sha256=-S57a158GiHZ8cn7R7ba23H0pup2Qdf6hDhl09lOZRU,2259
|
|
64
|
+
agent_easy_framework-0.0.3.dist-info/METADATA,sha256=rqxEI4ZFAWa7ZF7x-O-onkwdhIjODWnU9te26d4gCqs,14668
|
|
65
|
+
agent_easy_framework-0.0.3.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
66
|
+
agent_easy_framework-0.0.3.dist-info/entry_points.txt,sha256=OKlzXhKS8qZZQ0Z6AuJ6WltJW8P7m-GfWRX2rcd6icg,60
|
|
67
|
+
agent_easy_framework-0.0.3.dist-info/licenses/LICENSE,sha256=Ew2onRHMM28wHYO5Ob-kdFS7wlAlw9ckegjAeEENJFc,1065
|
|
68
|
+
agent_easy_framework-0.0.3.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nathan M
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
agent_server/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""agent_server: the canonical MCP-first server package.
|
|
2
|
+
|
|
3
|
+
This package is the golden-path reference implementation. The
|
|
4
|
+
``agent-easy mcp`` generator copies it into new projects and renames the
|
|
5
|
+
top-level package. Keep it real, runnable, typed, and tested - it is the
|
|
6
|
+
contract every generated server inherits.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from agent_server.__about__ import __version__
|
|
12
|
+
|
|
13
|
+
__all__ = ["__version__"]
|
agent_server/__main__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Authentication: provider protocol, registry, and built-in providers."""
|