Skip to content

ci: discover MCP library releases on Packagist and test each minor - #9

Merged
naji247 merged 2 commits into
feat/plan-a-foundationfrom
feat/release-discovery
Oct 22, 2026
Merged

naji247 merged 2 commits into
feat/plan-a-foundationfrom
feat/release-discovery

Conversation

@naji247

@naji247 naji247 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Summary

CI now finds new releases of the MCP libraries by itself, the way the TypeScript SDK's mcp-compatibility.yml does with npm.

Before this change, CI tested fixed points only: the lowest and the highest version of each require-dev range, plus mcp/sdk 0.9.0, pinned. On 0.x versions, a caret range such as ^0.8.1 allows only 0.8.x. As a result, a new mcp/sdk 0.9.1 or 0.10, a symfony/mcp-bundle 0.15 or a laravel/mcp 2.0 never ran on a pull request. composer.json still lets a customer install all of them.

What changes

  • Discover job (ci.yml and nightly.yml): reads Packagist on every pull request and every night. It picks the newest patch of each minor release of mcp/sdk, laravel/mcp and symfony/mcp-bundle, starting at the lowest version that require-dev allows. Today it finds mcp/sdk 0.8.1 and 0.9.0, laravel/mcp 1.0.2 and 1.1.1, and symfony/mcp-bundle 0.13.0 and 0.14.1.
  • Released jobs: one job per discovered release. Each one runs PHPStan and the Contract, Integration and E2E suites. They replace the mcp/sdk 0.9.0 (PHP 8.5) job, and All green needs them.
  • Package probe: runs on each discovered mcp/sdk release, not on a fixed list. Each probe runs on the lowest PHP that CI tests and that release allows (8.3 today). A future release that drops PHP 8.3 then moves to 8.4, and pull requests stay green.
  • Nightly: runs the same release jobs and package probes. A failing release opens or updates one nightly issue per minor release, so a release published between pull requests reaches a person within a day. The issue shows why the release failed: the end of the install, PHPStan and PHPUnit output.
  • Scripts:
    • tests/bin/released-versions.php prints the releases for the job matrix. It tries a failed GET twice more, and the discover step makes sure that the result is a JSON list that is not empty.
    • tests/bin/require-library.sh installs one version of a library, then runs a full update so every root package can move. The local tests/bin/mcp-sdk-leg.sh uses it too.
    • composer/semver is now a dev dependency. It reads each release's PHP requirement; before, it came only through orchestra.
    • tests/Support/HttpGet.php holds the GET that branding-drift.php had inline.
  • Tests:
    • ReleaseDiscoveryTest covers the release selection: Packagist's minified rows, pre-releases, a new patch, minor or major, a floor inside a minor, 0.10 sorting after 0.9, and the PHP choice for each release.
    • WorkflowsTest makes sure that All green needs every gating CI job, that the release jobs and probes take the discovered releases, that the discovery knows the PHP versions of the tests job, and that every nightly job opens its issue when it fails.
  • Docs: the README and CONTRIBUTING describe the discovery instead of listing fixed tested versions. agentcathq/agentcat-ui#253 gets the same change.

Test plan

  • composer check: 3521 tests pass, and so do PHPStan (both configurations), Rector, php-cs-fixer and the dependency analyser
  • PHPStan on PHP 8.5 with phpstan.neon.dist and phpstan.php85.neon
  • shellcheck on require-library.sh and mcp-sdk-leg.sh
  • Local release jobs: mcp/sdk 0.9.0, symfony/mcp-bundle 0.13.0 and laravel/mcp 1.0.2 (901 tests each)
  • WorkflowsTest fails on the old workflows and passes on the new ones
  • The discover step with Packagist out of reach: it tries three times, exits 2, and keeps the message for the nightly issue
  • CI on this pull request runs all six release jobs and both package probes: every job passes
  • The nightly workflow runs on this pull request, because nightly.yml changed: every job passes

…agist

CI tested fixed versions of the MCP libraries: the lowest and highest of each
require-dev range, plus mcp/sdk 0.9.0 pinned. A caret range on 0.x stops at the
next minor, so a new mcp/sdk 0.9.1 or 0.10, symfony/mcp-bundle 0.15 or
laravel/mcp 2.0 never ran, although composer.json lets a customer install it.

Like the TypeScript SDK's mcp-compatibility.yml, a discover job now reads
Packagist on every pull request and every night. It picks the newest patch of
each minor release of mcp/sdk, laravel/mcp and symfony/mcp-bundle, from the
lowest version that require-dev allows. The released jobs run PHPStan and the
adapter suites against each of them, and the package probe runs on each mcp/sdk
release. In the nightly, a failing release opens an issue.

- tests/Support/ReleaseDiscovery.php selects the releases, and
  tests/bin/released-versions.php prints them for the matrix.
- tests/bin/require-library.sh installs one version of a library. The local
  tests/bin/mcp-sdk-leg.sh uses it too.
- tests/Support/HttpGet.php holds the GET that branding-drift.php had inline.
- WorkflowsTest makes sure that All green needs every gating CI job, that the
  released jobs take the discovered releases, and that every nightly job opens
  its issue when it fails.
- The released jobs replace the mcp/sdk 0.9.0 job.
The package probe ran on PHP 8.3 with every discovered mcp/sdk release. A
release that needs PHP 8.4 cannot install there, so every pull request would
fail without an AgentCat defect. ReleaseDiscovery now expands Packagist's
minified rows, reads each release's PHP requirement with composer/semver, and
gives each row the lowest PHP that CI tests and the release allows.

- The nightly also runs the package probe on each discovered mcp/sdk release.
- A nightly issue names the minor release, so a failure that lasts across its
  patches stays in one issue. The issue shows the end of the install, PHPStan
  and PHPUnit output, or the message of released-versions.php.
- released-versions.php tries a failed GET twice more, and exits 1 for an
  unreadable composer.json as its header says.
- The discover steps make sure that the output is a JSON list that is not
  empty before the matrix reads it.
- require-library.sh requires the version without an update, then runs a
  full update, so every root package can move.
- composer/semver is a dev dependency now; it came only through orchestra.
Base automatically changed from feat/plan-f-release to feat/plan-a-foundation October 22, 2026 23:00
@naji247
naji247 merged commit 108c361 into feat/plan-a-foundation Oct 22, 2026
44 checks passed
@naji247
naji247 deleted the feat/release-discovery branch October 22, 2026 23:01
@naji247 naji247 mentioned this pull request Oct 22, 2026
1 task
naji247 added a commit that referenced this pull request Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants