Skip to content

feat(mcp-doctor): health-check & benchmark your MCP servers#201

Draft
genesiscz wants to merge 3 commits into
masterfrom
feat/pro-mcp-doctor
Draft

feat(mcp-doctor): health-check & benchmark your MCP servers#201
genesiscz wants to merge 3 commits into
masterfrom
feat/pro-mcp-doctor

Conversation

@genesiscz

@genesiscz genesiscz commented Jun 2, 2026

Copy link
Copy Markdown
Owner

What

tools mcp-doctor — health-check & benchmark your configured MCP servers.

It discovers every configured Model Context Protocol server (from the top-level mcpServers map of ~/.claude.json, plus project-level .mcp.json and .cursor/mcp.json), spawns/connects to each via the installed @modelcontextprotocol/sdk Client, runs the initialize handshake, lists its tools, measures startup latency, and reports a health table that flags dead, slow, and tool-name-colliding servers — before they bite you mid-session.

CLI surface

tools mcp-doctor [check]            # default: discover + spawn/connect + probe every server
tools mcp-doctor list              # config only — discover & normalize, NO spawn (fast, offline)
tools mcp-doctor tools <server>    # probe ONE server, print its tools / resources / prompts

Shared flags (work before or after the subcommand token): --json, --timeout <ms> (default 15000), --slow <ms> (default 3000), --only <names> (comma-list), --project <dir> (default cwd).

Design

Thin commander entrypoint over pure, testable lib functions:

  • discovery.tsreadConfigSources() (thin IO) + mergeServers() (PURE normalize, source attribution, project-over-global precedence, invalid entries for malformed defs).
  • report.tsclassifyResult() (PURE, clock-injected status: ok/slow/timeout/error) + buildReport() / formatHealthTable() / formatConfigTable() (PURE shaping).
  • duplicates.tsdetectDuplicateTools() (PURE cross-server tool-name collision detection, deterministically sorted).
  • probe.ts — INTEGRATION-only: builds the matching transport (stdio / streamable-http / sse), connect()listTools() (+ resources/prompts when advertised) → close(), guarded by the shared withTimeout(...) wall-clock race. This is the ONLY file that imports the SDK transports or reads the clock.

Latency is measured from just-before-connect to handshake-complete. Output discipline: result data → stdout only via out.result(...) / out.println(...); status/spinners/warnings → stderr; diagnostics → logger. --json emits parseable JSON with no banner bytes.

Testability boundary

The default unit test imports only discovery / duplicates / report — never probe.ts — so no SDK transport is loaded on the test path. The test is fully hermetic: synthetic JSON blobs + injected timestamps + fake tool lists, no network, no spawn, no dependence on the machine's live MCP config.

Verification (local)

  • bunx biome check src/mcp-doctor — exits 0 (clean).
  • bun test src/mcp-doctor — 14 pass, 0 fail, 35 assertions on the four pure cores (mergeServers, classifyResult, detectDuplicateTools, buildReport / formatHealthTable).
  • tsgo --noEmit — no type errors in src/mcp-doctor/.
  • ./tools mcp-doctor --help — exit 0, lists list / check (default) / tools <server> + shared flags.
  • ./tools mcp-doctor list / check --only foo with flags after the subcommand parse correctly (shared options registered per-subcommand, read via optsWithGlobals()).

Non-goals

No auto-fixing, no nested per-project block parsing of ~/.claude.json, no real spawning on the default test path, no call-tool, no watch/daemon mode.

Summary by CodeRabbit

New Features

  • Introduced mcp-doctor CLI tool for managing and diagnosing MCP servers
  • list command discovers and displays configured servers without probing
  • check command verifies server health and connectivity with concurrent probing
  • tools command inspects available tools on specific servers
  • Detects and reports duplicate tool names across servers
  • Supports both JSON and formatted table output formats
  • Configurable per-server timeout and slow-response thresholds

Tests

  • Added comprehensive test coverage for discovery, probing, and reporting functionality

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 518a6971-3be6-4646-983c-40aafe1fffbb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces a new mcp-doctor feature as a CLI tool. It adds a shared type system, a config-discovery module that reads and normalizes MCP server definitions from three JSON sources, a probe module that connects to each server via stdio/SSE/HTTP and queries its capabilities, a reporting module that classifies results and formats health/config tables, and a CLI entrypoint with list, check, and tools subcommands.

Changes

mcp-doctor CLI tool

