HelpScout (and WordPressAPI) MCP servers were failing to connect with authentication errors despite credentials being present in .mcp.json.
The executor.ts config loader was not properly mapping the .mcp.json format to the internal config format expected by the MCP aggregator:
.mcp.jsonuses:envfield for environment variables- MCP aggregator expects:
environmentfield
The normalizer in executor.ts was spreading the config but not mapping env → environment.
File: src/executor.ts (lines 73-85)
Before:
const normalizedServers: Record<string, any> = {};
for (const [name, config] of Object.entries(servers)) {
normalizedServers[name] = {
...(config as any),
transport: (config as any).type || (config as any).transport
};
}After:
const normalizedServers: Record<string, any> = {};
for (const [name, config] of Object.entries(servers)) {
const cfg = config as any;
normalizedServers[name] = {
...cfg,
transport: cfg.type || cfg.transport || 'stdio',
environment: cfg.environment || cfg.env || {} // KEY FIX
};
// Remove the old fields to avoid confusion
delete normalizedServers[name].env;
delete normalizedServers[name].type;
}- ✅ automem: 7 tools
- ✅ sequential-thinking: 1 tool
- ✅ context7: 2 tools
- ❌ WordPressAPI: Connection failed (no environment vars)
- ❌ helpscout: Authentication failed (no environment vars)
Total: 10 tools from 3 servers
- ✅ automem: 7 tools
- ✅ sequential-thinking: 1 tool
- ✅ context7: 2 tools
- ✅ WordPressAPI: 12 tools (FIXED!)
- ✅ helpscout: 8 tools (FIXED!)
Total: 30 tools from 5 servers! 🎉
Test standalone HelpScout MCP with credentials:
export HELPSCOUT_CLIENT_ID="IKA8CezyOi2TD5stGBJFrZ376tNBdksp"
export HELPSCOUT_CLIENT_SECRET="NoaApCokwUonLJHVtvMRPRWHBGfDz2gf"
npx help-scout-mcp-serverExpected output:
{"level":"info","message":"Authenticated with Help Scout API using OAuth2"}
{"level":"info","message":"Help Scout MCP Server started successfully"}
Added comprehensive debug logging to trace environment variable flow:
In mcp/aggregator.ts (lines 146-158):
console.log(`🔍 [DEBUG] Creating stdio client for command: ${resolvedCommand}`);
console.log(`🔍 [DEBUG] Config environment keys:`, Object.keys(config.environment || {}));
console.log(`🔍 [DEBUG] Merged environment HELPSCOUT keys:`,
Object.keys(mergedEnv).filter(k => k.includes('HELP'))
);In mcp-server.ts (lines 122-147):
console.log(`🔍 [CONVERTER] Processing server: ${name}`);
console.log(`🔍 [CONVERTER] Raw config.env keys:`, Object.keys(config.env || {}));
console.log(`🔍 [CONVERTER] Converted environment keys:`, Object.keys(servers[name].environment));- Field Name Consistency:
.mcp.jsonformat uses different field names (env,type) than internal types (environment,transport) - Multiple Config Loaders: There are at least 3 places where
.mcp.jsonis loaded:mcp-server.ts:convertMCPJsonToConfig()executor.ts: Direct JSON parsing with normalization- Each needs to handle the field mapping consistently
- Debug Logging is Critical: Without the debug logs, it was impossible to see that environment vars were empty
- Test Standalone First: Testing the MCP server standalone with env vars confirmed the credentials were valid
src/executor.ts: Main fix locationsrc/mcp/aggregator.ts: Debug logging addedsrc/mcp-server.ts: Converter debug logging added (not used by executor path).mcp.json: Config file withenvfield
- Unify Config Loading: Create a single
loadMCPConfig()function used by both executor and mcp-server - Type Safety: Add TypeScript types to catch field name mismatches at compile time
- Remove Debug Logs: Clean up debug logging once confident the fix is stable
- Add Tests: Unit tests for config normalization to prevent regression
Fixed: 2025-09-30 By: Claude Code Status: ✅ All 5 MCP servers connected successfully