Summary
`pac copilot mcp --run` (and the `dnx Microsoft.PowerApps.CLI.Tool --yes copilot mcp --run` equivalent) writes one non-JSON line to stdout before entering MCP protocol mode:
```
Loading FeatureFlags from file: C:\Users<user>.nuget\packages\microsoft.powerapps.cli.tool\2.7.4\tools\net10.0\any\featureflags.json
```
The MCP stdio transport requires stdout to be exclusively JSON-RPC. Any non-JSON line on stdout breaks the host parser. Claude Desktop surfaces this as a toast:
MCP pac-cli: Unexpected token 'L', "Loading Fe"... is not valid JSON
The server then fails to register and its tools are unavailable to the host.
Repro
```powershell
$tmpOut = New-TemporaryFile
$tmpErr = New-TemporaryFile
$p = Start-Process -FilePath "dnx" `
-ArgumentList "Microsoft.PowerApps.CLI.Tool","--yes","copilot","mcp","--run" `
-NoNewWindow -PassThru -RedirectStandardOutput $tmpOut -RedirectStandardError $tmpErr
Start-Sleep -Seconds 6
Stop-Process -Id $p.Id -Force
Get-Content $tmpOut # <-- contains the offending FeatureFlags line
Get-Content $tmpErr | Select-Object -First 6 # <-- clean info: lines (correct behavior)
```
Captured stdout (the problem):
```
Loading FeatureFlags from file: C:\Users<user>.nuget\packages\microsoft.powerapps.cli.tool\2.7.4\tools\net10.0\any\featureflags.json
```
Captured stderr (correctly routed, MCP ignores stderr):
```
info: ModelContextProtocol.Server.StdioServerTransport[857250842]
Server (stream) (Power Platform Management MCP Server) transport reading messages.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
```
Expected
All bootstrap logging (FeatureFlags loader, lifecycle messages, anything diagnostic) should write to stderr. Stdout must be reserved exclusively for JSON-RPC frames. This is the documented requirement of the MCP stdio transport.
Actual
Exactly one line — the FeatureFlags-loader log — goes to stdout, breaking every MCP host that connects via stdio.
Workaround
A Node stdio proxy that filters non-JSON lines off stdout works:
```js
const { spawn } = require('child_process');
const readline = require('readline');
const isWin = process.platform === 'win32';
const command = isWin ? 'cmd.exe' : 'dnx';
const args = isWin
? ['/c', 'dnx', 'Microsoft.PowerApps.CLI.Tool', '--yes', 'copilot', 'mcp', '--run']
: ['Microsoft.PowerApps.CLI.Tool', '--yes', 'copilot', 'mcp', '--run'];
const child = spawn(command, args, { stdio: ['pipe', 'pipe', 'inherit'] });
process.stdin.pipe(child.stdin);
readline.createInterface({ input: child.stdout })
.on('line', line => { if (line.startsWith('{')) process.stdout.write(line + '\n'); });
child.on('exit', code => process.exit(code ?? 0));
```
But every user running pac MCP via Claude Desktop, GitHub Copilot, VS Code, etc. has to either deploy a wrapper like this or disable pac MCP entirely.
Suggested fix
Route the FeatureFlags loader's diagnostic write to `Console.Error` (or the configured stderr logger) instead of stdout. The lifecycle logger already routes correctly to stderr — only the FeatureFlags path is misrouted.
Environment
- pac CLI 2.7.4 (resolved via `dnx Microsoft.PowerApps.CLI.Tool --yes` on 2026-05-29)
- .NET 10.0.7
- Windows 11 (Build 10.0.26200)
- MCP host: Claude Desktop (latest)
Related
Summary
`pac copilot mcp --run` (and the `dnx Microsoft.PowerApps.CLI.Tool --yes copilot mcp --run` equivalent) writes one non-JSON line to stdout before entering MCP protocol mode:
```
Loading FeatureFlags from file: C:\Users<user>.nuget\packages\microsoft.powerapps.cli.tool\2.7.4\tools\net10.0\any\featureflags.json
```
The MCP stdio transport requires stdout to be exclusively JSON-RPC. Any non-JSON line on stdout breaks the host parser. Claude Desktop surfaces this as a toast:
The server then fails to register and its tools are unavailable to the host.
Repro
```powershell
$tmpOut = New-TemporaryFile
$tmpErr = New-TemporaryFile
$p = Start-Process -FilePath "dnx" `
-ArgumentList "Microsoft.PowerApps.CLI.Tool","--yes","copilot","mcp","--run" `
-NoNewWindow -PassThru -RedirectStandardOutput $tmpOut -RedirectStandardError $tmpErr
Start-Sleep -Seconds 6
Stop-Process -Id $p.Id -Force
Get-Content $tmpOut # <-- contains the offending FeatureFlags line
Get-Content $tmpErr | Select-Object -First 6 # <-- clean info: lines (correct behavior)
```
Captured stdout (the problem):
```
Loading FeatureFlags from file: C:\Users<user>.nuget\packages\microsoft.powerapps.cli.tool\2.7.4\tools\net10.0\any\featureflags.json
```
Captured stderr (correctly routed, MCP ignores stderr):
```
info: ModelContextProtocol.Server.StdioServerTransport[857250842]
Server (stream) (Power Platform Management MCP Server) transport reading messages.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
```
Expected
All bootstrap logging (FeatureFlags loader, lifecycle messages, anything diagnostic) should write to stderr. Stdout must be reserved exclusively for JSON-RPC frames. This is the documented requirement of the MCP stdio transport.
Actual
Exactly one line — the FeatureFlags-loader log — goes to stdout, breaking every MCP host that connects via stdio.
Workaround
A Node stdio proxy that filters non-JSON lines off stdout works:
```js
const { spawn } = require('child_process');
const readline = require('readline');
const isWin = process.platform === 'win32';
const command = isWin ? 'cmd.exe' : 'dnx';
const args = isWin
? ['/c', 'dnx', 'Microsoft.PowerApps.CLI.Tool', '--yes', 'copilot', 'mcp', '--run']
: ['Microsoft.PowerApps.CLI.Tool', '--yes', 'copilot', 'mcp', '--run'];
const child = spawn(command, args, { stdio: ['pipe', 'pipe', 'inherit'] });
process.stdin.pipe(child.stdin);
readline.createInterface({ input: child.stdout })
.on('line', line => { if (line.startsWith('{')) process.stdout.write(line + '\n'); });
child.on('exit', code => process.exit(code ?? 0));
```
But every user running pac MCP via Claude Desktop, GitHub Copilot, VS Code, etc. has to either deploy a wrapper like this or disable pac MCP entirely.
Suggested fix
Route the FeatureFlags loader's diagnostic write to `Console.Error` (or the configured stderr logger) instead of stdout. The lifecycle logger already routes correctly to stderr — only the FeatureFlags path is misrouted.
Environment
Related