Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mcp Client Laravel Laravel Package

redberry/mcp-client-laravel

Laravel client for the Model Context Protocol (MCP). Supports JSON-RPC 2.0 over Streamable HTTP (including SSE) and STDIO. Configure multiple servers and use a single facade to list/call tools and read resources, with per-request content negotiation.

View on GitHub
Deep Wiki
Context7
v2.0.0

This release contains breaking changes. See UPGRADE.md for the 1.x → 2.x migration guide.

Added

  • Laravel 13 and PHP 8.5 support. composer.json now allows illuminate/contracts: ^10.0||^11.0||^12.0||^13.0, php: ^8.3||^8.4||^8.5, and orchestra/testbench: ^8.22||^9.0||^10.0||^11.0. Laravel 10 remains installable in package constraints during user transitions but is no longer covered by CI. The CI test matrix now runs PHP 8.3/8.4/8.5 against Laravel 11/12/13 (each with its matching Testbench major), prefer-lowest and prefer-stable. PHPStan, Pint, Pest, and pest-plugin-laravel constraints widened to track the latest majors (Pest 4, pest-plugin-laravel 4, Larastan 3-only).
  • HTTP transporter now implements MCP's Streamable HTTP transport (2025-03-26): every request advertises Accept: application/json, text/event-stream and content-negotiates with the server, parsing either a single JSON response or an SSE stream of JSON-RPC messages.
  • New SseStreamParser helper for decoding text/event-stream responses.
  • Optional ?callable $onEvent parameter on MCPClient::callTool() and MCPClient::readResource() (and on the underlying Transporter::request() interface) for observing intermediate streamed events.
  • HttpTransporter constructor now accepts an optional Guzzle ClientInterface for dependency injection.
  • read_timeout config key on the HTTP transporter (default 60 seconds) — the maximum gap between SSE chunks before the parser aborts a wedged stream. The clock resets on every received chunk so long-running operations that stream progress events stay alive.
  • HTTP transporter now recovers from session loss: when a request to an active session returns HTTP 404 (the MCP 2025-03-26 signal for an expired/unknown session), the transporter clears the session, re-runs the initialize handshake, and retries the original request once. Configurable via the new max_session_retries key (default 1, set 0 to disable).

