MCP SDK PHP

repository·main·Indexed 18 days ago

https://github.com/logiscape/mcp-sdk-php

A PHP implementation of the Model Context Protocol (MCP) providing client and server capabilities for standard PHP, Apache, and cPanel environments. It supports modern stateless core specifications, OAuth 2.1 protection, and extensions such as MCP Apps (SEP-1865) for host-rendered tool UIs and the Tasks extension (SEP-2663) for long-running tasks. The SDK includes a conformance testing suite to validate behavior against both stable and draft (2026-07-28 revision) MCP specifications.

Tokens
80.7K
Snippets
191
Records
285
Agent score
60%

What's inside logiscape-mcp-sdk-php

  1. Feature scope of the MCP Web Client

    main

    The Web Client is a thin UI layer over Mcp\Client\Client. It is optimized for operations that can complete within a single PHP request/response cycle.

    Supported MCP Operations:

    • Transports: stdio and HTTP/HTTPS (auto-detected via URL scheme).
    • OAuth 2.1: Supports browser-redirect consent, PKCE, and Dynamic Client Registration via OAuthConfiguration and FileTokenStorage.
    • Prompts: list, get.
    • Tools: list, call.
    • Resources: list, read.
    • Completions: Debounced auto-complete within prompt-argument inputs.
    • Server Info: Displays name, version, negotiated protocol version, and advertised capabilities.
    • Elicitation (Preview): Captures server-initiated elicitation/create requests and renders them as cards for user interaction (automatically declines by default).
  2. Understand Issue and Pull Request labels

    main

    This project uses a standardized labeling system based on the MCP SDK Working Group's conventions (SEP-1730). These labels are used by maintainers to categorize the type, status, priority, and area of issues and pull requests.

    Note for Contributors: You do not need to apply these labels when opening an issue or PR; maintainers will triage and label them accordingly.

  3. What is Server-Initiated LLM Sampling

    main

    Sampling allows an MCP server to request a completion from the client's LLM on the server's behalf. Instead of the server managing its own inference or API keys, it asks the client (e.g., Claude Desktop, an IDE) to run the model. This keeps costs, privacy, and content policies on the client side.

    Key Characteristics:

    • Agentic Mirror of Elicitation: While elicitation asks a human for input, sampling asks a language model for a response.
    • Context-Bound: The SDK only allows sampling within a tool handler. The SamplingContext is injected into tool callbacks via reflection.
    • Transport Agnostic: Works across both stdio and HTTP using the same suspend/resume mechanics used for elicitation.
    • Deprecation Note: As of the 2026-07-28 spec, sampling is deprecated. It remains functional for a minimum twelve-month window, but using it in a 2026-07-28 session will emit a PSR-3 warning.
  4. Configure CIMD for Stateless Web Hosting

    main

    When hosting an MCP client in a stateless web environment, you can use CIMD (Client Identity Metadata Document).

    By providing a cimdUrl in your OAuthConfiguration, the Authorization Server (AS) can pull your client's metadata directly. This allows for a stateless setup where the URL itself acts as the stable client_id, requiring no per-process registration or local persistence other than the tokens themselves.

    Requirements for CIMD:

    • The cimdUrl must be publicly reachable from the Authorization Server.
    • It must be served over HTTPS.
    • It must never be gated behind authentication.
  5. What are Prompts in MCP?

    main

    Prompts are reusable message templates that users can select in an MCP client (often via slash commands or a prompt library UI). Unlike tools, which are called autonomously by the model, prompts are user-initiated. They are ideal for standardizing common interactions like code review templates, analysis frameworks, or report formats.

    Lifecycle of a Prompt:

    1. The MCP client fetches available prompts using prompts/list.
    2. The user selects a prompt and provides arguments.
    3. The client sends prompts/get with those arguments to your server.
    4. Your server returns one or more messages that seed the conversation.
  6. Persist OAuth Tokens in a Database using PdoTokenStorage

    main

    For web-hosted MCP clients that need to share OAuth token sets across multiple PHP processes, use PdoTokenStorage. This implements the TokenStorageInterface using bare PDO.

    Important Security & Scoping Requirements:

    1. Caller/Tenant Scoping: The TokenStorageInterface keys records by resource URL alone and clear() wipes everything. To safely use a shared database table in a multi-user application, you must ensure the store is constructor-scoped to a specific namespace/tenant.
    2. Encryption: It provides encryption-at-rest parity with FileTokenStorage using an optional AES-256-GCM secret.
  7. How the stateless core and dual-era negotiation work

    main

    The v2 SDK supports the MCP 2026-07-28 "stateless core" specification. This model is ideal for PHP web hosting (where a fresh process is spawned per request) because it removes the need for an initialize handshake and session IDs; every request is self-contained.

    To ensure compatibility, the SDK implements dual-era negotiation:

    • Servers detect the era of each incoming request.
    • Clients automatically probe for the latest spec and fall back to legacy versions (2024-11-05 through 2025-11-25) if necessary.

    This allows a single codebase to interoperate with both modern and legacy MCP peers concurrently.

  8. Handle Elicitation Requests in MCP Clients

    main

    Elicitation is a mechanism where an MCP server asks the user for additional information mid-tool-call. To support this, you must register an elicitation handler on the Client instance before calling connect(). Registering a handler advertises the elicitation capability during the handshake.

    When a server requests elicitation, your handler is executed. You must return an ElicitationCreateResult with one of three valid actions:

    • 'accept': The user provided a response. The content array must contain the data.
    • 'decline': The user chose not to provide a response.
    • 'cancel': The user cancelled the entire interaction.

    If your handler throws an exception, the SDK catches it and sends an internal-error response (-32603) to allow the server to recover gracefully.

    <?php
    require __DIR__ . '/vendor/autoload.php';
    
    use Mcp\
    Client\
    Client;
    use Mcp\
    Types\
    ElicitationCreateRequest;
    use Mcp\
    Types\
    ElicitationCreateResult;
    
    $client = new Client();
    
    $client->onElicit(static function (ElicitationCreateRequest $req): ElicitationCreateResult {
        // Handle the request and return a result
        return new ElicitationCreateResult(action: 'accept', content: ['key' => 'value']);
    });
    
    $session = $client->connect('https://example.com/mcp-server.php');
    $result = $session->callTool('tool_name', []);
    $client->close();
  9. Implement context-aware completions

    main

    To provide smarter suggestions, completion providers can accept a second array $context parameter. This array contains the values the user has already selected for other arguments within the same prompt. This allows you to filter suggestions based on previous choices (e.g., suggesting frameworks only after a specific language has been selected).

    $server->completionForPrompt(
        'scaffold',
        'framework',
        function (string $value, array $context): array {
            $byLanguage = [
                'php'    => ['laravel', 'symfony', 'slim'],
                'python' => ['django', 'flask', 'fastapi'],
            ];
            // Use values from $context to narrow down candidates
            $candidates = $byLanguage[$context['language'] ?? ''] ?? [];
            return array_values(array_filter(
                $candidates,
                fn (string $f): bool => str_starts_with($f, $value),
            ));
        }
    );
  10. MCP SDK v2 Extensions: Tasks and Apps

    main

    The v2 SDK includes support for two major MCP extensions:

    • Tasks extension (SEP-2663): Supports long-running tool calls. Clients receive a task handle that they can poll, cancel, or use to feed input. This is backed by a file-based store designed to work on shared hosting.
    • MCP Apps extension (SEP-1865): Allows attaching a host-rendered HTML UI to a tool using a single ->ui(...) call.
  11. Handle connection cancellation

    main

    When a client sends a notifications/cancelled notification, it indicates a request should be stopped.

    Important Limitations:

    • No mid-tool preemption: Because PHP is synchronous and single-threaded, the SDK cannot interrupt a tool that is currently executing its callback. The cancellation handler only fires when the SDK is next reading from the transport (after the current tool returns).
    • Cooperative cancellation: You must use registerNotificationHandler to record the cancelled requestId and then manually check your own application state/cleanup logic to honor the cancellation.
    • No acknowledgement: Do not attempt to send a response from the notification handler; it is a notification, not a request.
    $cancelled = [];
    
    $server->getServer()->registerNotificationHandler(
        'notifications/cancelled',
        function (?Mcp\Types\NotificationParams $params) use (&$cancelled): void {
            if ($params === null || !isset($params->requestId)) {
                return;
            }
            // Record the abandoned request ID for manual cleanup/logging
            $cancelled[(int) $params->requestId] = true;
        }
    );
  12. Understand Streamable HTTP transport support

    main

    The SDK implements the modern Streamable HTTP transport. This involves a single endpoint where the client POSTs JSON-RPC and receives JSON or SSE responses.

    Limitations:

    • The SDK does not support the deprecated HTTP+SSE dual-endpoint transport (where a separate GET /sse endpoint is used alongside a POST endpoint).
    • Consequently, the client cannot connect to servers that only expose the legacy dual-endpoint transport.
    • However, the client can still speak older protocol revisions (like 2024-11-05) over the modern Streamable HTTP transport via protocol negotiation.