Skip to content

feat: complete Sprint 4.1 MCP registry adoption#21

Closed
codewithkenzo wants to merge 5 commits intomainfrom
feat/sprint4-1-mcp-registry-adoption
Closed

feat: complete Sprint 4.1 MCP registry adoption#21
codewithkenzo wants to merge 5 commits intomainfrom
feat/sprint4-1-mcp-registry-adoption

Conversation

@codewithkenzo
Copy link
Owner

@codewithkenzo codewithkenzo commented Feb 7, 2026

Summary

  • adopt the new MCP registry in runtime config composition so MCP assembly follows one source of truth (builtin/custom/plugin/skill precedence + collisions)
  • extend mcp_query to load plugin MCP servers through registry-backed discovery while preserving custom-first behavior and clearer totals metadata
  • migrate doctor MCP checks to registry-backed inspection and update MCP doctor tests accordingly

Verification

  • bun run typecheck
  • bun test src/features/mcp-registry/service.test.ts src/tools/mcp-query/tools.test.ts src/cli/doctor/checks/mcp.test.ts
  • bun test src/features/claude-code-mcp-loader/loader.test.ts src/features/skill-mcp-manager/manager.test.ts src/features/mcp-registry/service.test.ts src/tools/mcp-query/tools.test.ts src/cli/doctor/checks/mcp.test.ts

Notes

  • bun test src/plugin-handlers/config-handler.test.ts still contains pre-existing category-default expectation failures unrelated to this change set.

Greptile Overview

Greptile Summary

  • Migrates MCP composition to a registry as the single source of truth (builtin/custom/plugin/skill precedence + collision reporting) and uses it to populate config.mcp.
  • Updates mcp_query to discover plugin MCP servers via an injected loadPluginMcpServers callback while preserving registry-based filtering and totals metadata.
  • Reworks doctor MCP checks/tests to use registry-backed inspection for builtin/custom servers and adds basic validation for user configs.
  • Adds defensive skipping for malformed plugin MCP configs (registry + query) rather than throwing.

Confidence Score: 3/5

  • This PR is close, but should not merge until the runtime MCP config shape mismatch is fixed.
  • Registry adoption is cohesive and tests were updated, but toRuntimeMcpServerMap appears to write the wrong config shape into config.mcp, which can break MCP startup at runtime. There is also an inconsistent limit/refactor state in mcp_query that should be cleaned up to avoid metadata/behavior drift.
  • src/features/mcp-registry/service.ts, src/plugin-handlers/config-handler.ts, src/tools/mcp-query/tools.ts

Important Files Changed

Filename Overview
src/cli/doctor/checks/mcp.test.ts Updated tests to await async MCP info loaders and account for added builtin server (websearch).
src/cli/doctor/checks/mcp.ts Doctor MCP checks now build a registry-backed view of builtin/custom MCP servers and reintroduce basic config validation for user servers.
src/features/mcp-registry/service.test.ts Adjusted registry tests to expect malformed plugin configs to be skipped instead of throwing.
src/features/mcp-registry/service.ts Registry now skips invalid plugin server configs and adds toRuntimeMcpServerMap using transformMcpServer, but return type appears incorrect (transform output != McpServerConfig).
src/index.ts Adds loadPluginMcpServers callback to load plugin MCP servers via plugin loader unless plugins are disabled.
src/plugin-handlers/config-handler.ts Runtime MCP config composition now uses MCP registry + collision logging and converts effective servers into runtime mcp map via toRuntimeMcpServerMap.
src/tools/mcp-query/tools.test.ts Adds test ensuring mcp_query can load plugin MCP servers via loadPluginMcpServers callback.
src/tools/mcp-query/tools.ts mcp_query registry loader can discover plugin servers and slices servers before operation fetch; scope filter now only applies to custom servers (known issue in threads).

Sequence Diagram

