Skip to main content

flask-apcore

Flask Extension for apcore (AI-Perceivable Core) integration. Expose your Flask routes as MCP tools with auto-discovery, Pydantic schema inference, and built-in observability.

Features

  • Route scanning -- auto-discover Flask routes and convert them to apcore modules
  • Annotation inference -- GET -> readonly+cacheable, DELETE -> destructive, PUT -> idempotent
  • Pydantic schema inference -- input/output schemas extracted from type hints automatically
  • Docstring enrichment -- parameter descriptions from docstrings injected into JSON Schema
  • @module decorator -- define standalone AI-callable modules with full schema enforcement
  • YAML binding -- zero-code module definitions via external .binding.yaml files
  • Python output -- generate @module-decorated Python files from scanned routes
  • MCP server -- stdio and streamable-http transports via flask apcore serve
  • Observability -- distributed tracing, metrics, structured logging, error history, usage tracking
  • System modules -- built-in health, manifest, usage, and control modules (apcore 0.11.0+)
  • Input validation -- validate tool inputs against Pydantic schemas before execution
  • CLI-first workflow -- flask apcore scan + flask apcore serve for zero-intrusion integration
  • MCP Tool Explorer -- browser UI for inspecting modules via flask apcore serve --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
  • Unified entry point -- Apcore class provides property-based access to all components

Requirements

  • Python >= 3.11
  • Flask >= 3.0
  • apcore >= 0.13.0
  • apcore-toolkit >= 0.2.0

Installation

# Core
pip install flask-apcore

# With MCP server support (required for `flask apcore serve`)
pip install flask-apcore[mcp]

# All optional extras
pip install flask-apcore[mcp,smorest,restx]

Quick Start

1. Add Apcore to your Flask app

from flask import Flask
from flask_apcore import Apcore

app = Flask(__name__)
apcore = Apcore(app)

@app.route("/greet/<name>", methods=["GET"])
def greet(name: str) -> dict:
    """Greet a user by name."""
    return {"message": f"Hello, {name}!"}

Or use the factory pattern:

from flask import Flask
from flask_apcore import Apcore

apcore = Apcore()

def create_app():
    app = Flask(__name__)
    # ... register routes / blueprints ...
    apcore.init_app(app)
    return app

2. Scan routes and start MCP server

export FLASK_APP=app.py

# Scan Flask routes -> register as apcore modules
flask apcore scan

# Start MCP server (stdio, for Claude Desktop / Cursor)
flask apcore serve

That's it. Your Flask routes are now MCP tools.

3. Unified entry point

The Apcore instance provides property-based access to all components:

apcore = Apcore(app)

with app.app_context():
    # Properties
    apcore.registry           # Registry
    apcore.executor           # Executor (lazy-created)
    apcore.settings           # ApcoreSettings
    apcore.metrics            # MetricsCollector | None
    apcore.events             # EventEmitter | None
    apcore.error_history      # ErrorHistory | None
    apcore.usage              # UsageCollector | None

    # Convenience methods
    apcore.call("task_stats.v1")
    apcore.validate("task_stats.v1", {"key": "value"})
    apcore.list_modules(tags=["api"])
    apcore.describe("task_stats.v1")

4. Connect an MCP client

For Claude Desktop, add to your config:

{
  "mcpServers": {
    "my-flask-app": {
      "command": "flask",
      "args": ["apcore", "serve"],
      "env": { "FLASK_APP": "app.py" }
    }
  }
}

For HTTP transport (remote access):

flask apcore serve --http --host 0.0.0.0 --port 9100

Integration Paths

flask-apcore supports three ways to define AI-perceivable modules:

Route Scanning (zero-intrusion)

Scan existing Flask routes without modifying any code:

# Direct registration (in-memory)
flask apcore scan

# Generate YAML binding files (persistent)
flask apcore scan --output yaml --dir ./apcore_modules

# Generate Python module files
flask apcore scan --output python --dir ./apcore_modules

# Preview without side effects
flask apcore scan --dry-run

# Filter routes by regex
flask apcore scan --include "user.*" --exclude ".*delete"

# AI-enhanced module descriptions (requires APCORE_AI_ENABLED)
flask apcore scan --ai-enhance

# Verify written output
flask apcore scan --output yaml --verify

@module Decorator (precise control)

Define standalone modules with full schema enforcement:

from flask_apcore import Apcore, module
from pydantic import BaseModel

