Files
fastmcp-feedback/CONTRIBUTING.md
T
rsp2k daec2d9e72
Tests / test (==2.12.2) (push) Canceled after 0s
Tests / test (==2.14.3) (push) Canceled after 0s
Tests / test (>=3.3,<4) (push) Canceled after 0s
Tests / test (>=4,<5) (push) Canceled after 0s
Tests / test-postgres (==2.12.2) (push) Canceled after 0s
Tests / test-postgres (>=4,<5) (push) Canceled after 0s
Tests / canary (push) Canceled after 0s
Run the DatabaseSink tests against Postgres + pgvector as well as SQLite
The sink ships with a JSONB variant and is documented for asyncpg, but
the suite only ever exercised SQLite. The embeddings work will need
pgvector, so this adds a local Postgres stack and a way to run the
database tests on it, here and in CI.

- docker-compose.yml: ffb-postgres (pgvector/pgvector:pg16) on a private
  network, published on 127.0.0.1 only, with an init script that adds
  the vector extension to the test database and template1
- Makefile: pg-up/pg-down/pg-reset/pg-logs/pg-psql, test, test-pg,
  test-all, lint; .env is generated from .env.example with a random
  password, and FFB_TEST_DATABASE_URL from the environment wins over it
- tests: a db_url fixture parametrized over sqlite and postgres. The
  postgres leg skips unless FFB_TEST_DATABASE_URL is set, and creates a
  uniquely named database per test (with vector) that is dropped after.
  The DatabaseSink factories in the events, retention, correlation,
  soft-error and instrumentation tests now use it, so their 38 database
  tests run on both. The missing-events-table test accepts either
  backend's error. New tests check isolation and that vector works.
- asyncpg and pgvector added to the dev and test extras
- CI: a test-postgres job on FastMCP 2.12.2 and 4.x with a pgvector
  service container, failing if the Postgres cases skip
- CONTRIBUTING: how to run the suite against Postgres
2026-09-29 19:33:41 -06:00

6.5 KiB

Contributing to FastMCP Feedback

Thank you for your interest in contributing! This guide will help you get started.

Development Setup

Prerequisites

  • Python 3.11+
  • uv (recommended) or pip
  • Git

Getting Started

# 1. Fork the repository on git.supported.systems
# 2. Clone your fork
git clone git@git.supported.systems:YOUR_USERNAME/fastmcp-feedback.git
cd fastmcp-feedback

# 3. Create virtual environment and install dependencies
uv venv
uv pip install -e ".[dev]"

# 4. Verify setup
uv run pytest

Development Workflow

# Create feature branch
git checkout -b feature/your-feature-name

# Make your changes...

# Run tests
uv run pytest

# Run linting
uv run ruff check .
uv run ruff format .

# Run type checking (optional but appreciated)
uv run mypy src/fastmcp_feedback

# Commit with clear message
git commit -m "feat: Add support for custom validators"

# Push and create PR
git push origin feature/your-feature-name

Code Style

We use Ruff for linting and formatting:

# Check for issues
uv run ruff check .

# Auto-fix issues
uv run ruff check --fix .

# Format code
uv run ruff format .

Style Guidelines

  • Line length: 88 characters (Black default)
  • Imports: Sorted with isort (via Ruff)
  • Type hints: Required for public APIs
  • Docstrings: Google style for public functions

Testing

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov

# Run specific test file
uv run pytest tests/unit/test_tools.py

# Run specific test
uv run pytest -k "test_submit_feedback"

# Run only unit tests
uv run pytest -m unit

# Run only integration tests
uv run pytest -m integration

Running the tests against Postgres

The DatabaseSink tests run on SQLite by default. Each one also has a [postgres] variant that runs against a real Postgres 16 with pgvector when FFB_TEST_DATABASE_URL is set, and skips otherwise. The repo ships a compose stack for it (Docker required):

