Skip to content

feat(config): add mcpServers canonical object format with headers support#1037

Merged
esengine merged 3 commits into
esengine:mainfrom
ADX15xs:feat/mcp-servers-config
May 17, 2026
Merged

feat(config): add mcpServers canonical object format with headers support#1037
esengine merged 3 commits into
esengine:mainfrom
ADX15xs:feat/mcp-servers-config

Conversation

@ADX15xs

@ADX15xs ADX15xs commented May 16, 2026

Copy link
Copy Markdown

What

Introduces mcpServers: Record<string, McpServerConfig> as the canonical way to declare MCP servers, alongside a single normalizeMcpConfig() normalization layer that merges the new object format with legacy mcp[] / mcpEnv / mcpDisabled fields. Headers are plumbed through buildTransportFromSpec into SseTransport and StreamableHttpTransport, enabling HTTP auth for SSE and Streamable HTTP transports.

Why

The legacy mcp: string[] format cannot express HTTP headers (e.g. Authorization, X-API-Key) needed for authenticated SSE / Streamable HTTP MCP servers. The new mcpServers object format fills this gap while remaining fully backward-compatible.

How to verify

  1. npm run verify — lint, typecheck, and all 3125 tests pass (203 test files).
  2. New tests: tests/mcp-normalize-config.test.ts (27 tests) cover legacy-only, object-only, merge conflicts, disabled flags, env/headers, and transport round-trips.
  3. Existing MCP tests all pass: mcp-env-config, mcp-spec, mcp-integration, mcp-reconnect, acp-mcp, chat-mcp-startup-summary, resolve.

Checklist

  • npm run verify passes locally (lint + typecheck + tests + comment-policy gate)
  • No Co-Authored-By: Claude trailer in commits
  • Comments follow CONTRIBUTING.md (no module-essay headers, no incident history)
  • No edits to CHANGELOG.md — release notes are maintainer-written at release time

Closes #1032

@esengine esengine left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ADX15xs — the normalization layer and the call-site fan-out look right, and the 27-test matrix is exactly what I wanted on this surface. Headers plumb cleanly through both SSE and Streamable HTTP.

One thing I need fixed before merge: the three as unknown as McpServerSpec / as McpServerSpec casts —

  • src/cli/commands/mcp-inspect.ts:147
  • src/cli/commands/mcp-runtime.ts:202
  • src/mcp/reconnect.ts:531

CLAUDE.md bans as escape hatches without a biome-ignore + reason, and these aren't really needed — McpSpec is a discriminated union on transport, so switching on parsed.transport and building the overlaid spec per branch gives you a typed McpServerSpec without any cast.

Comment-style nits in src/config.ts and the test body I'll clean up in a follow-up — no need for you to spin on those. Just the casts and this is in.

@ADX15xs ADX15xs requested a review from esengine May 17, 2026 01:46
ADX15xs added 2 commits May 17, 2026 10:18
… server declarations

Introduces a robust configuration system for MCP servers that supports both legacy string-based specs and a new canonical `mcpServers` object format. This allows for advanced configurations including custom HTTP headers for SSE and Streamable HTTP transports.

- Adds `mcpServers` to `ReasonixConfig` to support structured server definitions.
- Implements `normalizeMcpConfig` to merge legacy `mcp` strings with the new object format, ensuring `mcpServers` takes precedence.
- Enhances `buildTransportFromSpec` to support passing `headers` for non-stdio transports.
- Updates CLI commands (`acp`, `mcp-inspect`, `mcp-runtime`, `run`) and internal resolution logic to use normalized configurations.
- Adds `specToRaw` for serializing normalized specs back to legacy string formats.
- Updates documentation to reflect the new configuration schema and examples.
- Adds unit tests for configuration normalization logic.
Implements transport-specific property assignment when merging parsed MCP specifications with normalized configuration. This ensures that environment variables are only applied to `stdio` transports, while HTTP headers are correctly scoped to `sse` and `streamable-http` transports, preventing invalid configuration leakage between types.

