Codesapien.McpTransportGateway 1.0.0

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet tool install --global Codesapien.McpTransportGateway --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Codesapien.McpTransportGateway --version 1.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Codesapien.McpTransportGateway&version=1.0.0
                    
nuke :add-package Codesapien.McpTransportGateway --version 1.0.0
                    

MCP Transport Gateway

A pluggable C# MCP transport gateway.

The project composes an incoming listener transport with an outgoing connector transport through a shared MCP message bridge. The current implementation supports stdio, streamable HTTP, and SSE.

Current status

The gateway is implemented as a minimal ASP.NET Core host with transport adapters and end-to-end tests.

Validated transport permutations:

  • streamable HTTP -> stdio
  • SSE -> stdio
  • stdio -> streamable HTTP
  • stdio -> SSE

The bridge architecture is composition-based, so additional pairings are possible as more adapters are added or hardened.

Project layout

  • src\McpTransportGateway - gateway host, transport adapters, configuration, and bridge runtime
  • tests\McpTransportGateway.Tests - integration tests for the initial transport matrix
  • tests\McpTransportGateway.TestServer - a small stdio MCP echo server used by tests and local examples
  • McpTransportGateway.slnx - solution entry point

Architecture overview

The runtime is split into a few core concepts:

  • ITransportListener - accepts inbound MCP sessions
  • ITransportConnector - creates outbound MCP sessions
  • TransportRegistry - resolves the configured listener and connector
  • TransportBridge - relays JSON-RPC messages between the two transports
  • AcceptedSession - wraps a live inbound session and its lifetime

Current adapters:

  • Incoming StreamableHttp
    • Hosts POST, GET, and DELETE on a configurable MCP path
    • Maintains in-memory session state keyed by Mcp-Session-Id
  • Incoming Sse
    • Hosts a configurable SSE subscription endpoint and message endpoint
    • Tracks sessions in memory by query-string sessionId
  • Incoming Stdio
    • Accepts MCP messages on the gateway process's own stdin/stdout
  • Outgoing Stdio
    • Launches a child MCP server process per downstream session
  • Outgoing StreamableHttp
    • Connects to a remote MCP server over streamable HTTP
  • Outgoing Sse
    • Connects to a remote MCP server over SSE

The bridge also tracks per-request related transports so streamable HTTP responses are returned on the correct response stream.

Requirements

  • .NET SDK 10.0 or newer
  • Windows, Linux, or macOS with a working dotnet CLI
  • If you use outgoing stdio, the target MCP server command must be available on the machine running the gateway

Build and test

Build everything:

dotnet build McpTransportGateway.slnx

Run the test suite:

dotnet test McpTransportGateway.slnx

Package as a .NET tool

The gateway project is configured to pack as a .NET tool package with:

  • package ID: McpTransportGateway
  • tool command: mcpgateway

Create the tool package:

dotnet pack src\McpTransportGateway\McpTransportGateway.csproj -c Release

By default, the package is written to:

artifacts\packages\

Test-install the package from the local output folder:

dotnet tool install --tool-path .\artifacts\tool-install --add-source .\artifacts\packages McpTransportGateway
.\artifacts\tool-install\mcpgateway --help

After publishing the package to NuGet.org or another feed, users can install it globally with:

dotnet tool install --global McpTransportGateway

Then run it as:

mcpgateway --help

To publish a packed version to a NuGet feed:

dotnet nuget push .\artifacts\packages\McpTransportGateway.<version>.nupkg --source <feed-url> --api-key <key>

How configuration works

The gateway reads configuration from the standard ASP.NET Core sources, including:

  • appsettings.json
  • appsettings.{Environment}.json
  • environment variables
  • command-line arguments

The gateway options live under the Gateway section.

A development example is checked in at src\McpTransportGateway\appsettings.Development.json.

For other environments or real deployments, supply your own Gateway section through configuration.

In addition to raw ASP.NET Core configuration keys, the gateway now supports a friendly CLI layer for common scenarios such as:

  • --stdio "dotnet my-server.dll" to expose a local stdio server
  • --sse https://example.com/sse to connect to a remote SSE server
  • --streamableHttp https://example.com/mcp to connect to a remote streamable HTTP server

Friendly CLI flags override appsettings, environment variables, and raw --Gateway:... command-line keys.

Friendly CLI arguments

Show the built-in help:

mcpgateway --help

Supported shorthand flags:

  • --stdio "<command line>" - launch a local stdio MCP server and expose it over HTTP transports
  • --sse <url> - connect to a remote SSE MCP server and expose it through stdio
  • --streamableHttp <url> - connect to a remote streamable HTTP MCP server and expose it through stdio
  • --outputTransport <stdio|sse|streamableHttp> - selects the opposite side of the bridge for shorthand modes