class SummaryResult(BaseModel):
    total: int
    active: int

@module(id="user_stats.v1", tags=["analytics"])
def user_stats() -> SummaryResult:
    """Return user statistics."""
    return SummaryResult(total=100, active=42)

app = Flask(__name__)
app.config["APCORE_MODULE_PACKAGES"] = ["myapp.modules"]
Apcore(app)

YAML Binding (zero-code)

Define modules externally in .binding.yaml files:

# apcore_modules/greet.binding.yaml
bindings:
  - module_id: greet.get
    target: app.greet
    description: "Greet a user by name"

Set APCORE_AUTO_DISCOVER=True (default) to load bindings on startup.

CLI Commands

flask apcore scan

Scan Flask routes and generate apcore module definitions.

Options:
  -s, --source [auto|native|smorest|restx]  Scanner source (default: auto)
  -o, --output [yaml|python]                Output format; omit for direct registration
  -d, --dir PATH                            Output directory (default: APCORE_MODULE_DIR)
  --dry-run                                 Preview without writing or registering
  --include REGEX                           Only include matching module IDs
  --exclude REGEX                           Exclude matching module IDs
  --ai-enhance                              AI-enhance module metadata (requires APCORE_AI_ENABLED)
  --verify                                  Verify written output

flask apcore serve

Start an MCP server exposing registered modules as tools.

Options:
  --stdio                  Use stdio transport (default)
  --http                   Use streamable-http transport
  --host TEXT              HTTP host (default: 127.0.0.1)
  -p, --port INT           HTTP port (default: 9100)
  --name TEXT              MCP server name (default: apcore-mcp)
  --validate-inputs        Validate tool inputs against schemas
  --log-level [DEBUG|INFO|WARNING|ERROR]

  Module Filtering:
  --tags TEXT              Comma-separated tags to filter modules
  --prefix TEXT            Module ID prefix filter

  Explorer:
  --explorer               Enable the MCP Tool Explorer UI
  --explorer-prefix TEXT   URL prefix for explorer (default: /explorer)
  --allow-execute          Allow Try-it execution in the explorer
  --explorer-title TEXT    Page title for Explorer UI
  --explorer-project-name  Project name shown in Explorer footer
  --explorer-project-url   Project URL shown in Explorer footer

  Authentication:
  --jwt-secret TEXT        JWT secret key for MCP auth (HTTP only)
  --jwt-algorithm ALGO     JWT signing algorithm (default: HS256)
  --jwt-audience TEXT      Expected JWT audience claim
  --jwt-issuer TEXT        Expected JWT issuer claim
  --require-auth/--no-require-auth  Require auth for all requests (default: True)
  --exempt-paths TEXT      Comma-separated paths exempt from auth

  Execution:
  --approval [off|elicit|auto-approve|always-deny]  Approval mode (default: off)
  --output-formatter TEXT  Output formatter dotted path (e.g., apcore_toolkit.to_markdown)

Configuration

All settings use the APCORE_ prefix in app.config:

