Commit graph

192 commits

Author SHA1 Message Date
Mateu Aguiló Bosch
0347dc85b4
[Server] Allow runtime-resolved element handlers (#294)
* [Server] feat: allow runtime handlers

Adds Mcp\Server\Handler\RunTimeHandlerInterface so integrators
(e.g. configuration-driven element sources) can register handlers
whose arguments and execution are resolved at runtime rather than
via PHP reflection of a callable.

ReferenceHandler::handle() dispatches instanceof RunTimeHandler
ahead of the callable/array/string branches, calls filterArguments
to narrow the argument map, and forwards execute() a ClientGateway
built from the active session.

The Registry-layer surface (ElementReference and the four
*Reference subclasses, RegistryInterface, Registry::register*,
ArrayLoader's handler-description helper) is widened to accept the
new type. The Builder/ArrayLoader path keeps its narrow callable
union; exposing runtime handlers there requires reworking
HandlerResolver and is left for a follow-up.

* feat(server): add runtime handler metadata API

Extend RunTimeHandlerInterface with four nullable metadata
accessors (getInputSchema, getOutputSchema, getPromptArguments,
getCompletionProviders) so the loader can obtain element
metadata without reflection.

Add RunTimeHandlerTrait providing null defaults for all four
accessors so single-purpose handlers can override only the
methods relevant to their element kind.

* feat(server): expose runtime handlers via Builder

Widen Builder::addTool, addResource, addResourceTemplate, and
addPrompt to accept RunTimeHandlerInterface instances alongside
the existing closure/array/string handler forms.

Branch ArrayLoader::load() on instanceof RunTimeHandlerInterface
in each of the four registration loops so runtime handlers skip
the reflection-based HandlerResolver/HandlerSchema path and pull
metadata from the interface accessors instead. Require explicit
name and description for runtime handlers and raise
ConfigurationException when missing or when a runtime tool has
no input schema source.

Replace direct $data['handler'] use in error log context with
getHandlerDescription() to avoid serializing large runtime
handler object graphs into log records.

Document the runtime handler API in docs/server-builder.md with a
new Runtime Handlers subsection and add a cross-reference from
docs/mcp-elements.md.

* test(server): cover runtime handler Builder path

Add ArrayLoaderRunTimeHandlerTest covering:
- successful tool registration with handler-supplied input schema,
  with kwarg input schema (precedence over the handler), and the
  same precedence rule for output schema
- ConfigurationException for tools missing name, description, or
  any input schema source
- successful resource registration via Builder kwargs and the
  matching missing-name failure mode
- successful resource template registration with completion
  providers sourced from the handler and the missing-description
  failure mode
- successful prompt registration with arguments and completion
  providers sourced from the handler, plus the missing-name
  failure mode
- a trait-only fixture verifying the four metadata accessors
  return null by default

Update existing ReferenceHandlerTest anonymous classes to use
RunTimeHandlerTrait so they satisfy the widened interface.

* refactor(server): split runtime handler interface

Splits RunTimeHandlerInterface into a minimal base contract (only
execute()) plus element-specific subtypes: RunTimeToolHandlerInterface,
RunTimePromptHandlerInterface, and
RunTimeResourceTemplateHandlerInterface. Each subtype declares only
the metadata accessors relevant to its element kind, so a tool
handler no longer has to no-op out prompt or template methods.

Drops the now-redundant RunTimeHandlerTrait and removes
filterArguments; execute() receives the full argument map directly.

Updates ArrayLoader, ReferenceHandler, and Builder type signatures
to use the per-element interfaces, and rewrites the Runtime
Handlers documentation accordingly.

* refactor(server): rename runtime handler interfaces to Runtime casing

Renames RunTimeHandlerInterface and its element-specific subtypes to
Runtime casing, adds a dedicated RuntimeResourceHandlerInterface so
addResource() rejects mismatched runtime handlers at the type level,
and strips _session and _request from arguments forwarded to runtime
handlers. Hardens ArrayLoader to re-throw ConfigurationException
without wrapping, and extracts inline test fixtures into
tests/Fixtures/Runtime/.

* chore: please the linting gods

* test(server): use Uuid::v4 for symfony/uid 5.4 compatibility

Uuid::v7() was added in symfony/uid 6.2 and breaks the Symfony 5.4
matrix job. Match the convention used elsewhere in the suite.

* refactor(server): split ArrayLoader registration

Extract per-element preparation into dedicated private prepare*
methods for tools, resources, templates, and prompts. Factor the
shared required-field assertion and reflected name/description
resolution into helpers.

* refactor(server): non-null runtime handler types

Drop nullable return types on RuntimeToolHandlerInterface::
getInputSchema(), RuntimePromptHandlerInterface::
getPromptArguments()/getCompletionProviders(), and
RuntimeResourceTemplateHandlerInterface::
getCompletionProviders() in favor of plain arrays.
ArrayLoader no longer needs the null-coalescing
fallbacks, and NullSchemaToolHandler plus its
ConfigurationException test become redundant.

* doc: update docs/server-builder.md

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* feat: peer revie feedback

Introduce a new `Builder::add(...)` pattern for a more generic runtime
handler.

* refactor(server): apply PR 294 review feedback

Move per-interface handler dispatch from ReferenceHandler into
ExplicitElementLoader by wrapping each ElementHandlerInterface in a
Closure that satisfies the existing callable contract, revert the
*Reference / Registry handler-type widening PR 294 introduced, throw
Mcp\Exception\InvalidArgumentException (not \TypeError) on mismatched
Builder::add() pairings, and rename two classes for clarity:

* Mcp\Capability\Registry\Loader\ArrayLoader -> ReflectedElementLoader
* Mcp\Schema\Resource -> Mcp\Schema\ResourceDefinition (no alias)

ReferenceHandler::prepareArguments() now injects ClientGateway by type
and binds an `array $arguments` / `array $variables` closure parameter
from the leftover inbound arguments. This addresses Antoine's coupling
concern (ReferenceHandler no longer knows about the four handler
interfaces) and Chris's package-exception preference, and clears the
phpdoc reserved-word collision Antoine flagged on the resource schema
class. Existing tests are re-targeted to exercise the closure path
through ExplicitElementLoader / ReferenceHandler.

* doc: address PR 294 review feedback

Apply Chris's line-level suggestions on docs/server-builder.md
(rewrap to 120 chars, smoothed Drupal mcp module name-drop in the
explicit-element registration section, exception name reads
Mcp\Exception\InvalidArgumentException), rewrap docs/mcp-elements.md
to 120 chars, and add 0.6.0 CHANGELOG entries covering the
Builder::add() entry point, the new handler interfaces, the new
ExplicitElementLoader, plus three BC breaks (Resource ->
ResourceDefinition rename, ArrayLoader -> ReflectedElementLoader
rename, mismatched-pairing exception swap).

* refactor: address self-review feedback

* CHANGELOG: drop spurious [BC Break] entry for the exception
  type Builder::add() raises (method is new in this PR).
* docs/server-builder: revert wrap-only edits to pre-existing
  main content; keep 120ch wrapping only for new sections.
* ExplicitElementLoader: trim verbose class docblock.
* ReferenceHandler: rename SPLAT_PARAMETER_NAMES constant to
  ARGUMENT_BAG_PARAMETERS.

* refactor: rename CallableHandler to Handler

* style: fix phpdoc param alignment

* refactor: inline $reference->handler access

* fix: maintainer review feedback

docs: mention ExplicitElementLoader in comment

docs: move Drupal reference to README list

docs: drop implementation-only changelog entry

docs: revert rewrap noise from mcp-elements.md

* style: fix phpdoc param alignment

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
Co-authored-by: soyuka <soyuka@users.noreply.github.com>
2026-05-29 07:16:12 +02:00
Volodymyr Panivko
293a5880e4
[Server] Compose StreamableHttpTransport security middleware via defaultMiddleware() factory (#307)
* [Server] Add CORS, DNS rebinding and protocol version middleware

Introduce three PSR-15 middleware for `StreamableHttpTransport` exposed
through a public `StreamableHttpTransport::defaultMiddleware()` factory
composed automatically when no middleware is passed.

- `CorsMiddleware`: secure-by-default (no `Access-Control-Allow-Origin`),
  configurable allowlist, reflects matching origin with `Vary: Origin`
  to protect shared caches.
- `DnsRebindingProtectionMiddleware`: validates `Origin`/`Host` against
  a hostname allowlist (localhost-only by default).
- `ProtocolVersionMiddleware`: rejects requests carrying an unsupported
  `Mcp-Protocol-Version` header with `400 Bad Request`.

The transport no longer applies CORS via an `instanceof + array_unshift`
post-hook; the middleware parameter is nullable — `null` installs the
secure defaults, `[]` disables them, and users compose by spreading
`StreamableHttpTransport::defaultMiddleware()`. `SESSION_HEADER` and
`PROTOCOL_VERSION_HEADER` are promoted to public constants so middleware
can reuse them.

BC breaks:
- The `corsHeaders` constructor parameter is removed; the `middleware`
  parameter shifts one position. Positional callers passing the old
  `corsHeaders` argument must switch to named arguments or drop it.
- Default `Access-Control-Allow-Origin` is no longer `*`.

Addresses #260 (DNS rebinding), #277 (CORS extraction) and #306
(protocol version validation).

* [Server] Address review feedback on middleware defaults

- CorsMiddleware: emit Access-Control-Allow-Methods/Headers only on
  preflight per CORS spec; tokenize Vary header to avoid substring
  false-positives; add allowCredentials flag that emits
  Access-Control-Allow-Credentials and throws when combined with
  wildcard origin.
- DnsRebindingProtectionMiddleware: return plain-text 403 body
  (HTTP-level rejection, not JSON-RPC); use parse_url(..., PHP_URL_HOST)
  for origin parsing; drop redundant unbracketed '::1' from default
  allowlist.
- ProtocolVersionMiddleware: use Error::forInvalidParams instead of
  forInvalidRequest -- JSON-RPC -32602 fits header-value rejection
  better.
- JsonRpcErrorResponse::create now accepts a JsonRpc\Error so callers
  choose the error code.
- StreamableHttpTransport: emit a warning log when an explicit empty
  middleware list is passed, so operators can spot accidental bypass
  of the default security stack.

* [Server] Fix CI: switch warning-log tests to PHPUnit mocks

Replace the anonymous AbstractLogger fixture in
StreamableHttpTransportTest with `$this->createMock(LoggerInterface::class)`
so the test does not declare a `log()` signature at all. That sidesteps
both the psr/log v1 LSP incompatibility (untyped parameter) and the
phpstan `missingType.parameter` complaint in one move, and matches how
the rest of the suite (CallToolHandlerTest etc.) fakes loggers.

* Update src/Server/Transport/Http/Middleware/CorsMiddleware.php

Co-authored-by: Antoine Bluchet <soyuka@users.noreply.github.com>

---------

Co-authored-by: Antoine Bluchet <soyuka@users.noreply.github.com>
2026-05-25 13:49:43 +02:00
dependabot[bot]
ee40ff523f
chore(deps): bump actions/download-artifact from 4 to 8 (#330)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 08:48:16 +02:00
dependabot[bot]
d2fc743553
chore(deps): bump actions/upload-artifact from 4 to 7 (#331)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 08:47:44 +02:00
Christopher Hertel
f12ea0ab58
Fix conformance score calculcation (#313) 2026-05-19 14:40:17 +02:00
Christopher Hertel
3e45b1f486
Streamline README and add conformance score badges (#312)
- Add a shields.io badge row to the README header (version, CI, PHP
  version, license, conformance scores, protocol/spec) to match the
  other official MCP SDKs.
- Expand "PHP Libraries Using the MCP SDK" into a curated, alphabetically
  sorted list of downstream projects.
- Add tests/Conformance/bin/score.php, a Symfony Console command that
  turns a conformance run's --output-dir into a shields.io endpoint JSON.
- Extend the weekly conformance workflow to score each run and publish
  the client/server pass-rate to the orphan `badges` branch that the
  README badges read.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:02:26 +02:00
Christopher Hertel
1300d2ee7d
Add title parameter to Builder::addResource() and addResourceTemplate() (#310)
#301 added the `title` field to the `Resource`/`ResourceTemplate` schema
classes and the `McpResource`/`McpResourceTemplate` attributes, but the
manual registration methods on `Builder` were never updated — so manual
registration could not set a resource title, unlike tools and prompts.

Add a `$title` parameter between `$name` and `$description` (matching
`addTool()`/`addPrompt()`) and propagate it through `ArrayLoader` when
constructing the `Resource`/`ResourceTemplate` objects.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:02:01 +02:00
Dayna Blackwell
a820497b62
Add title field to Resource and ResourceTemplate (#301)
The MCP specification (2025-11-25) defines an optional title field for
Resource and ResourceTemplate as a human-readable display label, distinct
from name (a short identifier). Tool and Prompt already implement this
field; Resource and ResourceTemplate were missing it.

Changes:
- Add title parameter to Resource and ResourceTemplate constructors
- Add title to fromArray(), jsonSerialize(), and PHPStan type arrays
- Add title to McpResource and McpResourceTemplate attributes
- Pass title through Discoverer when constructing schema objects
- Add tests for deserialization, serialization, and null omission

Fixes #296
2026-05-17 14:10:31 +02:00
Christopher Hertel
967c5cda4d
[Server] Untangle origin tracking from Registry (#302)
Drop the isManual flag from ElementReference and the discovery-state methods
from RegistryInterface. The Registry becomes a flat last-write-wins map;
DiscoveryLoader owns its own owned-set bookkeeping so re-running discovery
only removes elements it itself contributed. Adds ChainLoader for explicit
composition. Manual-over-discovered precedence is preserved via loader
ordering, not a flag on the reference.
2026-05-17 14:03:31 +02:00
Christopher Hertel
e00450a218
Bump protocol version to nov 25 (#308) 2026-05-17 14:02:40 +02:00
Antoine Bluchet
1d7100060f
[CI] Add weekly conformance run against latest upstream release (#304)
The PR pipeline only catches conformance changes when someone opens a
PR. Upstream `@modelcontextprotocol/conformance` releases between PRs
go untested. This adds a weekly cron + `workflow_dispatch` trigger
pinned to `@latest`, and opens a tracking issue on scheduled failures.
2026-05-17 14:02:19 +02:00
Christopher Hertel
5e0731f706
Add configurable session garbage collection (gcProbability/gcDivisor) (#258)
Make session GC probability configurable via gcProbability and gcDivisor
parameters, mirroring PHP's session.gc_probability/session.gc_divisor.
Exposed through both SessionManager constructor and Builder::setSession().

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-15 08:14:38 +02:00
Sven Münnich
73414d65f6
Add PSR-3 compliant exception context when logging exceptions (#300)
* Add PSR-3 exception context to caught error logs

* Apply review feedback
2026-05-12 23:20:42 +02:00
Christopher Hertel
bfc4728792
Fix case sensitivity for http header (#283) 2026-05-12 23:20:14 +02:00
SBNTT
06917f6af6
fix: Cannot pass null to nullable enum parameters (#299)
* nullable enum value

* fix tests
2026-05-08 10:15:14 +02:00
Dayna Blackwell
797472777f
[Schema] fix: allow URIs without double slash in Resource and ResourceTemplate (RFC 3986) (#297)
* fix: allow URIs without double slash in Resource and ResourceTemplate (RFC 3986)

The URI regex required "://" after the scheme, rejecting valid URIs
like urn:isbn:123, mailto:user@example.com, config:key, and data:
URIs. RFC 3986 only requires ":" after the scheme; the "//" is part
of the authority component which is optional.

Changed both Resource.URI_PATTERN and ResourceTemplate.URI_TEMPLATE_PATTERN
to require ":" instead of "://".

Adds data-provider tests for URIs without double slash in both classes.

Fixes #293

* Reword unit tests

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
2026-05-08 10:14:08 +02:00
johnhunt-lc
a929548f33
force application/json for the 202 if there are no messages in the queue when building a json response (#295) 2026-05-08 09:56:36 +02:00
johnhunt-lc
86bd845924
[Server] Allow overriding the default file name pattern for Discovery (#292)
* Add optional namePatterns capability to discovery so that the default scan for `*.php` files can be overridden.

* add default to namePatterns docs

* add an error check if we manage to pass in an empty list of patterns

* add unit tests (and a static entry to classmap for composer.json so it autoloads from a non .php file for the test)

* run php-cs-fixer

* change how default namePatterns are set and make sure all the annotations are correct

* Fix bad whitespace

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* switch to a const default instead of nullable with a check in the function to convert null to a default

* make sure we handle empty arrays

* formatting fixes

* Apply suggestion from @chr-hertel

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* Add changelog entry

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
2026-05-08 09:48:29 +02:00
Mateu Aguiló Bosch
fb2c8c2ee4
[Schema][Server] Add top-level title to Tool (#288) v0.5.0
* feat(schema): add top-level title to Tool

Mirror PR #278's Prompt change for Tool:

- Add optional ?string $title to Mcp\Schema\Tool between $name
  and $inputSchema. fromArray() now reads $data['title'];
  jsonSerialize() emits 'title' right after 'name'. The
  @phpstan-type ToolData gains title?: string.
- Add ?string $title to the #[McpTool] attribute between $name
  and $description.
- Note ToolAnnotations::$title as deprecated-for-display in
  favor of Tool::$title per MCP spec 2025-06-18 (PHPDoc only,
  field retained for BC).

Phase 1 of plan 01--tool-title-spec-compliance. Later phases
update Discoverer, Builder::addTool(), ArrayLoader, and the
conformance fixture to match the new signature.

* feat(server): thread title through discovery

- Discoverer::processMethod() now propagates McpTool::$title
  into every discovered Tool via named arguments.
- Builder::addTool() accepts ?string $title between $name and
  $description. [BC Break] positional callers passing the old
  $description as 3rd positional argument must switch to named
  arguments, matching the precedent set for addPrompt() in
  0.5.0.
- tests/Conformance/server.php migrated to named-argument form
  for every addTool() call.

Phase 2 of plan 01--tool-title-spec-compliance.

* feat(loader): forward title in ArrayLoader

ArrayLoader now reads 'title' from each tool config entry and
passes it into the Tool constructor, completing the wiring
from Builder::addTool() through array-driven registration.

The $tools @param array-shape typedef gains title: ?string
between name and description.

Phase 3 of plan 01--tool-title-spec-compliance.

* test(schema): cover Tool.title end-to-end

- New tests/Unit/Schema/ToolTest.php: constructor round-trip,
  jsonSerialize key-order when title set vs null, fromArray
  tolerance.
- New tests/Unit/Capability/Discovery/DiscovererToolTitleTest
  plus a TitleFixture class verifying McpTool(title: ...)
  propagates through discovery into the registered Tool.
- New tests/Unit/Capability/Registry/Loader/ArrayLoader...
  test verifying array-driven title propagation.
- Extend McpToolTest for title named-arg and default-null.
- Extend BuilderTest with addTool(title: 't') propagation.
- Update tests/Unit/.../RegistryTest, CallToolHandlerTest,
  ListToolsHandlerTest and examples/.../server.php
  new Tool(...) call sites to pass title (named args) so
  they match the new constructor signature.
- CHANGELOG 0.6.0 section: feature bullet + [BC Break]
  note for addTool() signature, mirroring 0.5.0 Prompt
  entries.
- docs/server-builder.md: addTool() row and prose now
  list title? between name and description.

Phase 4 of plan 01--tool-title-spec-compliance. All 730
phpunit tests pass; remaining phpstan warnings are
pre-existing and unrelated to Tool.title.

* refactor(schema): make Tool.title non-BC-breaking

Move `title` to the end of the Tool, Builder::addTool, and McpTool
attribute constructors with a default of null. This preserves
positional-argument compatibility and removes the need for
`title: null` boilerplate at call sites. JSON serialization order
(name, title, inputSchema, ...) is unchanged.

Also tighten the new tests: parameterize ToolTest with data
providers, fold the Discoverer title fixture into the existing
DiscoverableToolHandler, and drop the reflection-heavy Builder
test that overlapped with ArrayLoaderToolTitleTest.

* fix: move title after name

---------

Co-authored-by: DDEV User <nobody@example.com>
2026-04-26 15:37:40 +02:00
Christopher Hertel
97979ec48d
CS update after release of v3.95 (#282) 2026-04-26 12:39:27 +02:00
Christopher Hertel
abae36e888
[Client] add client conformance test suite (#279)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 12:33:21 +02:00
Sergei Predvoditelev
d5b00cd8ae
Fix PHPDoc type of GetPromptRequest::$arguments (#285) 2026-04-20 21:13:58 +02:00
Mateu Aguiló Bosch
73e4cc2456
style: apply php-cs-fixer and PHPStan fixes (#289)
* style: apply php-cs-fixer to test files

Addresses drift flagged by the default PHP-CS-Fixer config — mostly
adds missing `: void` return types on pre-existing test methods.

No behavioural changes.

* fix: resolve phpstan errors surfaced by qa

- Drop the obsolete `Method ::test*() has no return type specified`
  ignore rule — every test method now declares a return type, so
  the pattern never matches and phpstan reports it as unmatched.
- Remove `?? []` from two reads of `CallToolRequest::$arguments`;
  the property is typed `array` (non-nullable), so the coalesce is
  a no-op that phpstan flags.

---------

Co-authored-by: DDEV User <nobody@example.com>
2026-04-20 20:49:15 +02:00
Christopher Hertel
7af5a345c1
Add title field to Prompt for MCP spec compliance (#278)
The MCP 2025-11-25 specification defines an optional `title` property on
Prompt for human-readable display in UI contexts, distinct from the
programmatic `name` identifier. This was missing from the SDK.

BC Break: Builder::addPrompt() signature changed — $title parameter added
between $name and $description. Callers using positional arguments for
$description must switch to named arguments.

Closes #276
2026-04-14 10:04:35 +02:00
simon chrzanowski
863cfc1e78
[Server] feat: relax StrictOidcDiscoveryMetadataPolicy and add Dynamic Client Registration middleware (RFC 7591) (#269)
* feat: relax OIDC discovery policy and add Dynamic Client Registration middleware (RFC 7591)

- Add LenientOidcDiscoveryMetadataPolicy for providers that omit
  code_challenge_methods_supported (e.g. FusionAuth, Microsoft Entra ID)
- Keep StrictOidcDiscoveryMetadataPolicy RFC-aligned
- Add ClientRegistrationMiddleware handling POST /register and enriching
  /.well-known/oauth-authorization-server with registration_endpoint
- Update Microsoft example to use built-in LenientOidcDiscoveryMetadataPolicy

* fix: move metadata policy note under server.php in Files section

Address review comment: the LenientOidcDiscoveryMetadataPolicy bullet
was a behavioral note, not a file entry. Inline it into the server.php
description to keep the Files list consistent.

* fix: address Copilot review comments on ClientRegistrationMiddleware

- Decode JSON with assoc=true for registrar data so nested objects
  are associative arrays, not stdClass instances
- Add Cache-Control: no-store to all error responses (400), not just
  the success response (201)
- Rewind response body stream before returning unmodified response
  when metadata is not valid JSON, preventing empty body on read

* fix: harden ClientRegistrationMiddleware and improve test coverage

- Revert spurious .gitignore trailing newline
- Use JSON_THROW_ON_ERROR consistently in enrichAuthServerMetadata()
- Add comment clarifying the second json_decode in handleRegistration()
- Assert Cache-Control: no-store on registrar exception error response
- Add test for non-object JSON body in metadata enrichment path
- Extract createPlainTextHandler helper for non-JSON response tests

* fix: reject JSON array bodies in metadata enrichment

Treat JSON list arrays (e.g. [] or ["..."]) as invalid metadata in
enrichAuthServerMetadata() to prevent corrupting the response shape
by adding registration_endpoint to a non-object.

* fix: add RFC 7591 error codes, Content-Type validation, and docblock safety warning

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:27:27 +02:00
Sule-Balogun Olanrewaju
5d57b685a2
Fix to let schema attribute enum type hint allow null values (#271) 2026-04-11 17:21:14 +02:00
Sule-Balogun Olanrewaju
ea38ef7b62
Fix to make Symfony Finder component optional (#267) 2026-04-11 17:19:47 +02:00
Kyrian Obikwelu
85fddf5f0f
[Client] docs: introduce client SDK documentation and improve README structure (#259)
* docs: add comprehensive client SDK documentation

- Create new client documentation with examples and API reference
- Restructure README for better clarity and flow
- Add client examples to documentation index
- Update roadmap to mark client component as complete

* Update README.md

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* Apply suggestions from code review

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
2026-03-31 21:37:32 +02:00
Christopher Hertel
7a5d5f5cfb
Add soyuka to codeowners to make approvals count (#272) 2026-03-23 11:52:00 +01:00
Christopher Hertel
e8f5a8ba22
Extend elicitation enum schema compliance (#261) 2026-03-22 18:46:40 +01:00
dependabot[bot]
6a99196ca0
chore(deps): bump ramsey/composer-install from 3 to 4 (#268)
Bumps [ramsey/composer-install](https://github.com/ramsey/composer-install) from 3 to 4.
- [Release notes](https://github.com/ramsey/composer-install/releases)
- [Commits](https://github.com/ramsey/composer-install/compare/v3...v4)

---
updated-dependencies:
- dependency-name: ramsey/composer-install
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 13:42:50 +01:00
simon chrzanowski
faac4a525c
[Server] add a reference handler setter to server builder (#265)
* feat: add setReferenceHandler to Builder

Allow consumers to provide a custom ReferenceHandlerInterface
implementation (e.g. a security-aware decorator) instead of
always using the default ReferenceHandler.

* test: add BuilderTest for setReferenceHandler

- Fluent API returns builder instance
- build() succeeds with and without custom handler
- Integration test verifies custom handler intercepts tool calls

* style: fix codestyle in BuilderTest

* style: use imports instead of inline FQCNs in BuilderTest

* docs: add changelog entry for setReferenceHandler
2026-03-13 14:39:13 +01:00
Christopher Hertel
eac6f01d58
Improve middleware pipeline consistency (#262)
- Make MiddlewareRequestHandler final and use index counter instead of
  array_shift to avoid mutating internal state
- Make OAuthProxyMiddleware factory discovery consistently lazy via
  getter methods, matching httpClient and requestFactory pattern

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:25:23 +01:00
dependabot[bot]
591abb4620
chore(deps): update phpdocumentor/reflection-docblock requirement || ^6.0 (#256)
Updates the requirements on [phpdocumentor/reflection-docblock](https://github.com/phpDocumentor/ReflectionDocBlock) to permit the latest version.
- [Release notes](https://github.com/phpDocumentor/ReflectionDocBlock/releases)
- [Commits](https://github.com/phpDocumentor/ReflectionDocBlock/compare/5.6.0...6.0.2)

---
updated-dependencies:
- dependency-name: phpdocumentor/reflection-docblock
  dependency-version: 6.0.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 23:52:01 +01:00
Christopher Hertel
ee3132a2f9
Add changelog entries for client and server auth (#257) 2026-03-10 22:52:59 +01:00
Christopher Hertel
ae320646bf
Encapsulate session handling from protocol to new SessionManager (#247) 2026-03-10 18:09:15 +01:00
dependabot[bot]
a6ed01bec0
chore(deps): bump actions/checkout from 5 to 6 (#255)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 17:26:45 +01:00
dependabot[bot]
085e8d9ad6
chore(deps): bump actions/setup-node from 5 to 6 (#254)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 17:23:15 +01:00
Kyrian Obikwelu
3ef864c444
[Client] Feat: Implement MCP client component (#192)
* feat(client): add complete MCP client SDK with STDIO and HTTP transports

Add Client, Builder, ClientProtocol, ClientSession, and transport
implementations for communicating with MCP servers. Supports tools, resources, prompts, and real-time progress/logging notifications.

* refactor(examples): reorganize examples into server/ and client/ folders

* feat: add SamplingRequestHandler for handling server sampling requests

* feat: add setLoggingLevel method to control server logging verbosity

* refactor: make progress token dependent on request ID

* docs: Update server IP in usage instructions and add notes on sampling server requirements.

* feat: add complete() method for completion/complete requests

* refactor: properly parse and type initialize result

* refactor: standardize method names

* fix: revert changes to server related components

* fix: revert changes to server related components

* refactor: Restructure client transports and handlers into dedicated namespaces.

* fix: cs and php-stan errors fixes(partial)

* feat: Refactor request handlers to return `Response` or `Error` objects directly, adding a `SamplingException` and error logging for sampling requests.

* feat: Replace `ClientTransportInterface` with `TransportInterface` and move response result deserialization to client methods.

* refactor: remove redundant timeout check for intialize on transports

The processFiber that executes per tick while fiber is suspended already handles timeouts while waiting

* feat: broaden symfony/http-client dependency to support Symfony 5.4 to 8.0

* Update examples/client/README.md

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* Update examples/client/README.md

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>

* refactor: remove outgoing message queue from session and simplify transport send method to directly dispatch messages.

* refactor: Replace ClientSession with ClientState for clearer intent on runtime state management

* refactor: rename connectAndInitialize to connect for consistency

* chore: cs fix

* chore: use SamplingCallbackInterface instead of a closure for sampling request handler

---------

Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
2026-03-10 17:22:40 +01:00
Christopher Hertel
a5a738396d
Add dependabot configuration for composer and github actions (#248) 2026-03-10 17:11:17 +01:00
Christopher Hertel
528cff269f
Add basic roadmap (#249) 2026-03-10 17:10:58 +01:00
Volodymyr Panivko
e3f4b88768
[Server] Oauth2 based on middleware (#221)
* Add Middleware handlers to StreamableHttpTransport

* OAuth Implementation based on middleware

* OAuth Implementation based on middleware

* Add Middleware handlers to StreamableHttpTransport

* OAuth Implementation based on middleware

* OAuth Implementation based on middleware

Signed-off-by: Volodymyr Panivko <sveneld300@gmail.com>

* Address PR review feedback for OAuth middleware

* Apply php-cs-fixer to satisfy QA

* Use Mcp exception classes in OAuth middleware

* Refactor OAuth HTTP stack and add Microsoft example policies

* Fix QA PHPStan findings in OAuth examples and auth middleware

* Require OIDC discovery in JWKS provider and refine OAuth proxy behavior

* Remove local development docker artifacts from VCS

* Revert .gitignore changes for local docker files

* Fix body retrieval in OAuthRequestMetaMiddleware for proper string conversion

Signed-off-by: Volodymyr Panivko <sveneld300@gmail.com>

* Address OAuth PR review feedback and align example configs

* Fix QA style issues and add authorization docs

* Fix PHPStan typing issues in OAuth middleware

* Remove duplicate Middleware namespace, consolidate under Http\Middleware

Remove old Mcp\Server\Transport\Middleware\ classes that were duplicated
in Mcp\Server\Transport\Http\Middleware\ and Http\OAuth\. Update docs
to reference the correct namespaces.

* Address PR review: replace Throwable catch with specific exceptions, add JSON_THROW_ON_ERROR

- JwtTokenValidator: replace catch(\Throwable) with explicit
  \InvalidArgumentException|\UnexpectedValueException|\DomainException,
  letting RuntimeException from JwksProvider propagate as infrastructure errors
- OAuthProxyMiddleware: add \JSON_THROW_ON_ERROR to json_encode for metadata response
- Update tests to expect RuntimeException for JWKS infrastructure failures

---------

Signed-off-by: Volodymyr Panivko <sveneld300@gmail.com>
Co-authored-by: Volodymyr Panivko <volodymyr.panivko@togethernetworks.com>
2026-03-10 17:10:07 +01:00
Antoine Bluchet
61c20f1450
fix(session): initialize data lazily in save() to prevent uninitialized property access (#252) 2026-03-05 00:07:49 +01:00
Jonathan Renard
a98e01a4be
chore: remove final keyword on attributes classes (#240)
Co-authored-by: Jonathan Renard <jRenard@PRESTAMAC-175.local>
2026-03-01 21:54:03 +01:00
Edouard Courty
1f5f7e16a3
chore(http): create constant for session id header (#246) v0.4.0 2026-02-23 22:42:54 +01:00
Edouard Courty
158e64627f
feat(server): add server lifecycle events (#175)
Signed-off-by: Edouard Courty <edouard.courty2@gmail.com>
2026-02-23 22:40:43 +01:00
Den Delimarsky
04a9a16be2
Add SECURITY.md with GitHub Security Advisories guidance (#250) 2026-02-22 19:20:00 +01:00
Sule-Balogun Olanrewaju
2166b38d56
Add missing handler for resource subscribe and unsubscribe (#220) 2026-02-18 00:11:35 +01:00
Johannes Wachter
02e86377e4
Add elicitation support for server-to-client user input requests (#228)
- Add ElicitAction enum (accept/decline/cancel)
- Add schema definitions for elicitation fields (string, number, boolean, enum)
- Add ElicitationSchema wrapper for requestedSchema
- Add ElicitRequest and ElicitResult for elicitation/create method
- Update ClientCapabilities to support elicitation capability
- Add elicit() method to ClientGateway
- Store client capabilities in session during initialization
- Add comprehensive unit tests
- Add elicitation example server with book_restaurant, confirm_action, and collect_feedback tools
2026-02-15 23:34:19 +01:00
Sule-Balogun Olanrewaju
aafac3ddf5
Feat: Improve invalid resource template messages (#245) 2026-02-13 21:46:03 +01:00