Skip to content

Latest commit

 

History

History
190 lines (136 loc) · 5.31 KB

framework-integration.md

File metadata and controls

190 lines (136 loc) · 5.31 KB

Framework integration

The HTTP transport is a PSR-7 request handler, not a web server. This page covers how it fits into an application you already have.

Architecture

The HTTP transport doesn't run its own web server. Instead, it processes PSR-7 requests and returns PSR-7 responses that your application can handle however it needs to:

Your Web App → PSR-7 Request → StreamableHttpTransport → PSR-7 Response → Your Web App

This design allows integration with any PHP framework or application that supports PSR-7.

Basic Usage (Standalone)

Here's a simplified example using PSR-17 discovery and Laminas emitter:

use Http\Discovery\Psr17Factory;
use Mcp\Server;
use Mcp\Server\Transport\StreamableHttpTransport;
use Mcp\Server\Session\FileSessionStore;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;

$psr17Factory = new Psr17Factory();
$request = $psr17Factory->createServerRequestFromGlobals();

$server = Server::builder()
    ->setServerInfo('HTTP Server', '1.0.0')
    ->setDiscovery(__DIR__, ['.'], excludeDirs: ['vendor'])
    ->setSession(new FileSessionStore(__DIR__ . '/sessions')) // HTTP needs persistent sessions
    ->build();

$transport = new StreamableHttpTransport($request);

$response = $server->run($transport);

(new SapiEmitter())->emit($response);

Framework Integration

Symfony Integration

First install the required PSR libraries:

composer require symfony/psr-http-message-bridge nyholm/psr7

Then create a controller that uses Symfony's PSR-7 bridge:

Note: This example assumes your MCP Server instance is configured in Symfony's service container.

// In a Symfony controller
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Mcp\Server;
use Mcp\Server\Transport\StreamableHttpTransport;

class McpController
{
    #[Route('/mcp', name: 'mcp_endpoint')]
    public function handle(Request $request, Server $server): Response
    {
        // Convert Symfony request to PSR-7 (PSR-17 factories auto-discovered)
        $psrHttpFactory = new PsrHttpFactory();
        $httpFoundationFactory = new HttpFoundationFactory();
        $psrRequest = $psrHttpFactory->createRequest($request);

        // Process with MCP (factories auto-discovered)
        $transport = new StreamableHttpTransport($psrRequest);
        $psrResponse = $server->run($transport);

        // Convert PSR-7 response back to Symfony
        return $httpFoundationFactory->createResponse($psrResponse);
    }
}

Laravel Integration

First install the required PSR libraries:

composer require symfony/psr-http-message-bridge nyholm/psr7

Then create a controller that type-hints ServerRequestInterface:

Note: This example assumes your MCP Server instance is constructed and bound in a Laravel service provider for dependency injection.

// In a Laravel controller
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Mcp\Server;
use Mcp\Server\Transport\StreamableHttpTransport;

class McpController
{
    public function handle(ServerRequestInterface $request, Server $server): ResponseInterface
    {
        // Create the MCP HTTP transport
        $transport = new StreamableHttpTransport($request);

        // Process MCP request and return PSR-7 response
        // Laravel automatically handles PSR-7 responses
        return $server->run($transport);
    }
}

// Route registration
Route::any('/mcp', [McpController::class, 'handle']);

Slim Framework Integration

Slim Framework works natively with PSR-7.

Create a route handler using Slim's built-in factories and container:

use Slim\Factory\AppFactory;
use Mcp\Server;
use Mcp\Server\Session\FileSessionStore;
use Mcp\Server\Transport\StreamableHttpTransport;

$app = AppFactory::create();

$app->any('/mcp', function ($request, $response) {
    $server = Server::builder()
        ->setServerInfo('My MCP Server', '1.0.0')
        ->setDiscovery(__DIR__, ['.'], excludeDirs: ['vendor'])
        ->setSession(new FileSessionStore(__DIR__ . '/sessions')) // HTTP needs persistent sessions
        ->build();

    $transport = new StreamableHttpTransport($request);

    return $server->run($transport);
});

HTTP Method Handling

The transport handles all HTTP methods automatically:

  • POST: Send MCP requests
  • GET: Not implemented (returns 405)
  • DELETE: End session
  • OPTIONS: CORS preflight

You should route all methods to your MCP endpoint, not just POST.

Session Management

Over HTTP, the server needs a session store that keeps sessions between requests. See Sessions over HTTP.

Recommended Route

It's recommended to mount the MCP endpoint at /mcp, but this is not enforced:

// Recommended
Route::any('/mcp', [McpController::class, 'handle']);

// Also valid
Route::any('/', [McpController::class, 'handle']);
Route::any('/api/mcp', [McpController::class, 'handle']);

Testing HTTP Transport

Use the MCP Inspector to test HTTP servers:

# Start your PHP server
php -S localhost:8000 server.php

# Connect with MCP Inspector
npx @modelcontextprotocol/inspector http://localhost:8000