InstrumentationMiddleware (and instrument(app)) records every tool call on a FastMCP server: tool, timing, outcome and original error type, session and request ids, argument and result sizes, plus identity and enrichment hook output. Modes off/meta/full; full adds redacted args and results. Recording can't slow or break a call. Records reach sinks through a bounded queue drained by a background task and are dropped, counted, when it fills. Sink and hook failures are logged, never raised, and async hooks are cut off after hook_timeout. Redactor strips secrets by key at any depth and by value pattern from args, results, error text and hook output. DatabaseSink runs on async SQLAlchemy, takes a host AsyncEngine, writes to a prefixed table and never creates it unless asked; build_metadata() plugs into Alembic env.py. Verified on FastMCP 2.12.2, 2.14.3, 3.3.1, 3.4.7 and 4.0.10. CI matrix gains 3.x. Version 2026.09.27.1.
68 lines
1.9 KiB
YAML
68 lines
1.9 KiB
YAML
name: Tests
|
|
|
|
# fastmcp-feedback declares fastmcp>=2.12.2,<5, so every version family in
|
|
# that range gets the full suite. A user on PyPI gets the newest FastMCP the
|
|
# range allows, not what uv.lock pins, which is how 2026.01.12.1 shipped with
|
|
# composition broken on 2.14 and 4.x without anyone noticing.
|
|
|
|
on:
|
|
push:
|
|
pull_request:
|
|
workflow_dispatch:
|
|
schedule:
|
|
# Weekly, so a new FastMCP release is caught even when nobody pushes
|
|
- cron: '17 9 * * 1'
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
fastmcp: ['==2.12.2', '==2.14.3', '>=3.3,<4', '>=4,<5']
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: astral-sh/setup-uv@v6
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install against fastmcp${{ matrix.fastmcp }}
|
|
run: |
|
|
uv venv
|
|
uv pip install -e ".[dev]" "fastmcp${{ matrix.fastmcp }}"
|
|
uv pip show fastmcp | grep -i '^version'
|
|
|
|
- name: Lint
|
|
run: uv run --no-sync ruff check src/ examples/ tests/_compat.py tests/unit/test_instrumentation.py
|
|
|
|
- name: Test
|
|
run: uv run --no-sync pytest -q --no-cov
|
|
|
|
# Newest FastMCP with no ceiling. Allowed to fail: it exists to say
|
|
# "a new major version is out and here is what breaks" before users do.
|
|
canary:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
continue-on-error: true
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: astral-sh/setup-uv@v6
|
|
with:
|
|
python-version: '3.13'
|
|
|
|
- name: Install newest FastMCP, ignoring our ceiling
|
|
run: |
|
|
uv venv
|
|
uv pip install fastmcp "sqlalchemy[asyncio]" aiosqlite pydantic \
|
|
pytest pytest-asyncio pytest-cov pytest-mock pytest-html
|
|
uv pip install --no-deps -e .
|
|
uv pip show fastmcp | grep -i '^version'
|
|
|
|
- name: Test
|
|
run: uv run --no-sync pytest -q --no-cov
|