flowlab
An API framework like FastAPI that also serves an MCP server at /mcp and runs
console commands, all from one app object. Database, cache, migrations and auth
are built in.
pip install flowlab
from flowlab import AuthSettings, FlowLab
app = FlowLab(auth_settings=AuthSettings())
@app.get("/")
def index() -> dict[str, str]:
return {"message": "Hello"}
@app.tool
def hello(name: str) -> str:
return f"Hello, {name}!"
@app.command("hello:say")
def say(name: str) -> None:
print(f"Hello, {name}!")
if __name__ == "__main__":
app.run()
Every migration lives in the project's migrations/ folder, including the
ones auth needs. python main.py auth:install copies them in (the starter
project already has them). For extra user fields, pass your own user_model;
see docs/auth.md.
python main.py auth:install # once: copies the users and api_keys migrations into migrations/
python main.py migrations:up
python main.py server:start # or: flowlab server:start (loads main:app from the cwd)
The FlowLab class
FlowLab(fastapi_settings=None, fastmcp_settings=None, typer_settings=None, *, database_settings=None, cache_settings=None, auth_settings=None, user_model=None, project_dir=None, **kwargs)
Every settings argument is optional; when it's left out, the settings are read
from the environment and .env.
FlowLab is a singleton: the database, cache, migrator and auth live on the one app.
FlowLab.instance()returns the app. Before one is created it raisesFlowLabNotInitialized, and so doget_db(),get_cache()and theDB/Cachedependencies. Creating a second app raisesFlowLabAlreadyInitialized.FlowLab.reset()closes and forgets the app (for tests);FlowLab.initialized()says whether one exists.app.db,app.cache: the open connections. Outsideapp.lifespan()(or a running server / command) they raiseNotConnected.app.migrator: aMigratorover the project'smigrations/folder (app.migrations_dir). The package never runs migrations of its own.app.auth: theAuthSettings. Auth is on whenauth_settingsis passed, which wires its routes, MCP tools and commands; otherwiseapp.authraisesAuthNotEnabled.**kwargsare passed toFastAPI(...).project_dirdefaults to the directory of the file that creates the app. A relative sqliteDB_NAMEand themigrations/folder resolve against it.appis itself an ASGI app (uvicorn main:appworks).app.apiis the FastAPI instance,app.mcpthe FastMCP server,app.clithe Typer app.- Routes:
app.get/post/put/patch/delete/api_route,app.include_router,app.add_middleware,app.exception_handler. - MCP:
app.tool,app.resource,app.prompt. Served atMCP_PATH(/mcp) as a stateless JSON route. - CLI:
app.command("namespace:verb", lifespan=True). Commands run inside the app lifespan (database and cache open) unlesslifespan=False. app.lifespan()is the one lifecycle used by HTTP, MCP and the CLI.app.add_lifespan(factory)adds a process-wide client to it. WithCACHE_DRIVER=database, opening the cache at startup runsCREATE TABLE IF NOT EXISTSforCACHE_TABLE; there is no migration for it.app.include_module(module)adds a module's routers. A module with migration templates gets a<name>:installcommand that copies the ones the project doesn't have yet intomigrations/, and a module with a schema check stops the server at startup withSchemaMismatchwhen its tables or columns are missing.app.user_model: yourBaseUsersubclass, passed asuser_model(see docs/auth.md).app.include_router(router, **options)takes all three kinds of router (see below).
Built-in commands: server:start, migrations:init|up|down|fresh|make, test,
queue:install|work|failed|retry|forget|flush|clear.
Run the CLI with python main.py <command>, flowlab <command> or
python -m flowlab <command>. The last two load main:app from the working
directory; pick another app with --app module:attribute or FLOWLAB_APP.
Routers
Split a project over files with one router per surface, then include each one:
from flowlab import APIRouter, CommandRouter, MCPRouter
api = APIRouter(prefix="/posts") # FastAPI's APIRouter
@api.get("/")
def posts() -> list[str]:
return []
mcp = MCPRouter("posts") # a FastMCP server
@mcp.tool
def count_posts() -> int:
return 0
console = CommandRouter()
@console.command("posts:prune")
def prune() -> None:
print("Pruned.")
app.include_router(api, tags=["posts"]) # options go to FastAPI.include_router
app.include_router(mcp, namespace="posts") # options go to FastMCP.mount; the tool becomes posts_count_posts
app.include_router(console)
flowlab also re-exports the FastAPI names a project needs, so routes can
import from one place: APIRouter, Depends, HTTPException, Request,
Response, Query, Path, Body, Header, Cookie, Form, File,
UploadFile, BackgroundTasks, Security, WebSocket, WebSocketDisconnect
and status.
Settings
All settings classes live in flowlab._settings and are exported from
flowlab: FastAPISettings, FastMCPSettings, TyperSettings,
DatabaseSettings, CacheSettings, QueueSettings, AuthSettings. They read the environment
and .env (from the working directory and from the directory of the script
being run).
Modules
flowlab.modules.db: query builder and ORM for SQLite, PostgreSQL, MySQL and MariaDB. See docs/db.md.flowlab.modules.cache: memory, database, Redis, Valkey and Memcached caches. See docs/cache.md.flowlab.modules.migrator: file-based migrations, publishing templates, schema drop helpers. See docs/migrator.md.flowlab.modules.auth: users, JWT login, API keys, MCP API key auth. See docs/auth.md.flowlab.modules.ratelimit: rate limits for routes and MCP tools, counted in the cache. See docs/ratelimit.md.flowlab.modules.queue: background jobs with@job, workers and failed-job commands, on the database, Redis, Valkey or Google Cloud Tasks. See docs/queue.md.
Extras: flowlab[postgres], flowlab[mysql], flowlab[asyncpg],
flowlab[redis], flowlab[valkey], flowlab[memcached], flowlab[gcp], flowlab[all].
Metadata
Release files for flowlab 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flowlab-0.2.0.tar.gz | 116.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flowlab-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 291.2 kB
Release files / flowlab-0.2.0.tar.gz
| Download URL | flowlab-0.2.0.tar.gz |
|---|---|
| Size | 116.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c865b4f4ef6d1093cbb2eba9c2de6b11087deaea6c33295198412c3da33624b0
|
|
BLAKE2b-256 checksum How to use checksums |
bd95b30489cec5bf3a8dbbe8418ec603507380f81b53b949691c2ef77e5403c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Release files / flowlab-0.2.0-py3-none-any.whl
| Download URL | flowlab-0.2.0-py3-none-any.whl |
|---|---|
| Size | 175.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b1e11f69f62df3174e8eb0a1db7fd0850aba39c374d94497ba8928d7c03ddabd
|
|
BLAKE2b-256 checksum How to use checksums |
6399dea4230fd3d15b12036e8269aa0128b0584469be8a9030a3d436b05e1772
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|