Important default:

  • --stdio defaults to --outputTransport streamableHttp

Additional supported flags:

  • --port <number> - binds the HTTP host to http://127.0.0.1:<port>
  • --ssePath <path> - hosted SSE subscription path
  • --messagePath <path> - hosted SSE message path
  • --streamableHttpPath <path> - hosted streamable HTTP path
  • --header "Name: Value" - repeatable header for outgoing remote HTTP/SSE connectors
  • --oauth2Bearer <token> - sets Authorization: Bearer <token> for outgoing remote HTTP/SSE connectors
  • --connectionTimeout <timespan-or-ms> - outgoing remote HTTP/SSE connect timeout
  • --workingDirectory <path> - working directory for outgoing stdio child processes
  • --env NAME=VALUE - repeatable environment variable for outgoing stdio child processes
  • --shutdownTimeout <timespan-or-ms> - outgoing stdio shutdown timeout

For advanced or less common cases, raw ASP.NET Core command-line configuration still works, for example:

mcpgateway --Gateway:Incoming:Kind StreamableHttp --Gateway:Outgoing:Kind Stdio --Gateway:Outgoing:Command dotnet

Configuration reference

Gateway:Incoming

Setting Required Description
Kind Yes One of Stdio, StreamableHttp, or Sse
Path Required for StreamableHttp Route used for streamable HTTP, default /mcp
SsePath Required for Sse SSE subscribe route, default /sse
MessagePath Required for Sse POST route used to send client messages, default /message

Rules:

  • Path, SsePath, and MessagePath must start with /
  • SsePath and MessagePath must be different when Incoming.Kind = Sse

Gateway:Outgoing

Setting Required Description
Kind Yes One of Stdio, StreamableHttp, or Sse
Endpoint Required for StreamableHttp and Sse Remote MCP endpoint URL
Command Required for Stdio Command used to launch the child MCP server
Arguments Optional Command arguments for outgoing stdio
WorkingDirectory Optional Working directory for outgoing stdio
EnvironmentVariables Optional Extra environment variables for outgoing stdio
Headers Optional Extra HTTP headers for outgoing StreamableHttp or Sse
ConnectionTimeout Optional Remote HTTP/SSE connect timeout, default 00:00:30
ShutdownTimeout Optional Child-process shutdown timeout for outgoing stdio, default 00:00:05

Rules:

  • ConnectionTimeout must be greater than zero
  • ShutdownTimeout must be greater than zero
  • Command is required when Outgoing.Kind = Stdio
  • Endpoint is required when Outgoing.Kind = StreamableHttp or Outgoing.Kind = Sse

TransportKind values

Supported values are:

  • Stdio
  • StreamableHttp
  • Sse

HTTP endpoints

The host always exposes:

  • GET /healthz - returns { "status": "ok" }

When Incoming.Kind = StreamableHttp:

  • POST {Gateway:Incoming:Path} - send JSON-RPC requests/notifications
  • GET {Gateway:Incoming:Path} - open the server-to-client stream for a session
  • DELETE {Gateway:Incoming:Path} - close a session

When Incoming.Kind = Sse:

  • GET {Gateway:Incoming:SsePath} - open the SSE subscription
  • POST {Gateway:Incoming:MessagePath}?sessionId=... - send JSON-RPC messages into that session

When Incoming.Kind = Stdio:

  • the gateway accepts MCP messages on its own stdin/stdout
  • the ASP.NET Core host still exists because the executable is currently hosted in the web stack

Example configuration

Example 1: streamable HTTP → stdio

This is the closest equivalent to exposing a local stdio server over a network transport.

Add this to src\McpTransportGateway\appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Gateway": {
    "Incoming": {
      "Kind": "StreamableHttp",
      "Path": "/mcp"
    },
    "Outgoing": {
      "Kind": "Stdio",
      "Command": "dotnet",
      "Arguments": [
        "tests\\McpTransportGateway.TestServer\\bin\\Debug\\net10.0\\McpTransportGateway.TestServer.dll"
      ],
      "WorkingDirectory": "C:\\Users\\facaval\\src\\mcpfe",
      "ShutdownTimeout": "00:00:05"
    }
  }
}

The example above assumes the gateway process working directory is the repository root and the test server has already been built. Relative command arguments are resolved from the gateway process working directory, not from the location of the JSON file. If you prefer, use an absolute path for the .dll.

Run it:

$env:ASPNETCORE_ENVIRONMENT = "Development"
dotnet build McpTransportGateway.slnx
dotnet run --project src\McpTransportGateway --launch-profile http

