Skip to main content

Flask Production MCP

A static production-readiness auditor for Flask applications, usable three ways:

  • a CLI (flask-production-mcp audit) for local runs and scripts
  • a pre-commit hook and a GitHub Action so it runs at the right moments
  • an MCP server so an AI coding agent can call it while building

It answers "is this Flask app ready to deploy?" — not just "does it have security bugs?" — across nine categories:

Category What it checks
flask app-factory / blueprint discovery, route inventory, duplicate routes, debug mode enabled
architecture extensions bound at import time, module-level Flask() beside a factory, hardcoded SECRET_KEY fallback, db.create_all() instead of migrations, unguarded app.run(), unregistered blueprints
templates POST forms with no CSRF field, | safe / {% autoescape false %} on dynamic data, url_for() to an endpoint that doesn't exist
deployment Dockerfile running as root, dev server as the container command, base image on :latest, debug mode via env, secrets baked into an image/compose file, DB port published to the host, Gunicorn reload = True, dev server in a Procfile/entrypoint, committed .env, Nginx (server_tokens, missing forwarded headers, client_max_body_size, HTTP-only edge)
testing no test suite at all, a low line-rate in an existing coverage.xml, a test count that looks thin next to the number of routes
security eval/exec, pickle loads, hardcoded secrets, missing auth on sensitive routes, missing rate limiting, debug config — plus Bandit, folded in and de-duplicated
database SQLAlchemy models / relationships / indexes, raw SQL, missing indexes on filtered columns, likely N+1 access
dependencies known CVEs via pip-audit (PyPI + OSV) — requirements*.txt, or uv.lock / poetry.lock / Pipfile.lock, or the exact-pinned deps in a bare pyproject.toml
code_quality bare/broad except, print(), breakpoint(), assert in app code, TODO/FIXME (test modules excluded)

All analysis is static. The target application is never imported or executed; virtual-environments, caches and build dirs are skipped.

Findings: blockers vs. advisories vs. notes

Every finding has a severity and a confidence. The audit sorts them:

Tier Rule Gates a release?
blockers high-confidence critical/high yes
advisories other critical/high/medium — needs a judgement call no (configurable)
notes low / info cleanups no

The overall_score is confidence-weighted: a confirmed critical bites hard, a long tail of "consider an index" guesses barely moves it. A project is production_ready when it has no blockers and no single category has collapsed below the score floor (default 50).

Install

pip install flask-production-mcp

# with the dependency-CVE and Bandit scanners:
pip install "flask-production-mcp[scanners]"

# or, from a checkout:
uv sync --extra scanners

Python 3.11+. The base install is MCP + the static analyzers. The scanners extra adds pip-audit (needs network) and bandit; without it the audit reports those scans as skipped rather than failing.

CLI

flask-production-mcp audit path/to/your/flask/app
Flask Production Audit  --  /path/to/app
------------------------------------------------------------
Overall score  71/100          NOT READY

  flask          100   clean
  architecture    96   1 finding
  templates       55   1 finding (1 blocker)
  deployment     100   clean
  testing         92   1 finding
  security       100   clean
  database        76   6 findings
  dependencies   100   clean
  code_quality    79   7 findings

BLOCKERS (1)
  x [TMPL-CSRF-001] templates  app/templates/admin/products.html:242
      POST form has no CSRF token field
      -> Add a hidden CSRF field inside the form ...

Result: NOT production ready
  - 1 blocker(s) in templates
Flag Effect
--json emit the full JSON result
--github emit GitHub Actions ::error / ::warning annotations + job summary
--fail-on {blockers,advisories,any,never} what makes exit code 1
--skip-deps skip the CVE scan (no network)
--skip-bandit skip the Bandit scan
--config FILE use a specific config TOML
-q print blockers only

Exit codes: 0 pass · 1 fail (per --fail-on) · 2 bad usage.

Configuration

flask-production.toml in the project root, or [tool.flask-production] in pyproject.toml. See flask-production.toml.example.

fail_on = "blockers"
category_floor = 50
scan_dependencies = true
run_bandit = true
ignore = ["DB-PERF-001"]        # drop rules by id
select = []                      # if set, run ONLY these

[severity]
"ARCH-SEC-001" = "high"          # re-grade a rule for this project

pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/yemibalogun/flask-production-mcp
    rev: v0.1.0
    hooks:
      - id: flask-production-audit

The hook runs offline (--skip-deps --skip-bandit -q) and fails the commit on blockers only. Override args: to change that.

GitHub Action

# .github/workflows/audit.yml
jobs:
  flask-production-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: yemibalogun/flask-production-mcp@v0.1.0
        with:
          path: .
          fail-on: blockers      # or advisories / any / never

Findings appear as inline annotations on the PR and in the job summary.

MCP server

flask-production-mcp serve      # stdio

Register with an MCP client (Claude Code / Desktop):

{
  "mcpServers": {
    "flask-production": {
      "command": "flask-production-mcp",
      "args": ["serve"]
    }
  }
}

Then: "Run a production audit on /path/to/my_flask_app and list the blockers."

Tools

Tool Purpose
audit_flask_production Start here. Unified audit: overall_score, per-category score, production_ready + blocking_reasons, blockers / advisories / notes.
inspect_flask_project Structure only: file counts, blueprints, routes, indicators.
audit_flask Flask route/debug findings.
audit_architecture Flask-architecture rules.
audit_templates Jinja/HTML template findings.
audit_deployment Dockerfile / compose / Gunicorn / Nginx / Procfile findings.
audit_testing Test-suite presence and rough adequacy.
audit_security Security audit (incl. Bandit).
audit_database Database architecture + performance findings.
audit_dependencies Dependency CVE scan.
audit_code_quality Production code-quality findings.

Every audit_* tool returns the same envelope (success, project_path, score, summary, findings, recommendations, errors).

Development

uv run pytest
uv run ruff check src tests
uv run mypy src
src/flask_production_mcp/
├── cli.py                  # audit / serve subcommands
├── config.py               # flask-production.toml loader + finding policy
├── server.py               # MCP server, registers the tools
├── models/findings.py      # Finding / AuditSummary / AuditResult
├── analyzers/
│   ├── base.py             # scoring (weighted), classification
│   ├── exclusions.py       # shared file-walk + exclusion rules
│   ├── flask.py            # discovery + analyze_flask
│   ├── architecture.py     # Flask-architecture rules
│   ├── templates.py        # Jinja/HTML rules
│   ├── deployment.py       # Dockerfile / compose / Gunicorn / Nginx rules
│   ├── testing.py          # test-suite health
│   ├── security.py         # analyze_security
│   ├── bandit_scan.py      # Bandit integration
│   ├── database.py         # analyze_database
│   ├── dependencies.py     # pip-audit (requirements / lock / pyproject pins)
│   ├── code_quality.py     # analyze_code_quality_file
│   └── production.py       # analyze_production (unified, parallel)
└── tools/                  # one thin MCP wrapper per analyzer

Scope

Everything is static — the app is never run. So it does not do performance profiling or dynamic/runtime security testing (both need a live app + database), and the testing category reads an existing coverage.xml rather than producing one. Unpinned dependencies in a bare pyproject.toml can't be resolved to exact versions without installing — add a lock file for full CVE coverage.

Metadata

Release files for flask-production-mcp 0.1.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-production-mcp 0.1.0
File Size Uploaded Provenance
flask_production_mcp-0.1.0.tar.gz 77.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-production-mcp 0.1.0
File Interpreter ABI Platform
flask_production_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 173.2 kB

Release files / flask_production_mcp-0.1.0.tar.gz

Download URL flask_production_mcp-0.1.0.tar.gz
Size 77.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f91eec49ff5a85894a9461c7bd7c8693d068c7da87d4a4e8664a2c0fbe0085cb
BLAKE2b-256 checksum
How to use checksums
df320229ac06eeb18bfb81c590df7a1ec01f417cb8c4287a7ebace8ba942067c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / flask_production_mcp-0.1.0-py3-none-any.whl

Download URL flask_production_mcp-0.1.0-py3-none-any.whl
Size 95.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1d13ab58fbd5b2ddb3e293a1355ca3eb32857c35e8f231e307abd57582c2984d
BLAKE2b-256 checksum
How to use checksums
2e2eda046f448dc4e2663e2c325b5cc8bf1250e5ebb20fb6a0bbcb099c65038a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Security for flask-production-mcp 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for flask_production_mcp-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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