- Update `mcp-inspect` and `mcp-runtime` to use conditional spec building based on transport type.
- Refactor `reconnectMcpServer` to decouple transport-specific properties from the base specification.
- Improve type safety by explicitly typing the constructed `McpServerSpec`.
@ADX15xs ADX15xs force-pushed the feat/mcp-servers-config branch from 5a07a4f to f64a477 Compare May 17, 2026 02:19
Extracts the complex conditional logic for merging parsed MCP specifications with configuration into a dedicated utility function. This simplifies the command implementations in `mcp-inspect` and `mcp-runtime` and cleans up the reconnection logic.

- Add `overlayMatchedSpec` to `src/mcp/spec.ts` to handle transport-specific property merging.
- Replace inline switch statements in `mcp-inspect.ts` and `mcp-runtime.ts` with the new utility.
- Simplify `reconnectMcpServer` in `src/mcp/reconnect.ts` by removing redundant spec reconstruction.
@esengine

Copy link
Copy Markdown
Owner

This is exactly the shape I wanted out of #1032 — single normalizeMcpConfig boundary, every call site goes through it, legacy mcp[] / mcpEnv / mcpDisabled collapses into the same McpServerSpec the rest of the code already speaks. Headers plumbed straight through buildTransportFromSpec into the SSE / Streamable-HTTP transports that already supported them — no new transport surface, just the missing wiring.

Round-tripping via specToRaw in mcp-runtime/resolve is a little awkward (we re-parse what we just normalized), but it keeps the diff focused; cleaning that up means rewriting the runtime's desired diff in spec-space, which is fair game for a follow-up. Tests cover the merge-conflict + override semantics I cared about most.

Will pull locally, run npm run verify, and merge. Thanks for landing the design from the issue intact.

@esengine esengine merged commit f294216 into esengine:main May 17, 2026
5 checks passed
@ADX15xs ADX15xs deleted the feat/mcp-servers-config branch May 17, 2026 04:50
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
…port (esengine#1037)

* refactor(mcp): implement configuration normalization and object-based server declarations

Introduces a robust configuration system for MCP servers that supports both legacy string-based specs and a new canonical `mcpServers` object format. This allows for advanced configurations including custom HTTP headers for SSE and Streamable HTTP transports.

- Adds `mcpServers` to `ReasonixConfig` to support structured server definitions.
- Implements `normalizeMcpConfig` to merge legacy `mcp` strings with the new object format, ensuring `mcpServers` takes precedence.
- Enhances `buildTransportFromSpec` to support passing `headers` for non-stdio transports.
- Updates CLI commands (`acp`, `mcp-inspect`, `mcp-runtime`, `run`) and internal resolution logic to use normalized configurations.
- Adds `specToRaw` for serializing normalized specs back to legacy string formats.
- Updates documentation to reflect the new configuration schema and examples.
- Adds unit tests for configuration normalization logic.

* feat(mcp): refine spec construction logic for different transport types

Implements transport-specific property assignment when merging parsed MCP specifications with normalized configuration. This ensures that environment variables are only applied to `stdio` transports, while HTTP headers are correctly scoped to `sse` and `streamable-http` transports, preventing invalid configuration leakage between types.

- Update `mcp-inspect` and `mcp-runtime` to use conditional spec building based on transport type.
- Refactor `reconnectMcpServer` to decouple transport-specific properties from the base specification.
- Improve type safety by explicitly typing the constructed `McpServerSpec`.

* refactor(mcp): centralize spec overlay logic into `overlayMatchedSpec`

Extracts the complex conditional logic for merging parsed MCP specifications with configuration into a dedicated utility function. This simplifies the command implementations in `mcp-inspect` and `mcp-runtime` and cleans up the reconnection logic.

- Add `overlayMatchedSpec` to `src/mcp/spec.ts` to handle transport-specific property merging.
- Replace inline switch statements in `mcp-inspect.ts` and `mcp-runtime.ts` with the new utility.
- Simplify `reconnectMcpServer` in `src/mcp/reconnect.ts` by removing redundant spec reconstruction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(config): add standard mcpServers object format with HTTP auth support

2 participants