The gateway will listen on the launch-profile URL from src\McpTransportGateway\Properties\launchSettings.json, which is currently http://localhost:5246 for the http profile.

The MCP endpoint will be:

http://localhost:5246/mcp

Equivalent CLI-first example:

mcpgateway `
  --stdio "dotnet tests\\McpTransportGateway.TestServer\\bin\\Debug\\net10.0\\McpTransportGateway.TestServer.dll" `
  --port 8000

That command defaults to hosted streamable HTTP, so the MCP endpoint will be:

http://127.0.0.1:8000/mcp

Example 2: SSE → stdio

{
  "Gateway": {
    "Incoming": {
      "Kind": "Sse",
      "SsePath": "/sse",
      "MessagePath": "/message"
    },
    "Outgoing": {
      "Kind": "Stdio",
      "Command": "dotnet",
      "Arguments": [
        "tests\\McpTransportGateway.TestServer\\bin\\Debug\\net10.0\\McpTransportGateway.TestServer.dll"
      ]
    }
  }
}

Subscribe at:

GET http://localhost:5246/sse

Send messages to:

POST http://localhost:5246/message?sessionId=<session-id>

Equivalent CLI-first example:

mcpgateway `
  --stdio "dotnet tests\\McpTransportGateway.TestServer\\bin\\Debug\\net10.0\\McpTransportGateway.TestServer.dll" `
  --outputTransport sse `
  --port 8000 `
  --ssePath /sse `
  --messagePath /message

Example 3: stdio → remote streamable HTTP

{
  "Gateway": {
    "Incoming": {
      "Kind": "Stdio"
    },
    "Outgoing": {
      "Kind": "StreamableHttp",
      "Endpoint": "http://localhost:3001/mcp",
      "ConnectionTimeout": "00:00:30",
      "Headers": {
        "Authorization": "Bearer <token-if-needed>"
      }
    }
  }
}

In this mode, an MCP client can launch the gateway over stdio and the gateway will proxy to a remote streamable HTTP MCP server.

Equivalent CLI-first example:

mcpgateway `
  --streamableHttp "http://localhost:3001/mcp" `
  --oauth2Bearer "<token-if-needed>"

Example 4: stdio → remote SSE

{
  "Gateway": {
    "Incoming": {
      "Kind": "Stdio"
    },
    "Outgoing": {
      "Kind": "Sse",
      "Endpoint": "http://localhost:3001/sse",
      "ConnectionTimeout": "00:00:30",
      "Headers": {
        "Authorization": "Bearer <token-if-needed>"
      }
    }
  }
}

Equivalent CLI-first example:

mcpgateway `
  --sse "http://localhost:3001/sse" `
  --oauth2Bearer "<token-if-needed>"

Environment variable equivalents

You can configure the same values with environment variables.

Example for streamable HTTP -> stdio in PowerShell:

$env:ASPNETCORE_ENVIRONMENT = "Development"
$env:Gateway__Incoming__Kind = "StreamableHttp"
$env:Gateway__Incoming__Path = "/mcp"
$env:Gateway__Outgoing__Kind = "Stdio"
$env:Gateway__Outgoing__Command = "dotnet"
$env:Gateway__Outgoing__Arguments__0 = "tests\\McpTransportGateway.TestServer\\bin\\Debug\\net10.0\\McpTransportGateway.TestServer.dll"
$env:Gateway__Outgoing__WorkingDirectory = "C:\\Users\\facaval\\src\\mcpfe"

dotnet build McpTransportGateway.slnx
dotnet run --project src\McpTransportGateway --launch-profile http

Useful patterns:

  • Gateway__Outgoing__Arguments__0, Gateway__Outgoing__Arguments__1, ...
  • Gateway__Outgoing__Headers__Authorization
  • Gateway__Outgoing__EnvironmentVariables__MY_SETTING

Running against your own stdio MCP server

To expose any local stdio MCP server over HTTP/SSE, point Outgoing.Kind to Stdio and set:

  • Command
  • Arguments
  • optionally WorkingDirectory
  • optionally EnvironmentVariables

Examples of possible commands:

  • dotnet
  • node
  • npx
  • python
  • uvx

Because the outgoing stdio connector creates a new child process per session, each downstream client gets isolated server state.

Local development notes

  • The host currently uses ASP.NET Core even when the active incoming transport is Stdio
  • Session state for hosted StreamableHttp and Sse listeners is in memory
  • No authentication or authorization layer has been added yet
  • No WebSocket transport has been implemented yet

Validation performed

The repository currently has end-to-end tests for:

  • StreamableHttp -> Stdio
  • Sse -> Stdio
  • Stdio -> StreamableHttp
  • Stdio -> Sse

Run them with:

dotnet test McpTransportGateway.slnx
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated