diff --git a/src/main/php/io/modelcontextprotocol/McpClient.class.php b/src/main/php/io/modelcontextprotocol/McpClient.class.php index 57a2d1c..79c695a 100755 --- a/src/main/php/io/modelcontextprotocol/McpClient.class.php +++ b/src/main/php/io/modelcontextprotocol/McpClient.class.php @@ -24,6 +24,26 @@ public function __construct($endpoint, string $version= '2025-03-26') { $this->capabilities= Capabilities::client(); } + /** Suspends this MCP client for later continuation */ + public function suspend(): array { + return [ + 'transport' => ['impl' => get_class($this->transport), 'suspended' => $this->transport->suspend()], + 'version' => $this->version, + 'server' => $this->server, + ]; + } + + /** Resumes a previously suspended transport */ + public static function resume(array $suspended): self { + $self= new self( + $suspended['transport']['impl']::resume($suspended['transport']['suspended']), + $suspended['version'] + ); + $self->server= $suspended['server']; + return $self; + } + + /** @return io.modelcontextprotocol.Transport */ public function transport() { return $this->transport; } diff --git a/src/main/php/io/modelcontextprotocol/StreamableHttp.class.php b/src/main/php/io/modelcontextprotocol/StreamableHttp.class.php index 38bd0ad..0d99f37 100755 --- a/src/main/php/io/modelcontextprotocol/StreamableHttp.class.php +++ b/src/main/php/io/modelcontextprotocol/StreamableHttp.class.php @@ -15,6 +15,7 @@ class StreamableHttp extends Transport { const SESSION = 'Mcp-Session-Id'; private $endpoint; + private $terminate= false; /** @param string|util.URI|webservices.rest.Endpoint $endpoint */ public function __construct($endpoint) { @@ -27,6 +28,17 @@ public function setTrace($cat) { $this->endpoint->setTrace($cat); } + /** Suspends this transport for later continuation */ + public function suspend(): array { + $this->terminate= false; + return ['uri' => (string)$this->endpoint->base(), 'headers' => $this->endpoint->headers()]; + } + + /** Resumes a previously suspended transport */ + public static function resume(array $suspended): self { + return new self((new Endpoint($suspended['uri']))->with($suspended['headers'])); + } + /** * Sends a notification * @@ -59,6 +71,7 @@ public function call($method, $params= null) { // If a session header is returned, remember it if ($session= $response->header(self::SESSION)) { $this->endpoint->with(self::SESSION, $session); + $this->terminate= true; } // Separate content-type value from optional parameters, e.g. "charset" @@ -85,7 +98,7 @@ public function call($method, $params= null) { /** @return void */ public function close() { - if (!isset($this->endpoint->headers()[self::SESSION])) return; + if (!$this->terminate) return; // Clients that no longer need a particular session SHOULD send an HTTP DELETE to the // MCP endpoint with the Mcp-Session-Id header, to explicitly terminate the session