Skip to content

New MCP servers & agent testing, built in

Laravel’s craft.
FastAPI’s speed.
Ready for agents.

A Python framework with service providers, an Artisan CLI, an ORM with migrations, logging channels, MCP servers, and agent evals, all in one container.

uvx fastapi-startkit@latest init my-app
  • Free & open source
  • Async from the ground up
  • Use one module or all

bootstrap/application.py

from pathlib import Pathfrom fastapi_startkit import Applicationfrom fastapi_startkit.fastapi import FastAPIProviderfrom fastapi_startkit.logging import LogProviderfrom fastapi_startkit.masoniteorm import DatabaseProvider # FastAPI Startkit ships with a fully async MasoniteORM provider.# Use it for an elegant, Active Record workflow—or completely swap it# for SQLAlchemy, SQLModel, or any async database stack you prefer.app: Application = Application(    base_path=Path(__file__).parent.parent,    providers=[        LogProvider,        FastAPIProvider,        DatabaseProvider,    ])
  • FastAPI
  • Starlette
  • Pydantic
  • Masonite ORM
  • SQLAlchemy
  • Cleo
  • LangChain
  • Pendulum

One core. Everything else plugs in.

Every component is an independent module with its own service provider. Register the provider to wire in its config, container bindings, and lifecycle. Leave it out and it never loads.

Try a setup
  • Loggingterminal · daily · syslog · slack
  • Database & ORMmodels · migrations · seeders
  • HTTP APIFastAPI · routers · resources
  • Redisconnections · key prefix · urls
  • Storagelocal · public · s3 disks
  • AI & MCPagents · MCP tools · evals

Application

fastapi_startkit · container

  • LogProviderloaded
  • DatabaseProviderloaded
  • FastAPIProviderloaded
  • RedisProviderloaded
  • StorageProviderloaded
  • AIProviderloaded
  • McpProviderloaded

7 of 7 providers loaded · 0 skipped

bootstrap/application.py · updates as you toggle
from pathlib import Pathfrom fastapi_startkit import Applicationfrom fastapi_startkit.logging import LogProviderfrom fastapi_startkit.masoniteorm import DatabaseProviderfrom fastapi_startkit.fastapi import FastAPIProviderfrom fastapi_startkit.redis import RedisProviderfrom fastapi_startkit.storage import StorageProviderfrom fastapi_startkit.ai import AIProviderfrom fastapi_startkit.mcp import McpProvider app = Application(    base_path=Path(__file__).parent.parent,    providers=[        LogProvider,        DatabaseProvider,        FastAPIProvider,        RedisProvider,        StorageProvider,        AIProvider,        McpProvider,    ],)
  1. Independent packages

    Each component has its own code and config, with no hard dependency on the others.

  2. Connected by providers

    A provider registers the component in the app container. Nothing else connects them.

  3. Pay only for what you load

    Skip a provider and its stack stays out of the process: a worker without FastAPIProvider never imports FastAPI.

Your app, callable by agents.

Subclass Tool and give it a Pydantic schema to make it an MCP tool. It is served at POST /mcp beside your HTTP routes, with the same config, models, and logs.

  1. agent

    “Summarize yesterday’s orders”

  2. mcp tool · app/mcp/tools.py
    class SummarizeOrders(Tool):    name = "summarize_orders"    description = "Summarize the orders for a day."     def schema(self):        return DayInput     async def handle(self, arguments: dict) -> Response:        day = arguments["date"]        orders = await Order.where("date", day).get()        return Response.text(f"{orders.count()} orders")
  3. your app
    • Order model
    • config
    • logging
    • database
07 / testing

Test agents like you test routes.

Fake or record any agent, assert on the tools it called, and grade answers with an LLM judge, all in the test runner you already use. Cassettes keep CI fast and offline.

.fake([...])
Deterministic replies, no API calls
.record()
Record once, replay from a cassette
assert_tool_called()
The agent called the right tool
assert_response_judged()
LLM-graded answer quality
Agent testing docs →
tests/test_support_agent.py
from unittest import IsolatedAsyncioTestCase
from app.agents import SupportAgent

class TestSupportAgent(IsolatedAsyncioTestCase):
    async def test_refund_request(self):
        with SupportAgent.record("refund.json") as agent:
            await agent.prompt("Refund order #1042")

            agent.assert_tool_called("lookup_order")
            await agent.assert_response_judged(
                expectation="Confirms the refund politely",
            )
uv run pytest tests/test_support_agent.py✓ 1 passed

Coming from Laravel? You already know it.

The same concepts and names, in Python. Pick a concept to compare.

Laravelapp/Models/Order.php
class Order extends Model
{
    protected $fillable = ['status'];
}

Order::where('status', 'paid')->get();
Startkitapp/models/order.py
class Order(Model):
    __table__ = "orders"

    id: int
    status: str

await Order.where("status", "paid").get()

Eloquent → Masonite ORM: $fillable becomes typed attributes

  1. Create

    uvx fastapi-startkit@latest init my-app
  2. Make a model

    uv run python artisan db:make:model Order
  3. Migrate

    uv run python artisan db:migrate

Start with one provider. Add the rest as you need them.

uvx fastapi-startkit@latest init my-app
Read the docs

Free and open source · Python 3.12+ · contributions welcome

A Laravel-style application framework for Python.© 2026 FastAPI Startkit