sequenceDiagram
  autonumber
  participant Doctor as doctor:mcp check
  participant Loader as claude-code-mcp-loader
  participant Registry as mcp-registry
  participant Query as tool:mcp_query
  participant PluginLoader as claude-code-plugin-loader

  Doctor->>Registry: createMcpRegistry(builtinServers)
  Doctor->>Registry: filterMcpRegistryServers("builtin")
  Doctor-->>Doctor: format builtin info

  Doctor->>Loader: loadRawMcpConfigs()
  Loader-->>Doctor: loadedServers
  Doctor->>Registry: createMcpRegistry(customServers)
  Doctor->>Registry: filterMcpRegistryServers("custom")
  Doctor-->>Doctor: validate command/url basics

  Query->>Loader: loadRawMcpConfigs() (if includeCustomMcp)
  Query->>PluginLoader: loadPluginMcpServers() (optional)
  PluginLoader-->>Query: pluginServers map
  Query->>Registry: createMcpRegistry(builtin+custom+plugin+skills)
  Query->>Registry: filterMcpRegistryServers(source)
  Query-->>Query: apply scope filter + limit
  Query-->>Query: optionally fetch operations via manager

  PluginLoader->>Registry: createMcpRegistry(builtin+custom+pluginServers)
  PluginLoader->>Registry: filterMcpRegistryServers("all")
  PluginLoader->>Registry: toRuntimeMcpServerMap(effectiveServers)
  Registry-->>PluginLoader: runtime mcp map
Loading

@codewithkenzo
Copy link
Owner Author

@greptileai review\n\nSprint 4.1 registry adoption ready for review.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

7 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 84 to 86
const pluginServers = options.loadPluginMcpServers
? await options.loadPluginMcpServers()
: {}
Copy link

Choose a reason for hiding this comment

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

Unhandled plugin load failure

defaultLoadRegistry awaits loadPluginMcpServers() without a try/catch. If plugin discovery throws (e.g., bad plugin config / missing plugin file), mcp_query fails entirely even in include_operations: false mode. Consider catching and surfacing a non-fatal error (e.g., omit plugin servers + include an error string in the response) so querying other sources still works.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tools/mcp-query/tools.ts
Line: 84:86

Comment:
**Unhandled plugin load failure**

`defaultLoadRegistry` awaits `loadPluginMcpServers()` without a try/catch. If plugin discovery throws (e.g., bad plugin config / missing plugin file), `mcp_query` fails entirely even in `include_operations: false` mode. Consider catching and surfacing a non-fatal error (e.g., omit plugin servers + include an error string in the response) so querying other sources still works.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

src/features/mcp-registry/service.ts
Plugin local config crash

pluginConfigToClaudeConfig assumes config.command exists (config.command.length), but McpServerConfig for non-remote plugin servers can be missing/undefined (and you already treat missing url as invalid). In that case this will throw Cannot read properties of undefined (reading 'length') while building the registry (startup + mcp_query), rather than producing a controlled error. Guard config.command before reading .length and emit a consistent validation error.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 39:41

Comment:
**Plugin local config crash**

`pluginConfigToClaudeConfig` assumes `config.command` exists (`config.command.length`), but `McpServerConfig` for non-remote plugin servers can be missing/undefined (and you already treat missing url as invalid). In that case this will throw `Cannot read properties of undefined (reading 'length')` while building the registry (startup + `mcp_query`), rather than producing a controlled error. Guard `config.command` before reading `.length` and emit a consistent validation error.

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 27 to 32
return filterMcpRegistryServers(registry, "custom").map((server) => ({
id: server.name,
type: "user" as const,
enabled: true,
valid: true,
}))
Copy link

Choose a reason for hiding this comment

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

Always returns valid: true - invalid MCP configs won't be detected

The old implementation validated each server config and set valid: false with error messages for broken configs. Now all servers are marked valid, so checkUserMcpServers can never warn about configuration issues. Test at mcp.test.ts:89-101 expects this validation but will fail.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/doctor/checks/mcp.ts
Line: 27:32

