-
Notifications
You must be signed in to change notification settings - Fork 643
Description
Is your feature request related to a problem?
Many AI clients (Claude Desktop, Cursor, VS Code, etc.) only support stdio MCP servers configured as local processes. When the actual MCP server runs over Streamable HTTP (e.g. a remote or self-hosted server with API key authentication), users need a lightweight bridge process to proxy messages between the two transports.
Today there is no sample showing this pattern, so developers end up implementing HTTP manually (handling mcp-session-id, SSE parsing, notifications, error mapping, etc.) without knowing the SDK already provides everything needed.
Describe the solution you'd like
Add a samples/StdioToHttpBridge sample showing how to proxy messages transparently between StdioServerTransport and HttpClientTransport using the raw ITransport layer:
using System.CommandLine;
using ModelContextProtocol.Client;
using ModelContextProtocol.Server;
var urlOption = new Option<string>("--url", ["-u"])
{
Description = "MCP server endpoint URL. Env: MCP_URL",
DefaultValueFactory = (_) => Environment.GetEnvironmentVariable("MCP_URL") ?? string.Empty
};
var apiKeyOption = new Option<string>("--api-key", ["-k"])
{
Description = "API key for authentication. Env: MCP_API_KEY",
DefaultValueFactory = (_) => Environment.GetEnvironmentVariable("MCP_API_KEY") ?? string.Empty
};
var insecureOption = new Option<bool>("--insecure", ["-i"])
{
Description = "Disable SSL certificate validation. DANGEROUS: use only in development. Env: MCP_INSECURE",
DefaultValueFactory = (_) => Environment.GetEnvironmentVariable("MCP_INSECURE") is "1" or "true"
};
var rootCommand = new RootCommand("stdio-to-HTTP MCP bridge") { urlOption, apiKeyOption, insecureOption };
rootCommand.SetAction(async action =>
{
var mcpUrl = action.GetValue(urlOption);
var apiKey = action.GetValue(apiKeyOption);
var insecure = action.GetValue(insecureOption);
if (string.IsNullOrWhiteSpace(mcpUrl) || string.IsNullOrWhiteSpace(apiKey))
{
if (string.IsNullOrWhiteSpace(mcpUrl)) Console.Error.WriteLine("Error: --url is required.");
if (string.IsNullOrWhiteSpace(apiKey)) Console.Error.WriteLine("Error: --api-key is required.");
Environment.Exit(1);
}
if (insecure) Console.Error.WriteLine("WARNING: SSL validation is DISABLED");
var handler = insecure
? new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }
: new HttpClientHandler();
var httpTransport = new HttpClientTransport(
new HttpClientTransportOptions
{
Endpoint = new Uri(mcpUrl!),
AdditionalHeaders = new Dictionary<string, string> { ["X-API-Key"] = apiKey! },
TransportMode = HttpTransportMode.StreamableHttp
},
new HttpClient(handler));
await using var remoteTransport = await httpTransport.ConnectAsync();
await using var stdioTransport = new StdioServerTransport("mcp-bridge");
// Proxy stdio → remote
var stdioToRemote = Task.Run(async () =>
{
await foreach (var message in stdioTransport.MessageReader.ReadAllAsync())
await remoteTransport.SendMessageAsync(message);
});
// Proxy remote → stdio
var remoteToStdio = Task.Run(async () =>
{
await foreach (var message in remoteTransport.MessageReader.ReadAllAsync())
await stdioTransport.SendMessageAsync(message);
});
await Task.WhenAny(stdioToRemote, remoteToStdio);
});
return await rootCommand.Parse(args).InvokeAsync();Why this approach
- Transparent proxy: works at raw
ITransportlevel — all JSON-RPC messages (includinginitialize/initialized) are forwarded as-is, no double handshake - SDK handles complexity:
HttpClientTransportmanagesmcp-session-id, Streamable HTTP protocol, reconnections automatically - Authentication via
AdditionalHeaders: clean way to inject API keys or bearer tokens - Environment variable support:
MCP_URL,MCP_API_KEY,MCP_INSECUREfor container/CI use - Distributable: can be published as
PublishSingleFile=trueself-contained executable
Additional context
This is the pattern we use in cv4pve-admin to let Claude Desktop connect to our self-hosted Proxmox VE MCP server over HTTPS with API key authentication.