docs/development/contributing.mdx
Contributing to FastMCP means joining a community that values clean, maintainable code and thoughtful API design. All contributions are valued - from fixing typos in documentation to implementing major features.
Every contribution should advance these principles:
PRs are evaluated against these principles. Code that makes FastMCP slower, harder to reason about, less Pythonic, or less complete will be rejected.
Every pull request requires a corresponding issue - no exceptions. This requirement creates a collaborative space where approach, scope, and alignment are established before code is written. Issues serve as design documents where maintainers and contributors discuss implementation strategy, identify potential conflicts with existing patterns, and ensure proposed changes advance FastMCP's vision.
FastMCP is an opinionated framework, not a kitchen sink. The maintainers have strong beliefs about what FastMCP should and shouldn't do. Just because something takes N lines of code and you want it in fewer lines doesn't mean FastMCP should take on the maintenance burden or endorse that pattern. This is judged at the maintainers' discretion.
Use issues to understand scope BEFORE opening PRs. The issue discussion determines whether a feature belongs in core, contrib, or not at all.
FastMCP is an extremely highly-trafficked repository maintained by a very small team. Issues that appear to transfer burden to maintainers without any effort to validate the problem will be closed. Please help the maintainers help you by always providing a minimal reproducible example and clearly describing the problem.
LLM-generated issues will be closed immediately. Issues that contain paragraphs of unnecessary explanation, verbose problem descriptions, or obvious LLM authorship patterns obfuscate the actual problem and transfer burden to maintainers.
Write clear, concise issues that:
Issues may be labeled "Invalid" simply due to confusion caused by verbosity or not adhering to the guidelines outlined here.
PRs that deviate from FastMCP's core principles will be rejected regardless of implementation quality. PRs are NOT for iterating on ideas - they should only be opened for ideas that already have a bias toward acceptance based on issue discussion.
To contribute to FastMCP, you'll need to set up a development environment with all necessary tools and dependencies.
# Clone the repository
git clone https://github.com/PrefectHQ/fastmcp.git
cd fastmcp
# Install all dependencies including dev tools
uv sync
# Install prek hooks
uv run prek install
In addition, some development commands require just to be installed.
Prek hooks will run automatically on every commit to catch issues before they reach CI. If you see failures, fix them before committing - never commit broken code expecting to fix it later.
Large pull requests create review bottlenecks and quality risks. Unless you're fixing a discrete bug or making an incredibly well-scoped change, keep PRs small and focused.
A PR that changes 50 lines across 3 files can be thoroughly reviewed in minutes. A PR that changes 500 lines across 20 files requires hours of careful analysis and often hides subtle issues.
Breaking large features into smaller PRs:
FastMCP values clarity over cleverness. Every line you write will be maintained by someone else - possibly years from now, possibly without context about your decisions.
PRs can be rejected for two opposing reasons:
The focus is on idiomatic, high-quality Python. FastMCP uses patterns like NotSet type as an alternative to None in certain situations - follow existing patterns.
Full type annotations on all functions and methods. They catch bugs before runtime and serve as inline documentation.
Async/await patterns for all I/O operations. Even if your specific use case doesn't need concurrency, consistency means users can compose features without worrying about blocking operations.
Descriptive names make code self-documenting. auth_token is clear; tok requires mental translation.
Specific exception types make error handling predictable. Catching ValueError tells readers exactly what error you expect. Never use bare except clauses.
Complex one-liners are hard to debug and modify. Break operations into clear steps.
Mutable default arguments cause subtle bugs. Use None as the default and create the mutable object inside the function.
Breaking established patterns confuses readers. If you must deviate, discuss in the issue first.
# Runs automatically on commit, or manually:
uv run prek run --all-files
This runs three critical tools:
Pytest runs separately as a distinct workflow step after prek checks pass. CI will reject PRs that fail these checks. Always run them locally first.
Tests are documentation that shows how features work. Good tests give reviewers confidence and help future maintainers understand intent.
# Run specific test directory
uv run pytest tests/server/ -v
# Run all tests before submitting PR
uv run pytest
Every new feature needs tests. See the Testing Guide for patterns and requirements.
A feature doesn't exist unless it's documented. Note that FastMCP's hosted documentation always tracks the main branch - users who want historical documentation can clone the repo, checkout a specific tag, and host it themselves.
# Preview documentation locally
just docs
Documentation requirements:
<VersionBadge />FastMCP's SDK documentation is auto-generated from the source code docstrings and type annotations. It is automatically updated on every merge to main by a GitHub Actions workflow, so users are not responsible for keeping the documentation up to date. However, to generate it proactively, you can use the following command:
just api-ref-all
uv run prek run --all-files && uv run pytestWrite PR descriptions that explain:
Focus on the "why" - the code shows the "what". Keep it concise but complete.
Framework Philosophy: FastMCP is NOT trying to do all things or provide all shortcuts. Features are rejected when they don't align with the framework's vision, even if perfectly implemented. The burden of proof is on the PR to demonstrate value.
Code Quality: We verify code follows existing patterns. Consistency reduces cognitive load. When every module works similarly, developers understand new code quickly.
Test Coverage: Not every line needs testing, but every behavior does. Tests document intent and protect against regressions.
Breaking Changes: May be acceptable in minor versions but must be clearly documented. See the versioning policy.
contrib: Community-maintained patterns and utilities. Original authors maintain their contributions. Not representative of the core framework.
experimental: Maintainer-developed features that may preview future functionality. Can break or be deleted at any time without notice. Pin your FastMCP version when using these features.