Add production rollout tooling and semantic index ops docs

Capture the production plugin rollout workflow and Qdrant validation steps so operations stay repeatable. Also harden redMCP stdio/schema compatibility to keep diverse MCP clients and validators working.
This commit is contained in:
Jason Thistlethwaite
2026-05-06 22:18:02 -04:00
parent 1f4c3d35ef
commit bd26c8894f
10 changed files with 765 additions and 4 deletions
+7
View File
@@ -213,6 +213,13 @@ Redmine credentials from environment variables or `redMCP/.env`.
redMCP/bin/redmcp-server.php
```
The stdio server supports both MCP framing styles used by clients in the wild:
- `Content-Length` framed JSON-RPC messages
- line-delimited JSON messages (one JSON-RPC object per line)
Responses mirror the detected input framing mode for compatibility.
For local testing, run the Streamable HTTP server:
```sh
+2 -2
View File
@@ -254,7 +254,7 @@ final class McpDispatcher
'due_date' => ['type' => 'string'],
'start_date' => ['type' => 'string'],
'custom_fields' => ['type' => 'array', 'items' => ['type' => 'object']],
'watcher_user_ids' => ['type' => 'array'],
'watcher_user_ids' => ['type' => 'array', 'items' => ['type' => ['integer', 'string']]],
'is_private' => ['type' => ['boolean', 'string', 'integer']],
'estimated_hours' => ['type' => ['number', 'string', 'integer']],
'done_ratio' => ['type' => ['integer', 'string']],
@@ -279,7 +279,7 @@ final class McpDispatcher
'start_date' => ['type' => 'string'],
'private_notes' => ['type' => ['boolean', 'string', 'integer']],
'custom_fields' => ['type' => 'array', 'items' => ['type' => 'object']],
'watcher_user_ids' => ['type' => 'array'],
'watcher_user_ids' => ['type' => 'array', 'items' => ['type' => ['integer', 'string']]],
'is_private' => ['type' => ['boolean', 'string', 'integer']],
'estimated_hours' => ['type' => ['number', 'string', 'integer']],
'done_ratio' => ['type' => ['integer', 'string']],
+9 -1
View File
@@ -7,6 +7,7 @@ namespace RedMCP;
final class McpStdioServer
{
private McpDispatcher $dispatcher;
private string $wireMode = 'content-length';
public function __construct(McpDispatcher $dispatcher)
{
@@ -36,7 +37,8 @@ final class McpStdioServer
if ($line === '') {
break;
}
if (!str_contains($line, ':')) {
if (!preg_match('/^[A-Za-z0-9-]+\s*:/', $line)) {
$this->wireMode = 'line';
$decoded = json_decode($line, true);
return is_array($decoded) ? $decoded : null;
}
@@ -76,6 +78,12 @@ final class McpStdioServer
return;
}
if ($this->wireMode === 'line') {
fwrite(STDOUT, $body . "\n");
fflush(STDOUT);
return;
}
fwrite(STDOUT, 'Content-Length: ' . strlen($body) . "\r\n\r\n" . $body);
fflush(STDOUT);
}