app.config.update(
    # Core
    APCORE_AUTO_DISCOVER=True,          # Auto-load bindings and @module packages
    APCORE_MODULE_DIR="apcore_modules/",# Directory for binding files
    APCORE_BINDING_PATTERN="*.binding.yaml",  # Glob pattern for binding files
    APCORE_MODULE_PACKAGES=[],          # Python packages to scan for @module functions
    APCORE_SCANNER_SOURCE="auto",       # Scanner: auto, native, smorest, restx

    # System Modules (apcore 0.11.0+)
    APCORE_SYS_MODULES_ENABLED=False,   # Enable system modules (health, manifest, usage, control)
    APCORE_SYS_MODULES_EVENTS_ENABLED=False,  # Enable event system for platform notifications

    # Middleware & Execution
    APCORE_MIDDLEWARES=[],              # Middleware dotted paths (e.g. ["myapp.mw.AuthMW"])
    APCORE_ACL_PATH=None,              # ACL file path (e.g. "acl.yaml")
    APCORE_CONTEXT_FACTORY=None,       # Custom ContextFactory dotted path
    APCORE_EXECUTOR_CONFIG=None,       # Executor config dict (passed to apcore.Config)
    APCORE_EXTENSIONS=[],              # Extension plugin dotted paths

    # MCP Server
    APCORE_SERVE_TRANSPORT="stdio",     # Transport: stdio, streamable-http, sse
    APCORE_SERVE_HOST="127.0.0.1",      # HTTP host
    APCORE_SERVE_PORT=9100,             # HTTP port
    APCORE_SERVER_NAME="apcore-mcp",    # MCP server name
    APCORE_SERVER_VERSION=None,         # MCP server version string
    APCORE_SERVE_VALIDATE_INPUTS=False, # Validate inputs against schemas
    APCORE_SERVE_LOG_LEVEL=None,        # Log level: DEBUG, INFO, WARNING, ERROR
    APCORE_SERVE_TAGS=None,             # Filter modules by tags (list of strings)
    APCORE_SERVE_PREFIX=None,           # Filter modules by ID prefix

    # MCP Authentication
    APCORE_SERVE_JWT_SECRET=None,            # JWT secret key (enables auth when set)
    APCORE_SERVE_JWT_ALGORITHM="HS256",      # Signing algorithm
    APCORE_SERVE_JWT_AUDIENCE=None,          # Expected audience claim
    APCORE_SERVE_JWT_ISSUER=None,            # Expected issuer claim
    APCORE_SERVE_REQUIRE_AUTH=True,          # Require auth for all requests
    APCORE_SERVE_EXEMPT_PATHS=None,          # Paths exempt from auth (list of strings)

    # MCP Approval (apcore-mcp 0.8.0+)
    APCORE_SERVE_APPROVAL="off",             # Approval mode: off, elicit, auto-approve, always-deny
    APCORE_SERVE_OUTPUT_FORMATTER=None,      # Output formatter dotted path

    # MCP Tool Explorer
    APCORE_SERVE_EXPLORER=False,             # Enable Tool Explorer UI in MCP server
    APCORE_SERVE_EXPLORER_PREFIX="/explorer",# URL prefix for explorer
    APCORE_SERVE_ALLOW_EXECUTE=False,        # Allow Try-it execution in explorer
    APCORE_SERVE_EXPLORER_TITLE="MCP Tool Explorer",  # Explorer page title
    APCORE_SERVE_EXPLORER_PROJECT_NAME=None, # Project name in explorer footer
    APCORE_SERVE_EXPLORER_PROJECT_URL=None,  # Project URL in explorer footer

    # Observability
    APCORE_TRACING_ENABLED=False,       # Enable distributed tracing
    APCORE_TRACING_EXPORTER="stdout",   # Exporter: stdout, memory, otlp
    APCORE_TRACING_OTLP_ENDPOINT=None,  # OTLP collector URL (e.g. "http://localhost:4317")
    APCORE_TRACING_SERVICE_NAME="flask-apcore",  # Service name for traces
    APCORE_METRICS_ENABLED=False,       # Enable metrics collection
    APCORE_METRICS_BUCKETS=None,        # Custom histogram buckets (list of floats)
    APCORE_LOGGING_ENABLED=False,       # Enable structured logging
    APCORE_LOGGING_FORMAT="json",       # Format: json, text
    APCORE_LOGGING_LEVEL="INFO",        # Level: trace, debug, info, warn, error, fatal

    # Scan Options
    APCORE_SCAN_AI_ENHANCE=False,       # AI-enhance scanned modules (requires APCORE_AI_ENABLED)
    APCORE_SCAN_VERIFY=False,           # Verify written output by default
)

Observability

Enable tracing, metrics, and structured logging:

app.config.update(
    APCORE_TRACING_ENABLED=True,
    APCORE_TRACING_EXPORTER="otlp",
    APCORE_TRACING_OTLP_ENDPOINT="http://localhost:4317",
    APCORE_METRICS_ENABLED=True,
    APCORE_LOGGING_ENABLED=True,
    APCORE_LOGGING_FORMAT="json",
)

When observability is enabled, the following middleware is automatically wired into the Executor:

Middleware Trigger Purpose
TracingMiddleware TRACING_ENABLED Distributed tracing spans
MetricsMiddleware METRICS_ENABLED Latency histograms, call counts
ObsLoggingMiddleware LOGGING_ENABLED Structured log entries
ErrorHistoryMiddleware Any of above Ring buffer of recent errors
UsageMiddleware METRICS_ENABLED Per-module usage stats and trends
PlatformNotifyMiddleware SYS_MODULES_EVENTS_ENABLED Threshold-based event emission

System Modules

Enable built-in system modules for introspection and control:

