AviaryMCP
AviaryMCP is Finch's opinionated Python SDK for new MCP services. Define a tool once and get the MCP transport, typed REST endpoints, OpenAPI, Finch enrollment, and the same authorization decision across every interface.
0.1.0rc6 is available on PyPI and requires the Finch 1.6 agent. The normal Finch CLI and finch.yml remain supported for existing, non-Python, and non-SDK services. Machine-readable guidance is available in the hosted llms.txt and AviaryMCP's project llms.txt.When to use it
| You have | Use |
|---|---|
| A new Python MCP service | AviaryMCP. The application owns its tools, routes, and Finch registration. |
| An existing HTTP/MCP service, or another language | The Finch quickstart and finch.yml. |
| Several existing FastMCP servers | Mount them into one AviaryMCP parent, with a namespace for each child. |
1. Install the release candidate
AviaryMCP is published publicly on PyPI. Pin the release candidate while evaluating it so a future prerelease does not change underneath your service.
python -m pip install 'aviary-mcp==0.1.0rc6'2. Define the service
Save this as server.py:
from aviary_mcp import AviaryMCP, Finch
service = "calculator"
mcp = AviaryMCP(
service,
finch=Finch.local(
path=service,
binary="/usr/local/bin/finch",
),
)
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
if __name__ == "__main__":
mcp.run()Finch.local starts a dedicated zero-config Finch child and keeps its approval scoped to this project. Pass the absolute Finch 1.6+ binary path; the SDK never downloads or silently selects executable code from PATH. The tenant is bound to the account that approves the first-run device prompt.
Use an existing Finch agent instead
For sidecars, system services, and shared container groups, choose the other explicit mode and name the permissioned Unix socket:
mcp = AviaryMCP(
"calculator",
finch=Finch.agent(
path="calculator",
socket="/run/finch/control.sock",
),
)
mcp.run()Both modes publish the same application at /mcp, /api/v1, and /birdz. Ordinary FastMCP tool decorators need no Finch route code.
3. Start and approve it
python server.py
AviaryMCP is not enrolled with Finch.
Open: https://finchmcp.com/aviary/authorize?code=ABCD-EFGH
Code: ABCD-EFGH
Service: calculator (calculator)
Routes: /mcp, /api/v1, /birdz
Edge auth: keyOpen the printed URL on any signed-in device. Finch shows the exact service, routes, edge mode, and device-key fingerprint before you approve it. Finch stores the resulting service-scoped credential; your application never receives a CLI token, device secret, or caller key. On later starts, the saved approval is reused and the service registers automatically.
app_path to finch.yml. AviaryMCP holds a renewable dynamic registration;finch.yml is for services the SDK does not manage.4. Use MCP or REST
The same add tool is available through each generated interface:
| Interface | Path |
|---|---|
| MCP | /calculator/mcp |
| Tool catalog | /calculator/api/v1/tools |
| Call a tool | /calculator/api/v1/tools/add |
| OpenAPI 3.1 | /calculator/api/v1/openapi.json |
| Liveness / readiness | /calculator/birdz and /calculator/birdz/ready |
curl -X POST \
https://your-slug.finchmcp.com/calculator/api/v1/tools/add \
-H 'Authorization: Bearer finch_...' \
-H 'content-type: application/json' \
-d '{"a": 20, "b": 22}'A caller still authenticates to Finch with a finch_ key or OAuth. Finch validates that credential at the edge, strips it, and signs a short-lived assertion bound to the exact method, path, query, body, tenant, and service. AviaryMCP's automatically configured assertion verifier checks it before MCP or REST can invoke the tool.
Compose existing FastMCP servers
from fastmcp import FastMCP
from aviary_mcp import AviaryMCP
weather = FastMCP("weather")
@weather.tool
def forecast(city: str) -> str:
return f"sunny in {city}"
mcp = AviaryMCP("aviary")
mcp.mount(weather, namespace="weather")The mounted tool becomes weather_forecast in MCP, REST, and OpenAPI. Namespaces keep tools from different birds from colliding.
Production boundaries
- Use one Finch sidecar/control socket per mutually trusted application group.
- Gate rollout on
/birdz/ready, not liveness alone. - Keep the Finch state volume persistent so approval survives restarts.
- Use a shared atomic replay store before running multiple application workers.
- Keep private edge auth as the default; public exposure requires separate explicit approval.