Skip to content

Latest commit

 

History

History
114 lines (83 loc) · 5.12 KB

CONTRIBUTING.md

File metadata and controls

114 lines (83 loc) · 5.12 KB

Contributing

Thanks for considering a contribution to the PHP SDK for the Model Context Protocol. This is a collaboration between the PHP Foundation and the Symfony project, and it follows Symfony's conventions throughout.

Ways to contribute

  • Report a bug or propose a feature by opening an issue. Check existing issues first — many spec-driven changes are already tracked under the relevant 2026-07-28-style release label.
  • Send a pull request for a fix, a new capability, or a docs improvement.
  • Improve the guides under docs/ — see Documentation below for how they're built.
  • Help close a conformance gap — make conformance-tests runs the official MCP conformance suite against this SDK; a failing scenario there is a concrete, well-scoped contribution.

Development setup

Requires PHP 8.1+.

composer install

Before opening a pull request

Run the full CI suite locally:

make ci

This runs, in order: make deps-stable (composer update --prefer-stable), make cs (PHP CS Fixer, auto-fixes style), make phpstan (static analysis) and make tests (all PHPUnit suites). All of them must pass.

The interop suite runs against Node packages. Install them once before you run make ci or make tests:

npm ci --include=dev --prefix tests/Interop

If your change touches protocol-observable behavior, also run:

make conformance-tests   # requires Docker and Node (npx)

Coding standards

This project follows Symfony's coding standards and backward compatibility promise. In short:

  • Until 1.0, a release can break backward compatibility. Add a [BC Break] entry to CHANGELOG.md for every break.
  • When the spec deprecates a feature, mark the code that implements it with a @deprecated tag and call trigger_deprecation() when it's used. After 1.0, this applies to every removal. The deprecation policy describes the tag and the removal window.
  • Code marked @internal is not covered by the promise.

Tests

New capabilities need unit tests (tests/Unit/) covering the core logic, and — for anything reachable over the wire — end-to-end coverage. The suites are split by what they prove:

  • Integration (tests/Integration/, make integration-tests): our client and our server agree with each other. Fixture servers cover single features; ClientExamples/ runs every script in examples/client/, one test class per example, piping "user input" to STDIN where an example asks for it, and snapshots what it prints.
  • Interop (tests/Interop/, make interop-tests, needs Node): each half works with an implementation we did not write. Server/ drives a selection of the example servers with the MCP Inspector, one test class per example; Client/ runs our client against the TypeScript SDK's reference server, @modelcontextprotocol/server-everything, over stdio and HTTP. Both are installed from tests/Interop/package-lock.json (npm ci --include=dev --prefix tests/Interop), so a release of one of their dependencies cannot change what the snapshots see.
  • Conformance (tests/Conformance/, make conformance-tests): each half passes the specification's scripted scenarios.

Snapshots are written on the first run; delete one to re-record it. If you're adding a documented pattern, consider adding or updating an example under examples/ along with its test class.

Documentation

The guides under docs/ are built with Zensical in --strict mode, which fails the build on a broken internal link. The build runs Zensical through uv, so install uv first, then run:

make docs-guides

Links between guide pages must be relative paths that resolve within docs/ (e.g. protocol-versions.md, ../README.md will not resolve — Zensical only follows the docs/ tree). For anything at the repo root (README.md, ROADMAP.md, CHANGELOG.md), link to it by its GitHub URL instead, matching the pattern already used across docs/. The class-level API reference is generated separately by phpDocumentor (make docs-api) and isn't hand-written.

Versioning

The SDK follows Semantic Versioning — see SDK tier target for what that means pre- and post-1.0, and how it lines up with Symfony's backward compatibility promise.

Licensing

New contributions are licensed under Apache License, Version 2.0. Existing code predating this policy remains under the MIT License — see LICENSE for the details. By opening a pull request, you agree your contribution is provided under those terms.

Getting help

If something is unclear or you want early feedback on an approach before writing code, open an issue or a draft pull request — that's the right place to ask, rather than guessing at scope.