app.config.update(
    APCORE_SYS_MODULES_ENABLED=True,
    APCORE_SYS_MODULES_EVENTS_ENABLED=True,  # Optional: enable event system
)

This registers:

  • system.health.summary / system.health.module — Health status
  • system.manifest.full / system.manifest.module — Module introspection
  • system.usage.summary / system.usage.module — Usage statistics
  • system.control.toggle_feature / system.control.update_config / system.control.reload_module — Runtime control

MCP Tool Explorer

The MCP Tool Explorer is a browser UI provided by apcore-mcp for inspecting registered modules and executing them interactively.

Security: Without JWT authentication, Explorer endpoints are unauthenticated. Either enable --jwt-secret or only expose in development/staging environments.

flask apcore serve --http --explorer --allow-execute \
    --explorer-title "My API Tools" \
    --explorer-project-name "My Project"

Browse to http://127.0.0.1:9100/explorer/ to view the interactive explorer with Try-it execution.

JWT Authentication

Protect MCP endpoints with JWT Bearer tokens (requires apcore-mcp>=0.10.0, HTTP transports only):

flask apcore serve --http \
    --jwt-secret "change-me-in-production" \
    --jwt-algorithm HS256 \
    --jwt-audience my-api \
    --jwt-issuer https://auth.example.com \
    --explorer --allow-execute

When JWT is enabled:

  • All MCP endpoints require a valid Authorization: Bearer <token> header
  • The Explorer UI shows a token input field for authentication
  • Use --no-require-auth to allow unauthenticated access
  • Use --exempt-paths to bypass auth for specific paths

Approval System

Require approval for module execution (apcore-mcp 0.8.0+):

# Interactive approval via MCP elicitation
flask apcore serve --http --approval elicit

# Auto-approve all (testing)
flask apcore serve --http --approval auto-approve

Docker Demo

A complete runnable demo is included in examples/demo/. It demonstrates the full pipeline: Flask CRUD routes with Pydantic schemas, route scanning, annotation inference, @module registration, MCP server, and observability.

cd examples/demo
docker compose up --build

See examples/demo/README.md for full details.

Public API

from flask_apcore import (
    Apcore,             # Flask Extension (unified entry point)
    module,             # @module decorator
    Registry,           # Module registry
    Executor,           # Module executor with middleware pipeline
    Context,            # Request context
    Identity,           # User identity
    ACL,                # Access control list
    Config,             # Executor configuration
    Middleware,          # Middleware base class
    ModuleAnnotations,  # Behavioral hints (readonly, destructive, etc.)
    ModuleDescriptor,   # Module metadata
    FunctionModule,     # Module wrapper for functions
    PreflightResult,    # Preflight validation result
    # Approval system
    ApprovalHandler,
    AutoApproveHandler,
    AlwaysDenyHandler,
    # Events
    EventEmitter,
    EventSubscriber,
    ApCoreEvent,
    # Cancellation
    CancelToken,
    # Errors
    ModuleError,
    ModuleNotFoundError,
    ACLDeniedError,
    SchemaValidationError,
    InvalidInputError,
    # System modules
    register_sys_modules,
)

Development

git clone https://github.com/aiperceivable/flask-apcore.git
cd flask-apcore
pip install -e ".[dev,mcp]"
pytest

License

Apache-2.0

Metadata

Release files for flask-apcore 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flask-apcore 0.4.0
File Size Uploaded
flask_apcore-0.4.0.tar.gz 155.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-apcore 0.4.0
File Interpreter ABI Platform
flask_apcore-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 200.8 kB

Release files / flask_apcore-0.4.0.tar.gz

Download URL flask_apcore-0.4.0.tar.gz
Size 155.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c1816b875c33b340371f64d2b24b62bdfb95d3e5fd7ecb66a7bd4cb917f4f3f8
BLAKE2b-256 checksum
How to use checksums
04a4ef4b1baee849fc4e9906125ea2e1ba8f6aaa490843f7afdc2ca81e1a39a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / flask_apcore-0.4.0-py3-none-any.whl

Download URL flask_apcore-0.4.0-py3-none-any.whl
Size 45.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
62d44e252554a3264c3d698ff613aae62a68542cbf72294670bceb3d7d2b5ec4
BLAKE2b-256 checksum
How to use checksums
f4045983b0e9e76f270eafec418cbc1dd15953e1e4fa572f3aea0fe931acfb7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page