Comment:
Always returns `valid: true` - invalid MCP configs won't be detected

The old implementation validated each server config and set `valid: false` with error messages for broken configs. Now all servers are marked valid, so `checkUserMcpServers` can never warn about configuration issues. Test at `mcp.test.ts:89-101` expects this validation but will fail.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 418 to 421
config.mcp = {
...(config.mcp as Record<string, unknown>),
...createBuiltinMcps(pluginConfig.disabled_mcps),
...mcpResult.servers,
...pluginComponents.mcpServers,
...toRuntimeMcpServerMap(filterMcpRegistryServers(mcpRegistry, "all")),
};
Copy link

Choose a reason for hiding this comment

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

No error handling for toRuntimeMcpServerMap

transformMcpServer throws on invalid configs (missing url for http, missing command for stdio). If any server in the registry has bad config, this will crash plugin initialization. Wrap in try-catch and log + skip invalid servers instead.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin-handlers/config-handler.ts
Line: 418:421

Comment:
No error handling for `toRuntimeMcpServerMap`

`transformMcpServer` throws on invalid configs (missing url for http, missing command for stdio). If any server in the registry has bad config, this will crash plugin initialization. Wrap in try-catch and log + skip invalid servers instead.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 197 to 207
export function toRuntimeMcpServerMap(
servers: McpRegistryServerDescriptor[]
): Record<string, McpServerConfig> {
const map: Record<string, McpServerConfig> = {}

for (const server of servers) {
map[server.name] = transformMcpServer(server.name, server.config)
}

return map
}
Copy link

Choose a reason for hiding this comment

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

transformMcpServer can throw - consider error handling

Called from config-handler critical path. If any server descriptor has invalid config, this throws and breaks initialization. Consider catching per-server and returning a partial map with errors logged.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 197:207

Comment:
`transformMcpServer` can throw - consider error handling

Called from config-handler critical path. If any server descriptor has invalid config, this throws and breaks initialization. Consider catching per-server and returning a partial map with errors logged.

How can I resolve this? If you propose a fix, please make it concise.

@codewithkenzo
Copy link
Owner Author

Closing: duplicate of #22. This PR incorrectly targets main instead of dev.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 27 to 32
return filterMcpRegistryServers(registry, "custom").map((server) => ({
id: server.name,
type: "user" as const,
enabled: true,
valid: true,
}))
Copy link

Choose a reason for hiding this comment

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

always hardcoded to valid: true - validation was removed

old implementation checked typeof config === "object" && config !== null, now registry-based approach doesn't validate config structure so test at mcp.test.ts:89-101 will fail

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/doctor/checks/mcp.ts
Line: 27:32

Comment:
always hardcoded to `valid: true` - validation was removed

old implementation checked `typeof config === "object" && config !== null`, now registry-based approach doesn't validate config structure so test at mcp.test.ts:89-101 will fail

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +39 to +41
if (!config.command) {
throw new Error("Invalid plugin MCP local config: missing command")
}
Copy link

Choose a reason for hiding this comment

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

guard added but empty command array still throws on line 43

should also check array length here before accessing command[0] on line 49