Changed

  • BREAKING: MCPClient::connect() is now immutable — it returns a clone configured for the requested server instead of mutating the root client in place. Holding two handles to two servers no longer silently routes both through the second connect(). Callers must capture or chain the return value: $gh = MCPClient::connect('github'); $gh->tools(); or MCPClient::connect('github')->tools(). The existing facade chain pattern in MCPClientCommand is unchanged. Repeated connect('same-server') reuses a cached Transporter on the root, so the initialize handshake is paid once per server per root instance.
  • BREAKING: MCPClient is now bound as a singleton in the service container (was bind()). Calls to app(MCPClient::class), the facade, and constructor-injected callers all resolve to the same instance now. Server config is captured at first resolve; if you mutate config('mcp-client.servers') at runtime, call app()->forgetInstance(\Redberry\MCPClient\MCPClient::class) to force a re-resolve.
  • BREAKING: Contracts\MCPClient is now aliased to the concrete singleton, so DI on the interface (function (Contracts\MCPClient $client)) resolves the same instance. Previously this raised an unresolvable container error.
  • Tightened return types on Contracts\MCPClient: tools(): Collection, resources(): Collection, callTool(): array, readResource(): array (all were untyped or mixed). The facade docblock now advertises callTool and readResource for IDE autocomplete.
  • MCPClient::connect() now throws RuntimeException with the configured-servers list when given an unknown server name (e.g. Unknown MCP server 'foo'. Configured servers: github, npx_server.) instead of falling through to the generic "Server configuration is not set" message.
  • STDIO transporter now decouples the per-request wait timeout from the subprocess kill-timer. New config keys: request_timeout (default 30s) for the waitForResponse() budget, and process_timeout (default null — kill timer disabled) for Symfony Process's 5th constructor argument. The legacy timeout key still works as a fallback for request_timeout only; it no longer doubles as a total-runtime cap, so long-lived sessions (e.g. queue workers issuing many tool calls over the same process) are no longer killed mid-flight after timeout seconds. BC note: users with timeout: 30 will now get "request waits 30s, process never killed" — typically what was wanted; pass process_timeout: 30 to restore the previous hard cap.
  • STDIO transporter env handling: when env is omitted (or empty), the package now passes null to Process so the subprocess inherits the parent env cleanly. When env is supplied, user keys are merged on top of the parent env (getenv()-derived map). Previously only PATH was forwarded, which silently broke npx / node whenever they needed HOME, NODE_OPTIONS, NPM_CONFIG_*, etc. New inherit_env: false opt-in for hermetic / sealed-env execution.
  • STDIO transporter startup-failure exceptions now include both stderr and stdout (with <empty> placeholders when missing) and the exit code, so missing-binary and npm-cache-miss surprises are diagnosable from the exception alone. The redundant error_log() call has been removed.
  • composer.json now explicitly requires guzzlehttp/guzzle and psr/http-message, which the HTTP transporter has always relied on transitively.
  • Both transporters now report protocolVersion: 2025-03-26 and source clientInfo.version from the installed composer package version (was hardcoded 0.1.0 on STDIO). Shared in a new Redberry\MCPClient\Core\Mcp value class.
  • HTTP transporter tests now exercise the real initialize + notifications/initialized handshake via constructor injection instead of poking private state with reflection. No production behavior change.
  • HTTP transporter JSON-RPC request ids now come from a per-instance incrementing counter (matching STDIO) instead of random_int(1, 1_000_000). Eliminates birthday-paradox collision risk from random id selection on long-lived sessions. The id_type config (int vs string) still controls the cast. The initialize handshake now uses the literal id "init" so a re-handshake after session loss never burns a slot of the user-request counter.
  • README clarifies that the optional $onEvent callback on callTool() / readResource() is a no-op under the STDIO transport (and under HTTP servers that reply with a single JSON message). It is always safe to pass; you do not need to branch on the active transport.

Fixed

  • MCPClient::callTool() and MCPClient::readResource() now throw the documented RuntimeException (per-method messages: "Call connect($serverName) before callTool()." and "Call connect($serverName) before readResource().") when called on an unconnected client. Previously they accessed an uninitialized typed property and surfaced a TypeError ("Typed property … must not be accessed before initialization") instead.
  • Spec-correct initialize handshake on the HTTP transporter — payload now includes protocolVersion, capabilities, and clientInfo, and the required notifications/initialized notification is sent before the first user request. Strict-spec MCP servers (the official TS reference, Anthropic's servers) previously rejected the bare initialize.
  • STDIO transporter sent the post-initialize notification with method initialized; renamed to spec-correct notifications/initialized.
  • SseStreamParser no longer raises a PHP warning when a server returns a JSON-RPC error without a message field; falls back to "Unknown JSON-RPC error" while preserving the error code.
  • HttpTransporter::parseResponse() now applies the same fallback for plain-JSON responses. A spec-compliant server returning {"error":{"code":-32000}} (no message) previously emitted a PHP warning and produced an empty exception message; it now throws TransporterRequestException with code -32000 and message "JSON-RPC error: Unknown JSON-RPC error".
  • STDIO transporter no longer fails the README's own npx -y [@modelcontextprotocol](https://github.com/modelcontextprotocol)/server-memory example on first run. The previous 3-second DEFAULT_TIMEOUT was below the cold-start time of npx -y (5–60s on first download); the new 30s request_timeout default covers it, and the kill timer is disabled by default so the second-and-later calls don't trip the same wall.
  • Collection::only() / except() now filter on the configured match key instead of always matching name. MCPClient::tools() returns a collection keyed by name; MCPClient::resources() returns one keyed by uri. Previously $client->resources()->only('file:///foo') silently returned an empty collection because resources have no name field — now it correctly filters by URI. Default match key remains 'name', so existing call sites for tools-shaped collections are unchanged.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope