StdioClientTransportOptions is failing with space in Command
メンテナーはふだん 1 日以内に返信
@jozkee がすでに取り組んでいます。
2026年7月19日 から。
評価
この issue はまだ評価されていません。
説明
Describe the bug
On Windows, StdioClientTransport wraps every non-cmd.exe command as cmd.exe /c <Command> <Arguments...>. When Command is an absolute path that contains a space (e.g. anything under C:\Program Files\...) and Arguments is non-empty, the resulting command line confuses cmd.exe's /c quote-handling rules: cmd strips the outer quotes around the executable path, splits on the first space, and tries to launch a non-existent program. The MCP server is never started.
The relevant code is in [src/ModelContextProtocol.Core/Client/StdioClientTransport.cs](https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs):
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
!string.Equals(Path.GetFileName(command), "cmd.exe", StringComparison.OrdinalIgnoreCase))
{
arguments = arguments is null or [] ? ["/c", command] : ["/c", command, ..arguments];
command = "cmd.exe";
}
Per cmd /?, when /c is followed by more than two quote characters, cmd strips the first and last quote and re-parses the middle. Because ProcessStartInfo.ArgumentList correctly quotes both the space-containing path and any further argument, you always end up with 4+ quote characters and trigger this stripping behavior. The /s switch plus an extra outer pair of quotes around the whole command-and-args region would prevent this, but the SDK does not emit either.
To Reproduce
Steps to reproduce the behavior:
- Place any working stdio MCP server executable at a path containing a space, e.g.
C:\Program Files\MssqlMcp\server.exe. - Create a client with at least one argument:
var options = new StdioClientTransportOptions { Name = "MssqlMcp", Command = @"C:\Program Files\MssqlMcp\server.exe", Arguments = [connectionString] }; var transport = new StdioClientTransport(options); var client = await McpClient.CreateAsync(transport); - Observe that
CreateAsyncfails — the child process either exits immediately or never starts. - Move/copy the same executable to a space-free path (e.g.
C:\Tools\MssqlMcp\server.exe), updateCommand, and the exact same code works.
Expected behavior
StdioClientTransport should launch the configured executable regardless of whether its path contains spaces, just as it does for paths without spaces. The Windows cmd /c wrapping should be transparent to the caller.
Logs
Trace-level log from StdioClientTransport shows the wrapped invocation; the spawned cmd.exe produces output like:
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
(Exact message varies depending on whether the path's first space-separated token happens to match an existing file.)
Additional context
- Platform: Windows (any version). Not reproducible on Linux/macOS — the wrapping branch is Windows-only.
- Reproduces whenever
Path.GetFileName(Command) != "cmd.exe"and the path contains a space andArgumentsis non-empty. With zero arguments, cmd's "exactly two quotes around an executable" special case happens to make it work, which is why this bug is intermittent and easy to miss in samples (npx,dotnet,uvicornall live on space-free PATH entries).
Workarounds users currently have to apply:
- Install/copy the server to a space-free directory.
A proper fix would be for the SDK to either (a) build the joined-and-quoted command string itself when wrapping with cmd (e.g. ["/d", "/s", "/c", $"\"\"{command}\" {joinedArgs}\""]) rather than relying on ArgumentList's per-arg quoting, or (b) skip the cmd wrapping entirely when Command resolves to a real executable file — the original justification in the source comment ("usually npx or uvicorn") only applies to PATH-resolved batch/script commands, not absolute .exe paths.
- 主要言語
- C#
- スター
- 4.6k
- フォーク
- 819
- 平均マージ
- 8日 7時間
- マージ済み PR(30日)
- 3
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
modelcontextprotocol/csharp-sdk のほかの issue
-
ClaimsPrincipal parameter injection sample request対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
modelcontextprotocol/csharp-sdk#1899 ·
メンテナーはふだん 1 日以内に返信
-
Document ClientOAuthOptions.ScopeSelector usage対応中かも @z0rimo が 25 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
modelcontextprotocol/csharp-sdk#1867 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
HTTP+SSE client: POST responses are never disposed, leaking one connection per sent message対応中かも @yalcinfu22 が 40 日前に担当しました。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
modelcontextprotocol/csharp-sdk#1840 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
stdio client never closes the server's stdin, so every client dispose burns the full ShutdownTimeout (5s by default)対応中かも @luisangelrod が 40 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
modelcontextprotocol/csharp-sdk#1836 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
enhancement needs confirmation
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
modelcontextprotocol/csharp-sdk#678 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
modelcontextprotocol/csharp-sdk の issue をすべて見る
似ている issue
-
[Doc Gap] Document new --enable-public-network-access breaking change for azurebackup vault createオープンcopilot documentation
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
メンテナーはふだん 1 日以内に返信
-
area-dashboard
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
0 - Backlog Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
BrighterCommand/Brighter#4539 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
area-networking
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
dotnet/aspnetcore#69671 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信