python-billing-agent
A runnable Python example that defines three billing-related tools with @platools.tool(), hosts them in a tiny FastAPI process, and wires platools doctor + platools test into a make target.
What’s in the box
examples/python-billing-agent/├── README.md├── pyproject.toml├── .env.example├── .gitignore├── app/│ ├── __init__.py│ ├── main.py # FastAPI host + platools.connect() bootstrap│ ├── tools.py # @platools.tool() decorated functions│ └── models.py # Pydantic models for inputs/outputs├── platools-tests.yaml # batch test file for `platools test`└── MakefileThe tools
app/tools.py registers three tools on a shared Platools() instance:
list_invoices(customer_id)->list[Invoice]- read-only,auth="user", no role gate. Returns the most recent invoices for a customer.create_invoice(customer_id, amount_cents, currency, description)->Invoice-auth="admin",roles=["billing"]. Creates a draft invoice.void_invoice(invoice_id, reason)->VoidResult-auth="admin",roles=["billing"],annotations={"destructive": True}. Voids an existing invoice and logs the reason.
Every parameter has a type hint and a docstring description. Every return type is a BaseModel. platools doctor ships green out of the box.
Running it
cd examples/python-billing-agent
# One-time setupcp .env.example .env # fill in PLATOS_URL + PLATOS_SECRET (or leave blank for doctor-only flows)uv sync
# Static analysis - the ship gateuv run platools doctor app.tools
# Local smoke tests (no platform required)uv run platools test --module app.tools
# Run the FastAPI host + outbound WebSocket (requires PLATOS_URL + PLATOS_SECRET)uv run uvicorn app.main:app --reload --port 8080If you don’t have a Platos platform deployed yet, uv run platools serve --module app.tools gives you a local MCP endpoint you can point Claude Desktop at - see local-dev-loop for the walkthrough.
What to learn from it
- One
Platools()per process.app/tools.pycreates the instance;app/main.pyimports it and callsasyncio.create_task(platools.connect())during FastAPI startup. - Pydantic models are first-class. Inputs and outputs both use
BaseModelsubclasses - the schema generator walks the annotations recursively. - Doctor in CI. The
Makefile’schecktarget runsuv run platools doctor app.toolsand exits non-zero on any error finding. platools-tests.yamlis the smoke test. One happy-path case and one expected-error case per tool. Coverage target is 100% - if you add a tool, you add a case.- Secrets stay out of the repo.
.env.exampleis committed,.envis gitignored, and the app readsos.environrather than hardcoding anything.
Source: examples/python-billing-agent/
Next steps
- typescript-support-agent - the same pattern in TypeScript.
- local-dev-loop - run these tools locally via
platools serve. - Python SDK - full reference for the decorator, schemas, and client.