MCP Context Server is licensed under the Elastic License 2.0 and is dual-licensed commercially by the project owner (see Commercial Licensing). To keep that model legally sound, every external contribution must grant the project owner the right to license the contributed code under any terms, including commercial ones.
By submitting a pull request, you agree that: (1) the contribution is your original work (or you have the right to submit it); (2) you grant Aleksandr Filippov a perpetual, worldwide, non-exclusive, irrevocable, royalty-free license to use, reproduce, modify, distribute, sublicense, and relicense your contribution under any license terms, including the Elastic License 2.0 and separate commercial licenses; and (3) you retain copyright in your contribution. A Developer Certificate of Origin sign-off alone is not sufficient, because it does not convey relicensing rights.
We welcome contributions! Please follow these guidelines:
- Fork the repository and create a feature branch
- Write tests for new functionality
- Run pre-commit hooks before committing
- Update documentation as needed
- Submit a pull request with a clear description
# 1. Clone and setup
git clone https://github.com/alex-feel/mcp-context-server.git
cd mcp-context-server
uv sync --all-extras --all-groups
# 2. Run tests
uv run pytest # Unit tests
uv run pytest -m integration # Integration tests
# 3. Test server locally
uv run python -m app.server # Should start without errors
# Press Ctrl+C to stop
# 4. Test published version (optional)
uvx --python 3.12 mcp-context-server # Run from PyPI without cloningImportant: Development requires ALL dependencies installed. Always use
uv sync --all-extras --all-groupsinstead of bareuv sync. This ensures all optional provider packages, type stubs, and development tools are available. Both local development and CI use this command. Running bareuv syncmay cause type-checker errors due to missing optional dependencies.
After code changes:
- Test your changes:
uv run pytest - Run code quality checks:
uv run pre-commit run --all-files
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=app --cov-report=html
# Run specific test file
uv run pytest tests/server/test_server.py
# Run metadata filtering tests
uv run pytest tests/core/test_metadata_filtering.py -v
uv run pytest tests/tools/test_metadata_error_handling.py -v
# Run semantic search tests
uv run pytest tests/tools/test_semantic_search_filters.py -v
# Run date filtering tests
uv run pytest tests/tools/test_date_filtering.py -v
# Run integration tests only
uv run pytest -m integration
# Skip slow tests for quick feedback
uv run pytest -m "not integration"# Run pre-commit hooks on all files, including Ruff, mypy, and pyright
uv run pre-commit run --all-filesEvery pull request runs Test and Test Summary (.github/workflows/test.yml) plus Run Pre-Commit Checks, MCP Checks and Security Scan (.github/workflows/lint.yml). The only exemption is Release Please's own version-bump PR, recognized by BOTH the release-please--branches-- head-branch prefix AND the PR author being the repository owner; the branch prefix alone is contributor-controlled and never sufficient on its own.
Repository setting maintainers must keep in place: these five jobs belong on the main branch ruleset as REQUIRED status checks. Without that, a job that is skipped rather than run shows up as neutral in the Checks tab, so a pull request whose CI never executed presents as having nothing failing. The workflow conditions decide when a job runs; only the ruleset makes a green result a merge requirement. This is a repository-settings change and cannot be made from the working tree.
We follow the Conventional Commits specification for all commit messages. This enables automated versioning and changelog generation.
Introduces new functionality or capabilities to the MCP Context Server.
Examples:
feat: add batch context retrieval endpointfeat: implement context search by date rangefeat: support WebP image format in multimodal storagefeat: add metadata filtering with 15 operators
Fixes issues or bugs in the existing codebase.
Examples:
fix: resolve database lock on concurrent writesfix: handle invalid base64 image data gracefullyfix: prevent memory leak in connection pool
Updates dependencies, refactors code, or performs housekeeping tasks.
Examples:
chore: update FastMCP to version 2.13chore: reorganize repository module structurechore: clean up unused test fixtures
Improves or updates documentation, including README, API docs, or code comments.
Examples:
docs: add examples for multimodal context storagedocs: update MCP client configuration guidedocs: clarify thread-based context scoping in architecture
Modifies continuous integration, deployment pipelines, or automation workflows.
Examples:
ci: add automated PyPI release workflowci: configure pre-commit hooks for type checkingci: enable coverage reporting in GitHub Actions
Adds or modifies tests, including unit, integration, or end-to-end tests.
Examples:
test: add integration tests for thread isolationtest: implement concurrent write test scenariostest: validate multimodal context deduplicationtest: add comprehensive metadata filtering tests
The commit type determines how the version number is incremented:
feat:→ Minor version bump (0.x.0)fix:→ Patch version bump (0.0.x)feat!,fix!, orBREAKING CHANGE→ Major version bump (x.0.0)
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Examples:
feat: add support for compressed image storage
Implements automatic image compression for attachments larger than 1MB, reducing database size by up to 70% while maintaining visual quality.
Closes #42
fix: resolve race condition in repository initialization
The database connection manager now uses a lock to prevent concurrent initialization attempts during high load.
Releases are automated using Release Please.
- Conventional commits on
mainbranch are tracked automatically - Release Please creates/updates a release PR with changelog
- Merging the release PR:
- Creates a GitHub release with semantic version tag
- Triggers
publish.ymlworkflow viarelease:publishedevent
On release, three jobs run from .github/workflows/publish.yml:
| Job | Depends On | Output |
|---|---|---|
publish-to-pypi |
build |
Package on PyPI |
publish-docker-image |
build |
Image on GHCR |
publish-to-mcp-registry |
publish-to-pypi |
Entry in MCP Registry |
PyPI and Docker publishing run in parallel. MCP Registry waits for PyPI.
Registry: ghcr.io/alex-feel/mcp-context-server
Platforms: linux/amd64, linux/arm64
Tags (for release v0.14.0):
0.14.0- Full version0.14- Minor version0- Major versionsha-abc1234- Git commit SHAlatest- Most recent release
Supply Chain Security:
- SLSA provenance attestation
- Software Bill of Materials (SBOM)
- Cryptographically signed build provenance via
actions/attest-build-provenance
If a new version was successfully published to PyPI but failed to publish to MCP Registry, follow this recovery procedure:
-
Fix the root cause: Identify and fix whatever prevented MCP Registry publication (e.g.,
server.jsonschema validation errors, network issues). -
Commit and push/merge fixes without triggering Release Please: Use commit types that do NOT trigger a new release. Avoid
featandfixprefixes, as these trigger Release Please to propose a new version with an incorrect changelog.Allowed commit types for fixes:
chore:- Maintenance tasksci:- CI/CD changesdocs:- Documentation updatestest:- Test modifications
Example:
git add server.json git commit -m "chore: fix server.json schema for MCP Registry" git push origin main -
Delete the remote tag: This makes the already-published GitHub release become a draft.
git push origin :refs/tags/v0.10.0
-
Create a new local tag: Point the tag to the latest commit (with your fixes).
git tag -fa v0.10.0 -m "v0.10.0" -
Push the updated tag:
git push origin v0.10.0
-
Re-publish the GitHub release: In the GitHub UI, navigate to Releases, find the draft release, and click "Publish release". This triggers the publish workflow:
- PyPI publication is skipped (version already exists due to
skip-existing: true) - Docker image is rebuilt and pushed (tags are overwritten)
- MCP Registry publication proceeds with the fixed files
- PyPI publication is skipped (version already exists due to
Important: Replace v0.10.0 with your actual version tag in all commands.
- Check existing GitHub Issues
- Read the README.md for usage documentation
- Create a new issue with detailed information if needed