Add redMCP Streamable HTTP server

This commit is contained in:
Jason Thistlethwaite
2026-04-25 02:23:48 +00:00
parent 3b6b4d6dba
commit 05c1a4bc97
11 changed files with 631 additions and 15 deletions
+82
View File
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace RedMCP;
final class McpStdioServer
{
private McpDispatcher $dispatcher;
public function __construct(McpDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
public function run(): void
{
while (($message = $this->readMessage(STDIN)) !== null) {
$response = $this->dispatcher->handleMessage($message);
if ($response !== null) {
$this->writeMessage($response);
}
}
}
/**
* @param resource $stream
*
* @return array<string,mixed>|null
*/
private function readMessage($stream): ?array
{
$headers = [];
while (($line = fgets($stream)) !== false) {
$line = rtrim($line, "\r\n");
if ($line === '') {
break;
}
if (!str_contains($line, ':')) {
$decoded = json_decode($line, true);
return is_array($decoded) ? $decoded : null;
}
[$name, $value] = explode(':', $line, 2);
$headers[strtolower(trim($name))] = trim($value);
}
if ($line === false && $headers === []) {
return null;
}
$length = isset($headers['content-length']) ? (int) $headers['content-length'] : 0;
if ($length <= 0) {
return null;
}
$body = '';
while (strlen($body) < $length && !feof($stream)) {
$chunk = fread($stream, $length - strlen($body));
if ($chunk === false || $chunk === '') {
break;
}
$body .= $chunk;
}
$decoded = json_decode($body, true);
return is_array($decoded) ? $decoded : null;
}
/**
* @param array<string,mixed> $message
*/
private function writeMessage(array $message): void
{
$body = json_encode($message, JSON_UNESCAPED_SLASHES);
if ($body === false) {
return;
}
fwrite(STDOUT, 'Content-Length: ' . strlen($body) . "\r\n\r\n" . $body);
fflush(STDOUT);
}
}