make pg-up      # start ffb-postgres and wait until healthy (creates .env on first run)
make test-pg    # whole suite, Postgres cases enabled
make test       # whole suite, SQLite only
make test-all   # both
make pg-down    # stop it; the data volume is kept (pg-reset deletes it)

The server listens on 127.0.0.1 only, on FFB_PG_PORT from .env (55433 by default; change it if that port is taken). make pg-psql opens a shell on it. Every Postgres test gets its own freshly created database with the vector extension, dropped when the test ends, so tests never see each other's rows. To write a test that runs on both backends, take the db_url fixture from tests/conftest.py: db_url("name") returns an async URL for an empty database, the same one for the same name within a test.

To point the suite at another server, set the variable yourself; the user needs permission to create and drop databases:

FFB_TEST_DATABASE_URL=postgresql+asyncpg://user:pass@host:5432/postgres uv run pytest -m postgres

Writing Tests

  • Place unit tests in tests/unit/
  • Place integration tests in tests/integration/
  • Use descriptive test names: test_submit_feedback_with_invalid_type_raises_error
  • Use fixtures from tests/conftest.py

Example test:

import pytest
from fastmcp_feedback import add_feedback_tools

@pytest.mark.unit
async def test_submit_feedback_creates_record(app_with_feedback, db_session):
    """Submitting feedback should create a database record."""
    result = await app_with_feedback.call_tool(
        "submit_feedback",
        type="bug_report",
        title="Test Bug",
        description="Description"
    )

    assert result["status"] == "success"
    assert result["id"] is not None

Pull Request Guidelines

Before Submitting

  1. Tests pass: uv run pytest
  2. Linting passes: uv run ruff check .
  3. New features have tests
  4. Documentation updated (if applicable)

PR Title Format

Use Conventional Commits:

  • feat: Add custom validation support
  • fix: Handle empty feedback list correctly
  • docs: Update installation instructions
  • test: Add edge case tests for insights
  • refactor: Simplify database connection logic

PR Description Template

## Summary
Brief description of changes.

## Changes
- Added X
- Fixed Y
- Updated Z

## Testing
How were these changes tested?

## Breaking Changes
None / List any breaking changes

Project Structure

fastmcp-feedback/
├── src/fastmcp_feedback/
│   ├── __init__.py       # Public API exports
│   ├── tools.py          # Main add_feedback_tools function
│   ├── models.py         # Pydantic models and SQLAlchemy ORM
│   ├── database.py       # Database connection management
│   ├── feedback.py       # Standalone server factory
│   ├── insights.py       # Privacy-compliant analytics
│   └── mixins/           # Modular tool mixins
│       ├── base.py
│       ├── submission.py
│       ├── retrieval.py
│       └── management.py
├── tests/
│   ├── conftest.py       # Shared fixtures
│   ├── unit/             # Unit tests
│   └── integration/      # Integration tests
├── pyproject.toml        # Package configuration
├── README.md
├── CONTRIBUTING.md       # This file
├── CHANGELOG.md
└── LICENSE

Adding New Features

Adding a New Mixin

  1. Create src/fastmcp_feedback/mixins/your_mixin.py
  2. Inherit from BaseMixin
  3. Implement register_tools(app, prefix="")
  4. Export from src/fastmcp_feedback/mixins/__init__.py
  5. Add to main __init__.py exports
  6. Write tests in tests/unit/test_your_mixin.py
  7. Update documentation

Adding a New Tool

  1. Add to appropriate mixin or create new one
  2. Use @app.tool() decorator with clear description
  3. Add Pydantic models for request/response if complex
  4. Write unit tests
  5. Add integration test
  6. Document in README

Versioning

We use calendar versioning (CalVer): YYYY.MM.DD

Version bumps happen automatically on release. Contributors don't need to update version numbers.

Getting Help

  • Questions: Open a discussion on the repository
  • Bugs: Open an issue with reproduction steps
  • Features: Open an issue describing the use case

License

By contributing, you agree that your contributions will be licensed under the MIT License.