Suggested change
if (!config.command) {
throw new Error("Invalid plugin MCP local config: missing command")
}
if (!config.command || config.command.length === 0) {
throw new Error("Invalid plugin MCP local config: missing or empty command")
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 39:41

Comment:
guard added but empty `command` array still throws on line 43

should also check array length here before accessing `command[0]` on line 49

```suggestion
  if (!config.command || config.command.length === 0) {
    throw new Error("Invalid plugin MCP local config: missing or empty command")
  }
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 402 to 406
const mcpRegistry = createMcpRegistry({
builtinServers: createBuiltinMcps(pluginConfig.disabled_mcps),
customServers: customRawServers,
pluginServers: pluginComponents.mcpServers,
});
Copy link

Choose a reason for hiding this comment

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

registry creation can throw if pluginServers contains invalid configs

pluginConfigToClaudeConfig (called during registry creation) throws on missing command/url. wrap in try-catch and log errors instead of crashing initialization

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin-handlers/config-handler.ts
Line: 402:406

Comment:
registry creation can throw if `pluginServers` contains invalid configs

`pluginConfigToClaudeConfig` (called during registry creation) throws on missing `command`/`url`. wrap in try-catch and log errors instead of crashing initialization

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 418 to 421
config.mcp = {
...(config.mcp as Record<string, unknown>),
...createBuiltinMcps(pluginConfig.disabled_mcps),
...mcpResult.servers,
...pluginComponents.mcpServers,
...toRuntimeMcpServerMap(filterMcpRegistryServers(mcpRegistry, "all")),
};
Copy link

Choose a reason for hiding this comment

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

toRuntimeMcpServerMap calls transformMcpServer which throws on invalid configs (missing url for http, missing command for stdio)

if any server descriptor has bad config, this crashes initialization. wrap in try-catch and skip invalid servers

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin-handlers/config-handler.ts
Line: 418:421

Comment:
`toRuntimeMcpServerMap` calls `transformMcpServer` which throws on invalid configs (missing `url` for http, missing `command` for stdio)

if any server descriptor has bad config, this crashes initialization. wrap in try-catch and skip invalid servers

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 84 to 86
const pluginServers = options.loadPluginMcpServers
? await options.loadPluginMcpServers()
: {}
Copy link

Choose a reason for hiding this comment

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

no try-catch around loadPluginMcpServers()

if plugin discovery throws (bad plugin config / missing file), mcp_query fails entirely even with include_operations: false. catch and surface non-fatal error so querying other sources still works

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tools/mcp-query/tools.ts
Line: 84:86

Comment:
no try-catch around `loadPluginMcpServers()`

if plugin discovery throws (bad plugin config / missing file), `mcp_query` fails entirely even with `include_operations: false`. catch and surface non-fatal error so querying other sources still works

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

src/features/mcp-registry/service.ts
pluginConfigToClaudeConfig can throw on lines 29, 40, 44

if any plugin server has invalid config, registry creation fails and crashes the caller. consider catching per-server and logging + skipping invalid entries

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 118:130

Comment:
`pluginConfigToClaudeConfig` can throw on lines 29, 40, 44

if any plugin server has invalid config, registry creation fails and crashes the caller. consider catching per-server and logging + skipping invalid entries

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 36 to 39
if (!config.command) {
valid = false
error = "Missing required field: command"
}
Copy link

Choose a reason for hiding this comment

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

check if config.command is empty string or empty array - !config.command passes for empty array [] which would cause transformMcpServer to fail later

Suggested change
if (!config.command) {
valid = false
error = "Missing required field: command"
}
if (!config.command || (Array.isArray(config.command) && config.command.length === 0) || config.command === "") {
valid = false
error = "Missing required field: command"
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/doctor/checks/mcp.ts
Line: 36:39

Comment:
check if `config.command` is empty string or empty array - `!config.command` passes for empty array `[]` which would cause `transformMcpServer` to fail later

```suggestion
      if (!config.command || (Array.isArray(config.command) && config.command.length === 0) || config.command === "") {
        valid = false
        error = "Missing required field: command"
      }
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +201 to +214
export function toRuntimeMcpServerMap(
servers: McpRegistryServerDescriptor[]
): Record<string, McpServerConfig> {
const map: Record<string, McpServerConfig> = {}

for (const server of servers) {
try {
map[server.name] = transformMcpServer(server.name, server.config)
} catch {
// Skip servers with invalid configs during runtime map construction
}
}

return map
Copy link

Choose a reason for hiding this comment

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

Type mismatch in map

toRuntimeMcpServerMap is declared to return Record<string, McpServerConfig>, but it assigns transformMcpServer(...) (which returns a Claude Code runtime server config, not the raw McpServerConfig type used for plugin configs). This makes the return type incorrect and can hide real incompatibilities at call sites (e.g. config-handler.ts spreads this into config.mcp). Update the return type to match transformMcpServer’s actual return type (or stop using transformMcpServer here) so type checking reflects what’s actually produced.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 201:214

Comment:
**Type mismatch in map**

`toRuntimeMcpServerMap` is declared to return `Record<string, McpServerConfig>`, but it assigns `transformMcpServer(...)` (which returns a Claude Code runtime server config, not the raw `McpServerConfig` type used for plugin configs). This makes the return type incorrect and can hide real incompatibilities at call sites (e.g. `config-handler.ts` spreads this into `config.mcp`). Update the return type to match `transformMcpServer`’s actual return type (or stop using `transformMcpServer` here) so type checking reflects what’s actually produced.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 135 to 141
if (args.scope) {
servers = servers.filter((server) => server.scope === args.scope)
servers = servers.filter((server) => server.source === "custom" ? server.scope === args.scope : true)
}

const candidateServers = servers.length
servers = servers.slice(0, limit)

Copy link

Choose a reason for hiding this comment

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

Scope filter breaks totals

The new scope filter only applies to custom servers (servers.filter(server => server.source === "custom" ? server.scope === args.scope : true)), but args.scope is documented as a general “Filter by MCP config scope”. When querying source: all (or plugin/skill), this will still return non-custom servers even though a scope filter was requested, and candidate_servers/returned_servers will include those unfiltered entries. Either apply the scope filter consistently across all sources (using the appropriate scope values for each) or reject scope for non-custom sources with a clear error.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tools/mcp-query/tools.ts
Line: 135:141

Comment:
**Scope filter breaks totals**

The new scope filter only applies to `custom` servers (`servers.filter(server => server.source === "custom" ? server.scope === args.scope : true)`), but `args.scope` is documented as a general “Filter by MCP config scope”. When querying `source: all` (or `plugin`/`skill`), this will still return non-custom servers even though a scope filter was requested, and `candidate_servers`/`returned_servers` will include those unfiltered entries. Either apply the scope filter consistently across all sources (using the appropriate scope values for each) or reject `scope` for non-custom sources with a clear error.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

src/tools/mcp-query/tools.ts
Incorrect total_servers count

After slicing servers to limit (line ~140), total_servers is returned as results.length (line ~269), which is now “results after limiting and query filtering”, not the total available matches. This makes total_servers misleading (and can be smaller than returned_servers semantics suggest), especially when include_operations: true and query filtering continues inside the loop. Consider defining totals explicitly (e.g., total_matching_servers pre-limit vs returned_servers post-limit) and wiring total_servers to the pre-limit count to match the field name.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tools/mcp-query/tools.ts
Line: 139:272

Comment:
**Incorrect total_servers count**

After slicing `servers` to `limit` (line ~140), `total_servers` is returned as `results.length` (line ~269), which is now “results after limiting and query filtering”, not the total available matches. This makes `total_servers` misleading (and can be smaller than `returned_servers` semantics suggest), especially when `include_operations: true` and query filtering continues inside the loop. Consider defining totals explicitly (e.g., total_matching_servers pre-limit vs returned_servers post-limit) and wiring `total_servers` to the pre-limit count to match the field name.

How can I resolve this? If you propose a fix, please make it concise.

…, scope filter, early limit

- Restore per-server config validation in getUserMcpInfo() (was hardcoded valid: true)
- Make toRuntimeMcpServerMap() resilient with try-catch per server
- Wrap createMcpRegistry() in try-catch with fallback to builtin+custom only
- Wrap loadPluginMcpServers() in try-catch for graceful degradation
- Scope filter now only applies to custom sources (builtin/plugin/skill not silently dropped)
- Apply limit before connecting to servers (not after)
…y command validation

- Wrap pluginConfigToClaudeConfig in try-catch per server in createMcpRegistry
  so one bad plugin config doesn't crash the entire registry
- Strengthen doctor command validation to catch empty string and empty array
- Update tests: malformed plugin configs are now silently skipped, not thrown
@codewithkenzo codewithkenzo force-pushed the feat/sprint4-1-mcp-registry-adoption branch from 01de010 to 12a6b3f Compare February 7, 2026 02:53
@codewithkenzo
Copy link
Owner Author

Superseded by #23 which includes all Sprint 4.1 + 4.2 commits.

@codewithkenzo codewithkenzo deleted the feat/sprint4-1-mcp-registry-adoption branch February 7, 2026 02:55
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +201 to +214
export function toRuntimeMcpServerMap(
servers: McpRegistryServerDescriptor[]
): Record<string, McpServerConfig> {
const map: Record<string, McpServerConfig> = {}

for (const server of servers) {
try {
map[server.name] = transformMcpServer(server.name, server.config)
} catch {
// Skip servers with invalid configs during runtime map construction
}
}

return map
Copy link

Choose a reason for hiding this comment

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

Runtime MCP type mismatch
toRuntimeMcpServerMap is typed as returning Record<string, McpServerConfig> but it populates values with transformMcpServer(server.name, server.config). Here server.config is a ClaudeCode runtime server shape (ClaudeCodeMcpServer), while McpServerConfig is the raw loader shape ({type: local|remote, command/url, ...}). This map is spread into config.mcp in src/plugin-handlers/config-handler.ts:428-433, so config.mcp will end up in the wrong shape for downstream MCP wiring.

Fix: either (a) change the function to return Record<string, ClaudeCodeMcpServer> and skip transformMcpServer entirely, or (b) keep transformMcpServer but don’t use the result as config.mcp (use it only where raw configs are expected).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/mcp-registry/service.ts
Line: 201:214

Comment:
**Runtime MCP type mismatch**
`toRuntimeMcpServerMap` is typed as returning `Record<string, McpServerConfig>` but it populates values with `transformMcpServer(server.name, server.config)`. Here `server.config` is a *ClaudeCode runtime* server shape (`ClaudeCodeMcpServer`), while `McpServerConfig` is the *raw loader* shape (`{type: local|remote, command/url, ...}`). This map is spread into `config.mcp` in `src/plugin-handlers/config-handler.ts:428-433`, so `config.mcp` will end up in the wrong shape for downstream MCP wiring.

Fix: either (a) change the function to return `Record<string, ClaudeCodeMcpServer>` and skip `transformMcpServer` entirely, or (b) keep `transformMcpServer` but don’t use the result as `config.mcp` (use it only where raw configs are expected).

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

src/tools/mcp-query/tools.ts
Result limiting is inconsistent
In execute, candidate_servers is captured before applying the limit, then servers = servers.slice(0, limit) is applied, but the later limitedResults variable was changed to const limitedResults = results (no-op). This leaves the implementation in an inconsistent state where the limiting logic is split and easy to regress (e.g., if results ever diverges from servers again).

Fix: apply the limit in one place (either slice servers and remove limitedResults, or keep results.slice(0, limit) and don’t slice servers), and ensure candidate_servers/returned_servers/total_servers reflect the chosen behavior.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tools/mcp-query/tools.ts
Line: 121:140

Comment:
**Result limiting is inconsistent**
In `execute`, `candidate_servers` is captured before applying the limit, then `servers = servers.slice(0, limit)` is applied, but the later `limitedResults` variable was changed to `const limitedResults = results` (no-op). This leaves the implementation in an inconsistent state where the limiting logic is split and easy to regress (e.g., if `results` ever diverges from `servers` again).

Fix: apply the limit in one place (either slice `servers` and remove `limitedResults`, or keep `results.slice(0, limit)` and don’t slice `servers`), and ensure `candidate_servers`/`returned_servers`/`total_servers` reflect the chosen behavior.

How can I resolve this? If you propose a fix, please make it concise.

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.

1 participant