FastAPI integration for apcore (AI-Perceivable Core). Expose your FastAPI routes as MCP tools with auto-discovery, Pydantic schema extraction, and built-in observability.
- Route scanning -- auto-discover FastAPI routes and convert them to apcore modules
- Annotation inference --
GET-> readonly+cacheable,DELETE-> destructive,PUT-> idempotent - Pydantic schema extraction -- input/output schemas extracted from Pydantic models and OpenAPI spec
- Two scanner backends -- OpenAPI-based (accurate) and native route inspection (fast)
- Simplified module IDs --
simplify_ids=Trueextracts clean function names from FastAPI operationIds @moduledecorator -- define standalone AI-callable modules with full schema enforcement- YAML binding -- zero-code module definitions via external
.binding.yamlfiles - MCP server -- stdio, streamable-http, and SSE transports via
fastapi-apcore serve - Observability -- distributed tracing, metrics, structured logging, error history, usage tracking
- Input validation -- validate tool inputs against Pydantic schemas before execution
- CLI-first workflow --
fastapi-apcore scan+fastapi-apcore servefor zero-intrusion integration - MCP Tool Explorer -- browser UI for inspecting modules via
--explorer - JWT authentication -- protect MCP endpoints with Bearer tokens via
--jwt-secret - Approval system -- require approval for destructive operations via
--approval - AI enhancement -- enrich module metadata using local SLMs via
--ai-enhance - Async tasks -- background task submission, status tracking, and cancellation
- Unified entry point --
FastAPIApcoreclass provides property-based access to all components
- Python >= 3.11
- FastAPI >= 0.100
- apcore >= 0.13.0
- apcore-toolkit >= 0.2.0
# Core
pip install fastapi-apcore
# With MCP server support (required for serve/export)
pip install fastapi-apcore[mcp]
# With CLI
pip install fastapi-apcore[cli]
# Everything
pip install fastapi-apcore[all]from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi_apcore import FastAPIApcore
apcore = FastAPIApcore()
@asynccontextmanager
async def lifespan(app: FastAPI):
apcore.init_app(app) # Auto-scan routes, discover modules, start MCP server
yield
app = FastAPI(lifespan=lifespan)
@app.get("/greet/{name}")
def greet(name: str) -> dict:
"""Greet a user by name."""
return {"message": f"Hello, {name}!"}Or use the factory pattern:
from fastapi import FastAPI
from fastapi_apcore import FastAPIApcore
apcore = FastAPIApcore()
def create_app() -> FastAPI:
app = FastAPI()
# ... add routers ...
apcore.init_app(app)
return app# Scan FastAPI routes -> register as apcore modules -> start MCP server
fastapi-apcore serve myapp.main:app --transport streamable-http --port 9090 --explorerThat's it. Your FastAPI routes are now MCP tools.
For Claude Desktop, add to your config:
{
"mcpServers": {
"my-fastapi-app": {
"command": "fastapi-apcore",
"args": ["serve", "myapp.main:app"]
}
}
}For HTTP transport (remote access):
fastapi-apcore serve myapp.main:app --transport streamable-http --host 0.0.0.0 --port 9090fastapi-apcore supports three ways to define AI-perceivable modules:
Scan existing FastAPI routes without modifying any code:
# Direct registration (in-memory)
fastapi-apcore scan myapp.main:app
# Generate YAML binding files (persistent)
fastapi-apcore scan myapp.main:app --output yaml --dir ./apcore_modules
# Preview without side effects
fastapi-apcore scan myapp.main:app --dry-run
# Filter routes by regex
fastapi-apcore scan myapp.main:app --include "users\." --exclude "\.delete$"Define standalone modules with explicit schemas:
from fastapi_apcore import FastAPIApcore
apcore = FastAPIApcore()
@apcore.module(id="math.add", tags=["math"], description="Add two numbers")
def add(a: int, b: int) -> int:
return a + bDefine modules via external .binding.yaml files in APCORE_MODULE_DIR:
bindings:
- module_id: users.greet
target: myapp.views:greet
description: "Greet a user by name"
tags: [users]
input_schema:
properties:
name: { type: string }
required: [name]
output_schema:
properties:
message: { type: string }The FastAPIApcore instance provides property-based access to all components:
apcore = FastAPIApcore()
# Properties (lazy-loaded singletons)
apcore.registry # apcore Registry
apcore.executor # apcore Executor (with extensions)
apcore.settings # ApcoreSettings
apcore.metrics_collector # MetricsCollector | None
apcore.context_factory # FastAPIContextFactory
apcore.task_manager # AsyncTaskManager
apcore.extension_manager # ExtensionManager
# Module execution
result = apcore.call("math.add", {"a": 1, "b": 2})
result = await apcore.call_async("math.add", {"a": 1, "b": 2}, request=request)
# Streaming
async for chunk in apcore.stream("ai.chat", {"prompt": "hello"}, request=request):
...
# With timeout/cancellation
result = apcore.cancellable_call("slow.task", timeout=30.0)
# Module introspection
apcore.list_modules(tags=["math"])
apcore.describe("math.add")
# Background tasks
task_id = await apcore.submit_task("batch.process", {"ids": [1, 2, 3]})
status = apcore.get_task_status(task_id)
await apcore.cancel_task(task_id)
# MCP serving
apcore.serve(transport="streamable-http", port=9090, explorer=True)
tools = apcore.to_openai_tools(strict=True)
# MCP helpers (inside module execution)
await FastAPIApcore.report_progress(context, progress=50, total=100)
response = await FastAPIApcore.elicit(context, "Please confirm")
# Singleton access
apcore = FastAPIApcore.get_instance()init_app() performs a complete initialization sequence:
apcore.init_app(
app, # FastAPI application instance
scan=True, # Auto-scan routes (default: True)
scan_source="openapi", # Scanner backend: "openapi" or "native"
include=None, # Regex: only register matching module IDs
exclude=None, # Regex: skip matching module IDs
)What init_app() does (in order):
- Auto-discover modules from YAML bindings and
APCORE_MODULE_PACKAGES - Scan FastAPI routes and register them as apcore modules
- Enable hot-reload if
APCORE_HOT_RELOAD=true - Start embedded MCP server if
APCORE_EMBEDDED_SERVERis configured
All settings are read from environment variables with the APCORE_ prefix:
| Variable | Default | Description |
|---|---|---|
APCORE_MODULE_DIR |
apcore_modules/ |
Directory for YAML binding files |
APCORE_AUTO_DISCOVER |
true |
Auto-discover modules on startup |
APCORE_BINDING_PATTERN |
*.binding.yaml |
Glob pattern for binding files |
APCORE_MODULE_PACKAGES |
— | Comma-separated packages to scan for @module |
APCORE_VALIDATE_INPUTS |
false |
Validate inputs before module execution |
| Variable | Default | Description |
|---|---|---|
APCORE_SERVE_TRANSPORT |
stdio |
MCP transport: stdio, streamable-http, sse |
APCORE_SERVE_HOST |
127.0.0.1 |
Host for HTTP transport |
APCORE_SERVE_PORT |
9090 |
Port for HTTP transport |
APCORE_SERVER_NAME |
apcore-mcp |
MCP server name |
APCORE_SERVER_VERSION |
— | MCP server version string |
APCORE_EXPLORER_ENABLED |
false |
Enable MCP Tool Explorer UI |
APCORE_EXPLORER_PREFIX |
/explorer |
URL prefix for Explorer |
APCORE_EXPLORER_ALLOW_EXECUTE |
false |
Allow execution from Explorer |
| Variable | Default | Description |
|---|---|---|
APCORE_JWT_SECRET |
— | JWT secret for MCP authentication |
APCORE_JWT_ALGORITHM |
HS256 |
JWT signing algorithm |
APCORE_JWT_AUDIENCE |
— | Expected JWT audience claim |
APCORE_JWT_ISSUER |
— | Expected JWT issuer claim |
APCORE_ACL_PATH |
— | Path to ACL YAML rules file |
APCORE_MIDDLEWARES |
— | Comma-separated middleware dotted paths |
| Variable | Default | Description |
|---|---|---|
APCORE_TRACING |
— | Enable tracing: true or JSON config |
APCORE_METRICS |
— | Enable metrics: true or JSON config |
APCORE_OBSERVABILITY_LOGGING |
— | Enable structured logging: true or JSON config |
| Variable | Default | Description |
|---|---|---|
APCORE_TASK_MAX_CONCURRENT |
10 |
Max concurrent background tasks |
APCORE_TASK_MAX_TASKS |
1000 |
Max total tasks in queue |
APCORE_TASK_CLEANUP_AGE |
3600 |
Max age (seconds) for completed tasks |
APCORE_CANCEL_DEFAULT_TIMEOUT |
— | Default cancellation timeout (seconds) |
| Variable | Default | Description |
|---|---|---|
APCORE_EXECUTOR_CONFIG |
— | JSON string for Executor configuration |
APCORE_CONTEXT_FACTORY |
— | Dotted path to custom ContextFactory class |
APCORE_HOT_RELOAD |
false |
Watch module files for changes |
APCORE_HOT_RELOAD_PATHS |
— | Comma-separated paths to watch |
APCORE_EMBEDDED_SERVER |
— | Auto-start MCP server on init: true or JSON config |
APCORE_OUTPUT_FORMATTER |
— | Dotted path to output formatter function |
APCORE_AI_ENHANCE |
false |
Enable AI metadata enhancement |
See fastapi_apcore.ApcoreSettings for the full list of 40 settings.
fastapi-apcore scan myapp.main:app [OPTIONS]| Option | Description |
|---|---|
--source, -s |
Scanner backend: openapi (default) or native |
--output, -o |
Output format: yaml. Omit for direct registration |
--dir, -d |
Output directory (default: APCORE_MODULE_DIR) |
--dry-run |
Preview without writing files or registering |
--include |
Regex: only include matching module IDs |
--exclude |
Regex: exclude matching module IDs |
--ai-enhance |
AI-enhance module metadata |
--verify |
Verify written output |
fastapi-apcore serve myapp.main:app [OPTIONS]| Option | Description |
|---|---|
--transport, -t |
Transport: stdio (default), streamable-http, sse |
--host |
Host for HTTP transport (default: 127.0.0.1) |
--port, -p |
Port for HTTP transport (default: 9090) |
--name |
MCP server name |
--explorer |
Enable MCP Tool Explorer UI |
--jwt-secret |
JWT secret key for authentication |
--approval |
Approval mode: off, elicit, auto-approve, always-deny |
--tags |
Comma-separated module tag filter |
--prefix |
Module ID prefix filter |
--validate-inputs |
Validate inputs before execution |
--output-formatter |
Dotted path to output formatter function |
--log-level |
Log level: DEBUG, INFO, WARNING, ERROR |
fastapi-apcore export [OPTIONS]| Option | Description |
|---|---|
--format, -f |
Export format (default: openai-tools) |
--strict |
Add strict: true for Structured Outputs |
--embed-annotations |
Include annotation metadata in descriptions |
--tags |
Comma-separated module tag filter |
--prefix |
Module ID prefix filter |
fastapi-apcore tasks list [--status STATUS]
fastapi-apcore tasks cancel TASK_ID
fastapi-apcore tasks cleanup [--max-age SECONDS]Two scanner backends are available:
| Backend | Method | Best for |
|---|---|---|
| OpenAPI (default) | Uses FastAPI's auto-generated OpenAPI spec | Accuracy, handles all FastAPI features |
| Native | Directly inspects app.routes |
Speed, no OpenAPI generation overhead |
from fastapi_apcore import get_scanner
# OpenAPI scanner (default) -- full operationId-based IDs
scanner = get_scanner("openapi")
modules = scanner.scan(app)
# OpenAPI scanner with simplified IDs (recommended for CLI)
scanner = get_scanner("openapi", simplify_ids=True)
modules = scanner.scan(app)
# product.get_product_product__product_id_.get → product.get_product.get
# Native scanner
scanner = get_scanner("native")
modules = scanner.scan(app, include=r"users\.", exclude=r"\.delete$")The simplify_ids option extracts the original Python function name from FastAPI's auto-generated operationId, producing much shorter and more readable module IDs. It defaults to False for backward compatibility.
fastapi_apcore/
__init__.py # Public API -- all user-facing exports
client.py # FastAPIApcore -- the main entry point
cli.py # Typer CLI (scan, serve, export, tasks)
engine/ # Internal engine (not for direct import)
config.py # ApcoreSettings -- env-based configuration
context.py # FastAPIContextFactory -- Request -> Identity
registry.py # Singleton management (Registry, Executor)
extensions.py # FastAPIDiscoverer + FastAPIModuleValidator
observability.py # Tracing/Metrics/Logging auto-setup
tasks.py # AsyncTaskManager singleton
shortcuts.py # Convenience functions
serializers.py # ScannedModule serialization
scanners/ # Route scanning backends
base.py # BaseScanner + ScannedModule
native.py # Direct route inspection
openapi.py # OpenAPI spec-based scanning
output/ # Output writers
registry_writer.py # Direct registry registration
yaml_writer.py # YAML binding file generation
Users only need to interact with two things:
FastAPIApcore-- the unified entry point (import fromfastapi_apcore)- CLI --
fastapi-apcore scan/serve/export/tasks
Everything in engine/ is internal wiring that FastAPIApcore manages automatically.
fastapi-apcore bridges FastAPI to the apcore protocol:
FastAPI App -> FastAPIApcore -> apcore (Registry/Executor) -> apcore-mcp (MCP Server)
All apcore types are re-exported for convenience:
from fastapi_apcore import (
Registry, Executor, Context, Identity, Config,
ACL, Middleware, ModuleAnnotations, FunctionModule,
CancelToken, PreflightResult, ModuleError,
ApprovalHandler, AutoApproveHandler, AlwaysDenyHandler,
EventEmitter, EventSubscriber, ApCoreEvent,
module, # @module decorator
)Apache-2.0