Layer / File(s) Summary
Shared type system
src/mcp-doctor/lib/types.ts
Defines all exported types: Transport, ConfigSource, Status literals; StdioServer, RemoteServer, InvalidServer interfaces; NormalizedServer union with isInvalidServer guard; ProbeResult, DuplicateTool, DoctorSummary, and DoctorReport.
Config discovery and normalization
src/mcp-doctor/lib/discovery.ts, src/mcp-doctor/mcp-doctor.test.ts (lines 1–83)
readConfigSources concurrently reads ~/.claude.json, .mcp.json, and .cursor/mcp.json via Bun APIs. normalizeOne maps raw entries to typed server shapes. mergeServers applies source-precedence ordering and returns results sorted by name. Tests cover all normalization cases and override precedence.
MCP server probing
src/mcp-doctor/lib/probe.ts
buildTransport constructs a stdio, SSE, or streamable-HTTP Transport from a NormalizedServer. probeServer connects within a timeout, lists tools/resources/prompts based on advertised capabilities, captures errors, and returns a classified ProbeResult.
Result classification, duplicate detection, and formatting
src/mcp-doctor/lib/report.ts, src/mcp-doctor/lib/duplicates.ts, src/mcp-doctor/mcp-doctor.test.ts (lines 85–187)
classifyResult maps probe timing and error state to ok/slow/timeout/error. detectDuplicateTools finds tool names present on multiple servers. buildReport aggregates ProbeResult[] into a DoctorReport with summary counts. formatHealthTable and formatConfigTable render human-readable tables. Tests cover all classification, duplicate detection, and report/table rendering scenarios.
CLI entrypoint and subcommands
src/mcp-doctor/index.ts
Registers shared Commander options (--json, --timeout, --slow, --only, --project-dir). Wires list, check, and tools subcommands using the discovery, probe, and reporting layers, then registers the tool via runTool.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature being introduced—a health-check and benchmarking tool for MCP servers—which aligns with the PR's primary objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pro-mcp-doctor

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces mcp-doctor, a CLI tool to health-check and benchmark configured Model Context Protocol (MCP) servers. It discovers configurations from multiple sources, probes servers over stdio, HTTP, or SSE, detects duplicate tools, and formats the results into a report. The review feedback highlights several robustness improvements: moving transport initialization inside a try-catch block to prevent CLI crashes, correcting timeout classification, validating URLs during discovery, defensively checking the configuration object structure, including invalid servers in the summary error count, and validating CLI timeout and slow threshold inputs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +60 to +71
const client = new Client(CLIENT_INFO);
const transport = buildTransport(server);
const startedAt = Date.now();
let finishedAt: number | null = null;
let error: string | null = null;
let tools: string[] = [];
let resourceCount = 0;
let promptCount = 0;
let serverInfo: { name: string; version: string } | null = null;

