Skip to content

Commit 335e599

Browse files
facundofariasclaude
andcommitted
fix: Send all logs to stderr for stdio transport compatibility
The stdio transport requires stdout to be reserved exclusively for JSON-RPC messages. Logging to stdout causes "Unexpected token" errors in Claude Desktop. Changes: - Update logger.ts to use console.error for all log levels (info, error, debug) - Add comment explaining stdio transport requirement - Document the issue and solution in STDIO_MIGRATION.md Troubleshooting section This fixes the "Unexpected token 'I', "[INFO] 2025"... is not valid JSON" error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent dbc88ef commit 335e599

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

STDIO_MIGRATION.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,19 @@ This document describes the changes made to convert the DeployHQ MCP server from
3636
- Updated architecture diagram to show stdio transport
3737
- Updated security section to emphasize local credential management
3838

39+
#### `src/utils/logger.ts`
40+
- **CRITICAL FIX**: Changed all logging to use `console.error` instead of `console.log`
41+
- stdio transport requires stdout to be reserved exclusively for JSON-RPC messages
42+
- Logging to stdout causes "Unexpected token" errors in Claude Desktop
43+
- All logs (info, error, debug) now properly go to stderr
44+
3945
### 3. Unchanged Files (for hosted deployment)
4046

4147
- `src/index.ts` - Express server entrypoint
4248
- `src/mcp-server.ts` - Core MCP server factory (shared by both transports)
4349
- `src/tools.ts` - Tool definitions (shared)
4450
- `src/api-client.ts` - DeployHQ API client (shared)
4551
- `src/transports/` - SSE and HTTP transport handlers
46-
- `src/utils/` - Logger and utilities
4752

4853
## Usage
4954

@@ -144,6 +149,29 @@ After (stdio):
144149
5. **No Infrastructure**: No hosting costs or maintenance
145150
6. **Backwards Compatible**: Hosted version still available if needed
146151

152+
## Troubleshooting
153+
154+
### "Unexpected token" JSON errors in Claude Desktop
155+
156+
**Problem**: Claude Desktop shows errors like:
157+
```
158+
Unexpected token 'I', "[INFO] 2025"... is not valid JSON
159+
```
160+
161+
**Cause**: The stdio transport uses stdout exclusively for JSON-RPC messages. Any other output (logs, debug messages, etc.) to stdout will corrupt the JSON stream.
162+
163+
**Solution**: All logging must use `console.error` (stderr) instead of `console.log` (stdout).
164+
165+
```typescript
166+
// ❌ Wrong - writes to stdout, breaks stdio
167+
console.log('[INFO] Starting server...');
168+
169+
// ✅ Correct - writes to stderr, preserves stdio
170+
console.error('[INFO] Starting server...');
171+
```
172+
173+
This is why our logger uses `console.error` for all log levels.
174+
147175
## Next Steps
148176

149177
To publish to npm:

src/utils/logger.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/**
22
* Shared logger utility
3+
* IMPORTANT: For stdio transport, all logs must go to stderr (not stdout)
4+
* stdout is reserved exclusively for JSON-RPC messages
35
*/
46

57
export const log = {
68
info: (message: string, ...args: unknown[]): void => {
7-
console.log(`[INFO] ${new Date().toISOString()} - ${message}`, ...args);
9+
console.error(`[INFO] ${new Date().toISOString()} - ${message}`, ...args);
810
},
911
error: (message: string, ...args: unknown[]): void => {
1012
console.error(`[ERROR] ${new Date().toISOString()} - ${message}`, ...args);
1113
},
1214
debug: (message: string, ...args: unknown[]): void => {
1315
if (process.env.NODE_ENV === 'development' || process.env.LOG_LEVEL === 'debug') {
14-
console.log(`[DEBUG] ${new Date().toISOString()} - ${message}`, ...args);
16+
console.error(`[DEBUG] ${new Date().toISOString()} - ${message}`, ...args);
1517
}
1618
},
1719
};

0 commit comments

Comments
 (0)