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
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
- Tests pass:
uv run pytest - Linting passes:
uv run ruff check . - New features have tests
- Documentation updated (if applicable)
PR Title Format
Use Conventional Commits:
feat: Add custom validation supportfix: Handle empty feedback list correctlydocs: Update installation instructionstest: Add edge case tests for insightsrefactor: 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
- Create
src/fastmcp_feedback/mixins/your_mixin.py - Inherit from
BaseMixin - Implement
register_tools(app, prefix="") - Export from
src/fastmcp_feedback/mixins/__init__.py - Add to main
__init__.pyexports - Write tests in
tests/unit/test_your_mixin.py - Update documentation
Adding a New Tool
- Add to appropriate mixin or create new one
- Use
@app.tool()decorator with clear description - Add Pydantic models for request/response if complex
- Write unit tests
- Add integration test
- 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.