try {
await withTimeout(client.connect(transport), opts.timeoutMs);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The buildTransport(server) function is called outside of the try/catch block. If transport initialization fails (for example, if new URL(server.url) throws a TypeError due to an invalid URL configuration), the error will go uncaught. This will cause the entire Promise.all in probeAll to reject, crashing the CLI tool.

Moving buildTransport inside the try block ensures that any initialization errors are gracefully caught, logged, and reported as a probe failure for that specific server.

Suggested change
const client = new Client(CLIENT_INFO);
const transport = buildTransport(server);
const startedAt = Date.now();
let finishedAt: number | null = null;
let error: string | null = null;
let tools: string[] = [];
let resourceCount = 0;
let promptCount = 0;
let serverInfo: { name: string; version: string } | null = null;
try {
await withTimeout(client.connect(transport), opts.timeoutMs);
const client = new Client(CLIENT_INFO);
const startedAt = Date.now();
let finishedAt: number | null = null;
let error: string | null = null;
let tools: string[] = [];
let resourceCount = 0;
let promptCount = 0;
let serverInfo: { name: string; version: string } | null = null;
try {
const transport = buildTransport(server);
await withTimeout(client.connect(transport), opts.timeoutMs);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - moved the buildTransport call inside the try block so a malformed remote URL throwing from new URL() now fails that single server instead of rejecting the Promise.all and crashing the whole batch. Also validating the URL at discovery time (see the discovery.ts thread) so bad URLs surface offline in list too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the update and for confirming the fix in 82b3ca5. Validating the URL at discovery time is a great approach to ensure that configuration issues are caught early and reported clearly, rather than failing during the probe phase. This change significantly improves the robustness of the mcp-doctor tool.

Comment on lines +20 to +23
if (input.error) {
const latency = input.finishedAt === null ? null : input.finishedAt - input.startedAt;
return { status: "error", latencyMs: latency };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The "timeout" status is currently unreachable for connection timeouts. When withTimeout times out, it throws an error which is caught in probeServer and assigned to error. Because input.error is non-null, classifyResult always returns "error" status instead of "timeout".

Checking if the error message indicates a timeout when finishedAt is null allows us to correctly classify and report actual timeouts.

Suggested change
if (input.error) {
const latency = input.finishedAt === null ? null : input.finishedAt - input.startedAt;
return { status: "error", latencyMs: latency };
}
if (input.error) {
const isTimeout = input.error.toLowerCase().includes("timeout") || input.error.toLowerCase().includes("timed out");
if (isTimeout && input.finishedAt === null) {
return { status: "timeout", latencyMs: null };
}
const latency = input.finishedAt === null ? null : input.finishedAt - input.startedAt;
return { status: "error", latencyMs: latency };
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - the timeout branch was dead because withTimeout rejects with an Error, probe sets the error field, and classifyResult checks error first. Now I lowercase the message and check for timeout or timed out, gated on finishedAt being null, so genuine handshake timeouts classify as timeout instead of generic error.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The fix in commit 82b3ca5 correctly addresses the issue where connection timeouts were being masked as generic errors. By checking for timeout-related keywords in the error message when finishedAt is null, the classifyResult function now correctly categorizes these as timeout status, which is the expected behavior for handshake failures. This is a robust approach given the current error handling flow.

Comment on lines +44 to +47
if (typeof def.url === "string" && def.url.length > 0) {
const transport = def.type === "sse" ? "sse" : "http";
return { name, transport, source, url: def.url };
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The normalizeOne function does not validate that def.url is a valid URL. If an invalid URL is configured, it is still treated as a valid remote server, which then fails during the probe phase.

Validating the URL during discovery allows us to catch malformed URLs early, marking them as invalid so they are correctly flagged in the offline tools mcp-doctor list command.

Suggested change
if (typeof def.url === "string" && def.url.length > 0) {
const transport = def.type === "sse" ? "sse" : "http";
return { name, transport, source, url: def.url };
}
if (typeof def.url === "string" && def.url.length > 0) {
try {
new URL(def.url);
const transport = def.type === "sse" ? "sse" : "http";
return { name, transport, source, url: def.url };
} catch {
return {
name,
transport: "stdio",
source,
invalidReason: `invalid URL: "${def.url}"`,
};
}
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - normalizeOne now wraps the url in new URL() and returns an InvalidServer with an invalidReason when it throws, so a malformed URL is flagged invalid at discovery instead of only failing at probe time. The InvalidServer type, isInvalidServer guard, and the invalid rendering in formatConfigTable already exist, so it shows up correctly in offline list output. Root-cause companion to the probe try/catch fix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the update, genesiscz. That approach sounds correct and robust. By handling the URL validation during the discovery phase and marking the server as invalid with a clear reason, you've successfully improved the user experience by providing immediate feedback rather than waiting for a probe failure. This aligns perfectly with the goal of making mcp-doctor list a fast, reliable offline tool.

Comment on lines +66 to +69
const map = config?.mcpServers;
if (!map) {
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If mcpServers in the JSON configuration is not a plain object (e.g., if it is an array, string, or other unexpected type), Object.entries(map) will behave unexpectedly or throw an error.

Adding a defensive check to ensure map is a non-array object prevents potential crashes when parsing malformed configuration files.

Suggested change
const map = config?.mcpServers;
if (!map) {
continue;
}
const map = config?.mcpServers;
if (!map || typeof map !== "object" || Array.isArray(map)) {
continue;
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - mcpServers comes from an unchecked cast over untrusted file contents, so it could be an array/string/number at runtime where the old truthy-only check would feed garbage index pairs into Object.entries. Added a guard that also requires it to be a non-array object before iterating.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the update and for applying the fix in 82b3ca5. The added guard ensures that mcpServers is a non-array object, which correctly prevents runtime errors when parsing potentially malformed configuration files. This looks good.

Comment on lines +67 to +75
const count = (s: Status): number => results.filter((r) => r.status === s).length;
const summary = {
total: results.length,
ok: count("ok"),
slow: count("slow"),
timeout: count("timeout"),
error: count("error"),
duplicateTools: duplicates.length,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Invalid servers are assigned status: "invalid", but they are currently not counted in any of the summary status fields (ok, slow, timeout, error), even though they are included in total. This leads to a confusing summary line where the numbers do not add up (e.g., 1 servers (0 ok · 0 slow · 0 error)).

Counting invalid servers under error in the summary resolves this mismatch cleanly.

Suggested change
const count = (s: Status): number => results.filter((r) => r.status === s).length;
const summary = {
total: results.length,
ok: count("ok"),
slow: count("slow"),
timeout: count("timeout"),
error: count("error"),
duplicateTools: duplicates.length,
};
const count = (s: Status): number => results.filter((r) => r.status === s).length;
const summary = {
total: results.length,
ok: count("ok"),
slow: count("slow"),
timeout: count("timeout"),
error: count("error") + count("invalid"),
duplicateTools: duplicates.length,
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - invalid servers counted toward total but no status sub-count, so the header could read 1 servers (0 ok, 0 slow, 0 error). Folded invalid into the error count as suggested, and also added the existing-but-unshown timeout count to the header line so timed-out-only runs reconcile too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the update and for incorporating the suggested fix for the invalid server status count. Adding the timeout count to the header is also a great improvement for reconciliation. I have reviewed the changes in 82b3ca5 and they look correct and address the issues identified.

Comment thread src/mcp-doctor/index.ts
Comment on lines +47 to +51
async function probeAll(servers: NormalizedServer[], opts: SharedOpts): Promise<ProbeResult[]> {
const timeoutMs = Number(opts.timeout);
const slowThresholdMs = Number(opts.slow);
return Promise.all(servers.map((server) => probeServer(server, { timeoutMs, slowThresholdMs })));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The opts.timeout and opts.slow options are parsed as numbers without validation. To prevent runtime issues like NaN propagation, these CLI arguments should be validated and normalized at the entry point (e.g., in the commander action handler) before being passed to business logic functions like probeAll.

async function probeAll(servers: NormalizedServer[], opts: SharedOpts): Promise<ProbeResult[]> {
    const timeoutMs = Number(opts.timeout);
    const slowThresholdMs = Number(opts.slow);

    if (Number.isNaN(timeoutMs) || timeoutMs <= 0) {
        throw new Error(`Invalid --timeout value: "${opts.timeout}". Must be a positive number.`);
    }
    if (Number.isNaN(slowThresholdMs) || slowThresholdMs <= 0) {
        throw new Error(`Invalid --slow value: "${opts.slow}". Must be a positive number.`);
    }

    return Promise.all(servers.map((server) => probeServer(server, { timeoutMs, slowThresholdMs })));
}
References
  1. Validate and normalize CLI arguments at the entry point (e.g., in a commander action handler) before they are passed to business logic.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

/gemini Fixed in 82b3ca5 (82b3ca5) - Number(opts.timeout) and Number(opts.slow) were unvalidated, so --timeout abc yielded NaN which made setTimeout fire immediately and the slow comparison always false. Added validation in probeAll using Number.isFinite plus a positive check, throwing a clear error (Number.isFinite also rejects Infinity).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the update, genesiscz. Using Number.isFinite and adding a positive check is a robust way to handle these inputs and prevents the NaN propagation issues I noted. This looks like a solid fix.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp-doctor/index.ts`:
- Around line 85-88: Import isInteractive from `@app/utils/cli` at the top of the
file, then wrap the spinner initialization and usage (the spinner.start() and
spinner.stop() calls) in a conditional check for isInteractive(). The probeAll()
function call should still execute regardless of interactivity, but the spinner
visual feedback should only be shown in interactive environments to prevent
unwanted output in CI or piped environments.
- Around line 48-49: The Number() conversions of opts.timeout and opts.slow into
timeoutMs and slowThresholdMs variables do not validate that the conversions
succeeded. Add validation after each Number() call to check that the result is
not NaN, and handle invalid numeric input by either throwing an error with a
clear message indicating the option must be numeric, or falling back to a
sensible default value. This ensures only valid numbers are passed to
probeServer.

In `@src/mcp-doctor/lib/probe.ts`:
- Around line 22-28: The type assertion `as Record<string, string>` on the
merged environment object in the StdioClientTransport creation is unsafe because
process.env values can be string or undefined. Remove the type assertion and
either let TypeScript infer the proper type, or defensively filter out undefined
values from the merged environment object (using Object.entries() with a filter
condition) before passing it to ensure all values are strings and the type
matches what StdioClientTransport expects.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3d096198-d37f-4e9e-942a-5f0b44d06d07

📥 Commits

Reviewing files that changed from the base of the PR and between 581f71f and 845c845.

📒 Files selected for processing (7)
  • src/mcp-doctor/index.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.ts: Always import and use SafeJSON from @app/utils/json instead of the global JSON object; use SafeJSON.parse() and SafeJSON.stringify() everywhere
Use logger (from @app/logger) for diagnostics; write to day-stamped file always and to stderr only when log level permits; use out.result() as the only writer to stdout
Log enough context to triage issues from logs alone without re-running the tool; log key decision branches, external-resource access, mode/config resolution, and result counts
Prefer error: err over error: err instanceof Error ? err.message : String(err) when the error field accepts unknown type

Files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{ts,tsx}: Do not use as any type assertions; use proper type narrowing, type guards, or explicit interfaces instead
When working with union types, use discriminant checks (e.g. entity.className === "User") instead of type assertions
Never use bare catch {} blocks; at minimum log the caught error with context using logger.debug() or logger.warn()
For functions with 3+ parameters or optional parameters, use an object parameter instead of positional parameters
Do not use one-line if statements, even for early returns; always use block form with braces
Add an empty line before if statements unless the preceding line is a variable declaration used by that if
Add an empty line after closing } unless followed by else, catch, finally, or another }
Always check isInteractive() from @app/utils/cli before showing prompts; provide sensible defaults or error with suggestCommand() in non-interactive mode

Files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Never add a file-path comment as the first line of files (e.g., // src/path/to/file.ts)
Do not add comments that restate what the code already says; avoid obvious comments like // Build initial context before buildContext()

Files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
src/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

When adding database logic, use an in-memory new Database(":memory:") for testing; group test files alongside source files

Files:

  • src/mcp-doctor/mcp-doctor.test.ts
src/**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/index.ts: Tool entry points must use a TypeScript file with shebang that shows an interactive tool selector when run without arguments, and executes the specified tool via bun run when given arguments
Tool entry points must end with await runTool(program, { tool }) from @app/utils/cli, which owns -v/--readme/help registration and console-level resolution

Files:

  • src/mcp-doctor/index.ts
src/*/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Tool directories must contain either index.ts/index.tsx or standalone .ts/.tsx files; tool name is derived from directory name or filename without extension

Files:

  • src/mcp-doctor/index.ts
🧠 Learnings (22)
📚 Learning: 2026-02-24T15:32:37.494Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 54
File: src/github/lib/output.ts:109-113
Timestamp: 2026-02-24T15:32:37.494Z
Learning: In TypeScript files under src/, do not require a leading blank line before an if statement that is the first statement inside a function body (immediately after the function signature). The blank line rule should only apply to if statements that come after other statements within the function body. Apply this guideline consistently across TS files in src to reduce unnecessary vertical whitespace and keep concise function bodies.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-09T13:13:58.786Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 81
File: src/github/commands/get.ts:209-212
Timestamp: 2026-03-09T13:13:58.786Z
Learning: In the GenesisTools repo (genesiscz/GenesisTools), do not treat CI formatter warnings as enforceable formatting rules for TypeScript files under src/. Focus reviews on logical correctness and consistency with existing code patterns. For files under src (e.g., src/github/commands/get.ts), prioritize code structure, readability, naming, correctness, and adherence to project conventions over automated formatting warnings from CI tools.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:26:31.610Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/timely/utils/entry-processor.ts:0-0
Timestamp: 2026-03-12T01:26:31.610Z
Learning: In code paths where JSON is consumed, prefer strict RFC 8259 validation by using SafeJSON.parse(text, { strict: true }) instead of the lenient default. Apply this at non-config boundaries (e.g., API responses, JSONL, cache outputs, subprocess outputs). Reserve the lenient comment-json behavior only for user-authored config files that may legitimately contain comments or trailing commas. For src/timely/utils/entry-processor.ts and similar modules, replace or wrap JSON parsing with SafeJSON.parse(text, { strict: true }) unless you are explicitly handling config files that require comments.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:58:27.831Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 103
File: src/port/index.ts:137-144
Timestamp: 2026-03-12T01:58:27.831Z
Learning: In GenesisTools, apply a no-obvious-comments rule: do not add inline comments for well-known POSIX patterns or standard idioms (e.g., a process.kill(pid, 0) probe) when surrounding code is self-documenting through descriptive function/variable names. This guidance applies to TypeScript files under src (src/**/*.ts). Only include comments if they add non-obvious rationale, edge-case behavior, or explain complex logic that cannot be inferred from code alone.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-22T22:19:44.520Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 119
File: src/indexer/commands/graph.ts:34-34
Timestamp: 2026-03-22T22:19:44.520Z
Learning: In genesiscz/GenesisTools, when using `SafeJSON.parse` in `src/**/*.ts`, it is acceptable to omit `{ strict: true }` if (and only if) the JSON being parsed is internal cache/state written by the same codebase (e.g., data saved by one internal writer and later read from a corresponding cached file). Do not require strict mode for these internal, machine-generated cache files. Require `{ strict: true }` at external/untrusted boundaries instead (e.g., API responses, third-party JSONL, subprocess output, or any JSON whose contents may not have been produced by trusted internal code).

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-25T19:55:27.917Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 129
File: src/utils/search/stores/vector-store.ts:19-23
Timestamp: 2026-03-25T19:55:27.917Z
Learning: When reviewing this codebase’s “3+ parameters → object parameter” guideline, only suggest object-parameter refactoring when the function’s parameters are ambiguous or include optional/unclear semantics. Do not flag tightly-defined utility/helper functions where (1) all parameters are required, (2) meanings are semantically clear from parameter names, and (3) the ordering is well-ordered and obvious. For example, functions like bruteForceVectorSearch(memoryIndex, queryVector, limit) should be allowed to keep positional parameters because the intent is clear.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-05-05T03:52:21.057Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 163
File: src/debugging-master/core/dashboard-server.ts:115-127
Timestamp: 2026-05-05T03:52:21.057Z
Learning: When reviewing Bun.serve fetch handlers in this repo, don’t treat `req.signal` as possibly `undefined` at runtime. Bun guarantees an `AbortSignal` on every incoming Request, so `req.signal?.addEventListener(...)` is unnecessary for runtime safety and is only a TypeScript narrowing artifact (e.g., the type might be `AbortSignal | null`). Therefore, don’t raise concerns about SSE/subscription cleanup being skipped because `req.signal` could be missing; cleanup decisions should be based on the actual handler lifecycle, not an imagined runtime absence of `req.signal`.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-06-11T22:07:33.681Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 216
File: src/macos/commands/mail/show.ts:8-8
Timestamp: 2026-06-11T22:07:33.681Z
Learning: In genesiscz/GenesisTools, treat `chalk` as the project-wide standard for colored terminal output in TypeScript files under `src/`. During code reviews, do not recommend replacing `chalk` with `picocolors` (or other alternatives) since CLAUDE.md and existing modules (e.g., `mcp-manager`) consistently use `chalk`. Only suggest converting `chalk` usages when the PR/user explicitly requests a full-project migration.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-06-11T22:07:40.404Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 216
File: src/mcp-manager/commands/remove.ts:6-6
Timestamp: 2026-06-11T22:07:40.404Z
Learning: In genesiscz/GenesisTools, when reviewing TypeScript CLI/terminal output code under `src/`, use `chalk` for colored terminal/CLI output. Do not suggest switching to `picocolors` (or any other color library); the repo convention (including `mcp-manager` and `CLAUDE.md`) standardizes on `chalk`.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-06-11T22:07:46.747Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 216
File: src/mcp-manager/utils/providers/claude.ts:7-7
Timestamp: 2026-06-11T22:07:46.747Z
Learning: In genesiscz/GenesisTools, `chalk` is the approved, project-wide standard for colored terminal/CLI output. For TypeScript files under `src/`, code reviews should not flag existing `chalk` usage and should not recommend migrating from `chalk` to `picocolors` (or otherwise proposing a replacement) as part of PRs, especially when the PR only touches a subset of files.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-02-24T15:32:44.925Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 54
File: src/github/lib/review-output.ts:18-20
Timestamp: 2026-02-24T15:32:44.925Z
Learning: In TypeScript files, do not require a blank line between the opening brace of a function and the first statement if the first statement is the if statement immediately after the signature. The blank-line rule applies to separating an if from unrelated preceding code within the same block, not to spacing after the function opening brace. Apply this rule to all TS functions across the codebase.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:26:03.611Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/ask/lib/ChatSessionManager.ts:0-0
Timestamp: 2026-03-12T01:26:03.611Z
Learning: Use SafeJSON.parse(text, { strict: true }) for strict RFC 8259 validation in all non-config boundaries (API responses, JSONL, cache, subprocess output). The 3-arg form SafeJSON.parse(text, null, { strict: true }) is invalid and should not be used. Only lenient default (no options) is appropriate for user-authored config files that may contain comments/trailing commas. Apply this guideline across TypeScript files (src/**/*.ts) wherever SafeJSON.parse is used.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:26:18.985Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/claude/lib/history/search.ts:0-0
Timestamp: 2026-03-12T01:26:18.985Z
Learning: When using SafeJSON.parse in TypeScript code, prefer the two-argument form SafeJSON.parse(text, { strict: true }) to enable strict RFC 8259 validation via the native JSON.parse. Do NOT use the three-argument form SafeJSON.parse(text, null, { strict: true }). Apply strict parsing at remote/third-party API boundaries, JSONL parsing points, and subprocess output. Fall back to the lenient/default form only for user-authored config files that may legitimately contain comments or trailing commas. This pattern keeps strict validation where appropriate and preserves leniency for internal/config data.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:26:27.000Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/debugging-master/commands/tail.ts:0-0
Timestamp: 2026-03-12T01:26:27.000Z
Learning: In the genesiscz/GenesisTools repository, prefer using SafeJSON.parse(text, { strict: true }) (2-argument form) at all non-config JSON boundaries such as API responses, JSONL parsers, cache files, and subprocess stdout. Reserve the lenient default (SafeJSON.parse(text) with no options) only for user-authored config files that may legitimately contain comments or trailing commas.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T01:26:24.859Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/azure-devops/commands/history-sync.ts:0-0
Timestamp: 2026-03-12T01:26:24.859Z
Learning: In GenesisTools, ensure SafeJSON.parse is called with exactly two arguments. Use SafeJSON.parse(text, { strict: true }) for strict RFC 8259 validation, or pass a reviver function as the second argument. Do not call SafeJSON.parse(text, null, { strict: true }) since the function signature does not support a three-argument form. Apply this guideline to all TypeScript files that use SafeJSON.parse (e.g., src/utils/json.ts) and other related code.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-17T01:30:56.939Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 107
File: src/utils/macos/tts.ts:130-139
Timestamp: 2026-03-17T01:30:56.939Z
Learning: In genesiscz/GenesisTools, do not suggest converting two-argument functions with an optional second parameter (for example setMute(muted: boolean, app?: string)) to an object-parameter form. The project prefers simple positional parameters for short utility functions, even when an optional argument is present. The object-parameter guideline should only apply when a function has 3 or more parameters.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-22T22:19:49.876Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 119
File: src/indexer/index.ts:41-56
Timestamp: 2026-03-22T22:19:49.876Z
Learning: When using Bun projects, treat `import.meta.dir` as an absolute directory path provided by Bun. If you build paths by concatenating with `import.meta.dir` (e.g., `import.meta.dir + "/file.ts"`), do not require `path.resolve()` as it would be redundant. Only apply `path.resolve()` guidance when the base path is relative (not when the base is already an absolute `import.meta.dir`).

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-12T03:48:42.474Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 104
File: src/darwinkit/index.ts:146-156
Timestamp: 2026-03-12T03:48:42.474Z
Learning: In TypeScript files that use Commander subcommands and exit after showing help, replace code after Command.help() with the pattern: call sub.outputHelp(); (returns void) followed by process.exit(0) or process.exit(1). This avoids TS7027 unreachable-code because Command.help() returns never. Apply this pattern in all src/**/*.ts files where subcommands need to display help before exiting.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-05-05T11:58:33.420Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 163
File: src/indexer/lib/sources/mail-source.dateSent.probe.test.ts:0-0
Timestamp: 2026-05-05T11:58:33.420Z
Learning: This repo uses Biome 2.x. The console lint rule is `noConsole` (located at `lint/suspicious/noConsole`), not `noConsoleLog`. In this codebase, `noConsole` is disabled in `biome.json`, so adding a `// biome-ignore lint/suspicious/noConsole:<...>` suppression comment is a no-op and should be avoided (CI flags it as having no effect). When reviewing, do not suggest adding Biome suppression comments for console usage; if a `console.*` call must remain, leave it without a `biome-ignore` comment.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-05-18T14:02:30.445Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 171
File: src/utils/ui/layouts/AuthLayout.tsx:34-34
Timestamp: 2026-05-18T14:02:30.445Z
Learning: When reviewing a PR, before leaving any comment on a specific file and hunk, verify that the file (and the relevant lines) actually exist in the PR’s current diff. For example, use `git diff --name-only <base>...<head>` (or the PR’s file list) to confirm the file is part of the diff, since pre-rebase/stale hunk references can lead to incorrect or outdated comments.

Applied to files:

  • src/mcp-doctor/lib/duplicates.ts
  • src/mcp-doctor/lib/discovery.ts
  • src/mcp-doctor/lib/probe.ts
  • src/mcp-doctor/lib/types.ts
  • src/mcp-doctor/mcp-doctor.test.ts
  • src/mcp-doctor/lib/report.ts
  • src/mcp-doctor/index.ts
📚 Learning: 2026-03-22T22:19:53.048Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 119
File: src/utils/search/stores/qdrant-vector-store.test.ts:192-206
Timestamp: 2026-03-22T22:19:53.048Z
Learning: In src/**/*.test.ts, it is acceptable to include comments that explain the semantic role or conceptual grouping of numeric/vector test data clusters (e.g., “Cluster 1: 'code' vectors”, “Query close to 'docs' cluster”). Even if variable/identifier names partially suggest intent, these comments should be treated as readable context (describing how clusters/queries relate conceptually) rather than “obvious comments,” and should not be flagged by the no-obvious-comments rule when they genuinely clarify the test data grouping and relationships.

Applied to files:

  • src/mcp-doctor/mcp-doctor.test.ts
📚 Learning: 2026-05-19T18:33:15.211Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 176
File: src/telegram/index.ts:25-28
Timestamp: 2026-05-19T18:33:15.211Z
Learning: When reviewing legacy CLI entrypoint files (e.g., src/**/index.ts) that call `await runTool(program, { tool: "..." })`, allow the `.catch()` handler to keep `console.error(err); process.exit(1)` without requiring a switch to `logger.error` **only** for minimal-touch migrations that were done solely to satisfy the “no-default-import” gate and that add no new feature/behavior code. If the PR introduces any new feature logic or expands the catch-handling beyond that migration, prefer `logger.error` (and follow the repo’s normal logging conventions).

Applied to files:

  • src/mcp-doctor/index.ts
🔇 Additional comments (18)
src/mcp-doctor/lib/types.ts (4)

1-5: LGTM!


7-32: LGTM!


34-38: LGTM!


40-72: LGTM!

src/mcp-doctor/lib/discovery.ts (1)

1-109: LGTM!

src/mcp-doctor/mcp-doctor.test.ts (1)

1-188: LGTM!

src/mcp-doctor/lib/probe.ts (1)

70-101: LGTM!

src/mcp-doctor/lib/duplicates.ts (1)

1-31: LGTM!

src/mcp-doctor/lib/report.ts (1)

1-125: LGTM!

src/mcp-doctor/index.ts (9)

1-8: LGTM!


10-16: LGTM!


18-25: LGTM!


27-39: LGTM!


41-45: LGTM!


53-55: LGTM!


57-73: LGTM!


99-118: LGTM!


120-120: LGTM!

Comment thread src/mcp-doctor/index.ts
Comment thread src/mcp-doctor/index.ts
Comment on lines +85 to +88
const spinner = out.spinner();
spinner.start(`Probing ${servers.length} servers…`);
const results = await probeAll(servers, opts);
spinner.stop("Probe complete");

@coderabbitai coderabbitai Bot Jun 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Check isInteractive() before using spinner.

Per coding guidelines, always check isInteractive() from @app/utils/cli before showing prompts or spinners. In non-interactive environments (e.g., CI, piped output), the spinner may cause issues or produce unwanted output.

🔧 Proposed fix to guard spinner with isInteractive check
+    const interactive = isInteractive();
-    const spinner = out.spinner();
-    spinner.start(`Probing ${servers.length} servers…`);
+    const spinner = interactive ? out.spinner() : null;
+    spinner?.start(`Probing ${servers.length} servers…`);
     const results = await probeAll(servers, opts);
-    spinner.stop("Probe complete");
+    spinner?.stop("Probe complete");

Don't forget to import isInteractive:

-import { runTool } from "`@app/utils/cli`";
+import { isInteractive, runTool } from "`@app/utils/cli`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp-doctor/index.ts` around lines 85 - 88, Import isInteractive from
`@app/utils/cli` at the top of the file, then wrap the spinner initialization and
usage (the spinner.start() and spinner.stop() calls) in a conditional check for
isInteractive(). The probeAll() function call should still execute regardless of
interactivity, but the spinner visual feedback should only be shown in
interactive environments to prevent unwanted output in CI or piped environments.

Source: Coding guidelines

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@coderabbitai Won't fix - this is already handled at the root. out.spinner() in src/logger/out.ts is defined as isQuietOutput() ? createQuietSpinner() : p.spinner(), and isQuietOutput() in src/utils/cli/output-mode.ts returns true whenever process.stdout.isTTY is false (CI, pipes). So in non-interactive output the spinner is already the no-op quiet spinner that emits no clack frames. Wrapping with isInteractive() at this call site would duplicate logic the out layer centralizes, and it would gate on stdin TTY where the spinner correctly gates on stdout TTY (the actual output channel).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@genesiscz have exceeded the limit for the number of chat messages per hour. Please wait 5 minutes and 19 seconds before sending another message.

Comment on lines +22 to +28
return new StdioClientTransport({
command: stdio.command,
args: stdio.args,
env: { ...process.env, ...stdio.env } as Record<string, string>,
cwd: stdio.cwd,
stderr: "ignore",
});

@coderabbitai coderabbitai Bot Jun 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Type assertion on merged environment could hide undefined values.

Line 25 asserts { ...process.env, ...stdio.env } as Record<string, string>, but process.env has type NodeJS.ProcessEnv where values can be string | undefined. If process.env contains undefined values, this assertion could be incorrect.

However, this is a common pattern and the MCP SDK's StdioClientTransport likely handles it gracefully. If issues arise, consider filtering undefined values explicitly.

🛡️ Optional defensive fix
         return new StdioClientTransport({
             command: stdio.command,
             args: stdio.args,
-            env: { ...process.env, ...stdio.env } as Record<string, string>,
+            env: Object.fromEntries(
+                Object.entries({ ...process.env, ...stdio.env })
+                    .filter(([, v]) => v !== undefined)
+            ) as Record<string, string>,
             cwd: stdio.cwd,
             stderr: "ignore",
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return new StdioClientTransport({
command: stdio.command,
args: stdio.args,
env: { ...process.env, ...stdio.env } as Record<string, string>,
cwd: stdio.cwd,
stderr: "ignore",
});
return new StdioClientTransport({
command: stdio.command,
args: stdio.args,
env: Object.fromEntries(
Object.entries({ ...process.env, ...stdio.env })
.filter(([, v]) => v !== undefined)
) as Record<string, string>,
cwd: stdio.cwd,
stderr: "ignore",
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp-doctor/lib/probe.ts` around lines 22 - 28, The type assertion `as
Record<string, string>` on the merged environment object in the
StdioClientTransport creation is unsafe because process.env values can be string
or undefined. Remove the type assertion and either let TypeScript infer the
proper type, or defensively filter out undefined values from the merged
environment object (using Object.entries() with a filter condition) before
passing it to ensure all values are strings and the type matches what
StdioClientTransport expects.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@coderabbitai Fixed in aa69e6b - the merged env is now built into an explicit typed accumulator that copies only entries whose value is not undefined, so the result is genuinely Record of string to string and the unsound cast is gone entirely (no cast at all now). process.env values are string-or-undefined and StdioClientTransport expects string-only env, so filtering is correct.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@genesiscz have exceeded the limit for the number of chat messages per hour. Please wait 5 minutes and 30 seconds before sending another message.

genesiscz added a commit that referenced this pull request Jun 14, 2026
- probe: move buildTransport inside try so a bad URL fails one server, not the batch
- discovery: validate def.url with new URL(); mark malformed remotes invalid
- discovery: guard mcpServers against non-object/array config values
- report: make timeout status reachable; surface timeout count in header
- report: fold invalid servers into error count so summary totals reconcile
- index: validate --timeout/--slow as positive finite numbers
@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- probe: move buildTransport inside try so a bad URL fails one server, not the batch
- discovery: validate def.url with new URL(); mark malformed remotes invalid
- discovery: guard mcpServers against non-object/array config values
- report: make timeout status reachable; surface timeout count in header
- report: fold invalid servers into error count so summary totals reconcile
- index: validate --timeout/--slow as positive finite numbers
@genesiscz genesiscz force-pushed the feat/pro-mcp-doctor branch from 82b3ca5 to 48c2ce1 Compare June 14, 2026 15:24
@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@genesiscz

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- probe.ts: filter undefined values out of merged process.env before passing to StdioClientTransport instead of an unsound 'as Record<string, string>' cast that assumed no undefined env values
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