svrnty-mcp-gateway/src/Svrnty.MCP.Gateway.Infrastructure/Transport/StdioServerTransport.cs
Svrnty 19ef79362e refactor: rename OpenHarbor.MCP to Svrnty.MCP across all libraries
- Renamed all directories: OpenHarbor.MCP.* → Svrnty.MCP.*
- Updated all namespaces in 179 C# files
- Renamed 20 .csproj files and 3 .sln files
- Updated 193 documentation references
- Updated 33 references in main CODEX codebase
- Updated Codex.sln with new paths
- Build verified: 0 errors

Preparing for extraction to standalone repositories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 21:04:17 -04:00

118 lines
3.2 KiB
C#

using System.Diagnostics;
using System.Text.Json;
using Svrnty.MCP.Gateway.Core.Interfaces;
using Svrnty.MCP.Gateway.Core.Models;
namespace Svrnty.MCP.Gateway.Infrastructure.Transport;
/// <summary>
/// Server transport implementation using stdio (standard input/output).
/// Launches a process and communicates via stdin/stdout.
/// </summary>
public class StdioServerTransport : IServerTransport
{
private readonly string _command;
private readonly string[] _args;
private Process? _process;
private StreamWriter? _stdin;
private StreamReader? _stdout;
private bool _isConnected;
public bool IsConnected => _isConnected;
public StdioServerTransport(string command, string[] args)
{
_command = command ?? throw new ArgumentNullException(nameof(command));
_args = args ?? Array.Empty<string>();
}
public async Task ConnectAsync(CancellationToken cancellationToken = default)
{
if (_isConnected)
{
return;
}
_process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = _command,
Arguments = string.Join(" ", _args),
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
_process.Start();
_stdin = _process.StandardInput;
_stdout = _process.StandardOutput;
_isConnected = true;
await Task.CompletedTask;
}
public async Task<GatewayResponse> SendRequestAsync(GatewayRequest request, CancellationToken cancellationToken = default)
{
if (!_isConnected || _stdin == null || _stdout == null)
{
throw new InvalidOperationException("Transport is not connected");
}
// Serialize request to JSON
var jsonRequest = JsonSerializer.Serialize(request);
await _stdin.WriteLineAsync(jsonRequest);
await _stdin.FlushAsync();
// Read response from stdout
var jsonResponse = await _stdout.ReadLineAsync();
if (string.IsNullOrEmpty(jsonResponse))
{
return new GatewayResponse
{
Success = false,
Error = "Empty response from server"
};
}
// Deserialize response
var response = JsonSerializer.Deserialize<GatewayResponse>(jsonResponse);
return response ?? new GatewayResponse
{
Success = false,
Error = "Failed to deserialize response"
};
}
public async Task DisconnectAsync(CancellationToken cancellationToken = default)
{
if (!_isConnected)
{
return;
}
_stdin?.Close();
_stdout?.Close();
if (_process != null && !_process.HasExited)
{
_process.Kill();
await _process.WaitForExitAsync(cancellationToken);
}
_process?.Dispose();
_process = null;
_stdin = null;
_stdout = null;
_isConnected = false;
}
public void Dispose()
{
DisconnectAsync().GetAwaiter().GetResult();
}
}