feat(server): Rework transport architecture and add StreamableHttpTransport (#49)

* feat(server): Rework transport architecture and add StreamableHttpTransport

- `Server::connect()` no longer contains a processing loop.
- `TransportInterface` is updated with `setMessageHandler()` and `listen()`.
- `StdioTransport` is updated to implement the new interface.
- A new, minimal `StreamableHttpTransport` is added for stateless HTTP.

* refactor(server): use  event-driven message handling

* feat(server): Introduce a formal session management system

* fix: ensure session elements are preserved when building server (regression from #46)

* refactor: consolidate HTTP example to use shared dependencies

* feat(server): Enhance message handling with session support

- Updated `TransportInterface` to use `onMessage` for handling incoming messages with session IDs.
- Refactored `Server`, `Handler`, and transport classes to accommodate session management using `Uuid`.
- Introduced methods for creating sessions with auto-generated and specific UUIDs in `SessionFactory` and `SessionFactoryInterface`.

* feat(server): Integrate session management in message handling

- Added session support to the `Server` and `Handler` classes, allowing for session data to be managed during message processing.
- Updated `TransportInterface` to include session context in the `send` method.
- Refactored various request handlers to utilize session information, ensuring proper session handling for incoming requests.
- Introduced a file-based session store for persistent session data management

* feat: Update session builder method to use set* instead of with*

* feat: Fix test compatibility with new session management architecture

* chore: apply code style fixes

* fix: remove deprecated SSE transport and resolve PHPStan issues
This commit is contained in:
Kyrian Obikwelu 2025-09-21 11:12:40 +01:00 • committed by GitHub
commit 719262b15d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -38,6 +38,10 @@ use Mcp\Schema\ResourceTemplate;
use Mcp\Schema\Tool;
use Mcp\Schema\ToolAnnotations;
use Mcp\Server;
use Mcp\Server\Session\InMemorySessionStore;
use Mcp\Server\Session\SessionFactory;
use Mcp\Server\Session\SessionFactoryInterface;
use Mcp\Server\Session\SessionStoreInterface;
use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
@ -65,6 +69,12 @@ final class ServerBuilder
private ?ContainerInterface $container = null;
private ?SessionFactoryInterface $sessionFactory = null;
private ?SessionStoreInterface $sessionStore = null;
private int $sessionTtl = 3600;
private ?int $paginationLimit = 50;
private ?string $instructions = null;
@ -193,6 +203,18 @@ final class ServerBuilder
return $this;
}
public function setSession(
SessionStoreInterface $sessionStore,
SessionFactoryInterface $sessionFactory = new SessionFactory(),
int $ttl = 3600,
): self {
$this->sessionFactory = $sessionFactory;
$this->sessionStore = $sessionStore;
$this->sessionTtl = $ttl;
return $this;
}
public function setDiscovery(
string $basePath,
array $scanDirs = ['.', 'src'],
@ -292,6 +314,10 @@ final class ServerBuilder
$discovery->discover($this->discoveryBasePath, $this->discoveryScanDirs, $this->discoveryExcludeDirs);
}
$sessionTtl = $this->sessionTtl ?? 3600;
$sessionFactory = $this->sessionFactory ?? new SessionFactory();
$sessionStore = $this->sessionStore ?? new InMemorySessionStore($sessionTtl);
return new Server(
jsonRpcHandler: Handler::make(
registry: $registry,
@ -300,6 +326,8 @@ final class ServerBuilder
toolCaller: $toolCaller,
resourceReader: $resourceReader,
promptGetter: $promptGetter,
sessionStore: $sessionStore,
sessionFactory: $sessionFactory,
logger: $logger,
),
logger: $logger,