You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
reasonix mcp inspect <spec> connects to one MCP server and prints its capabilities + tools / resources / prompts. When the connection fails, the user sees a bare error string with no recovery hint:
spawn ENOENT reads as gibberish to anyone who hasn't debugged Node child processes before. The fix is the same shape as #16 (web tool errors): every error string should end with a short " — try: …" tail telling the user what action would unstick them.
This is the inspect-side parallel to #16; the patterns line up so the two PRs can borrow phrasing.
Current behaviour
CLI registration: src/cli/index.ts:404
The try/catch at src/cli/index.ts:411-416 re-emits the raw err.message:
parseMcpSpec throws on empty / malformed input (src/mcp/spec.ts)
StdioTransport throws spawn <cmd> ENOENT when the command doesn't exist
SseTransport / StreamableHttpTransport throw on connection-refused, DNS, TLS
client.initialize() throws on handshake timeout or protocol-version mismatch
inspectMcpServer throws on internal protocol errors
Expected behaviour
Wrap the catch in a small classifier so each common cause gets a tailored hint. Examples:
spawn <cmd> ENOENT → command "<cmd>" not found — try: install the package first (e.g. \npx --version`), or check the spec's command spelling`
ECONNREFUSED → could not connect to <url> — try: confirm the server is running and the port matches
handshake timeout → MCP handshake timed out — try: confirm the target speaks MCP (some servers only emit JSON-RPC after stdin is closed); pass --json for raw output if you want to debug further
empty / malformed spec from parseMcpSpec → leave the existing message but suffix with — try: \name=command args` or an http(s):// URL`
src/cli/index.ts:411-416 — branch the catch on error code / message shape
OR (cleaner) extract a describeMcpInspectFailure(err): string helper into src/cli/commands/mcp-inspect.ts and call it from the catch
tests/mcp-inspect.test.ts — add 3-4 tests for the classifier (don't test against real subprocess; build fake Error objects with .code = "ENOENT" etc. and assert the formatted output)
Acceptance criteria
spawn ENOENT, ECONNREFUSED, and handshake-timeout errors all surface a " — try: …" tail with concrete next steps
parseMcpSpec errors keep their existing message but gain a suffix pointing at valid spec forms
Unknown errors fall through to the current mcp inspect failed: <message> — no regression
Exit code 1 preserved for all failure cases
No new dependencies
npm run verify passes
Hints
Don't introduce an McpInspectError class. A switch on (err as NodeJS.ErrnoException).code covers ENOENT / ECONNREFUSED cleanly.
Handshake-timeout: search src/mcp/client.ts for the timeout error message it throws; classify by message-substring match.
Background
reasonix mcp inspect <spec>connects to one MCP server and prints its capabilities + tools / resources / prompts. When the connection fails, the user sees a bare error string with no recovery hint:spawn ENOENTreads as gibberish to anyone who hasn't debugged Node child processes before. The fix is the same shape as #16 (web tool errors): every error string should end with a short " — try: …" tail telling the user what action would unstick them.This is the inspect-side parallel to #16; the patterns line up so the two PRs can borrow phrasing.
Current behaviour
src/cli/index.ts:404try/catchatsrc/cli/index.ts:411-416re-emits the rawerr.message:parseMcpSpecthrows on empty / malformed input (src/mcp/spec.ts)StdioTransportthrowsspawn <cmd> ENOENTwhen the command doesn't existSseTransport/StreamableHttpTransportthrow on connection-refused, DNS, TLSclient.initialize()throws on handshake timeout or protocol-version mismatchinspectMcpServerthrows on internal protocol errorsExpected behaviour
Wrap the catch in a small classifier so each common cause gets a tailored hint. Examples:
spawn <cmd> ENOENT→command "<cmd>" not found — try: install the package first (e.g. \npx --version`), or check the spec's command spelling`ECONNREFUSED→could not connect to <url> — try: confirm the server is running and the port matchesMCP handshake timed out — try: confirm the target speaks MCP (some servers only emit JSON-RPC after stdin is closed); pass --json for raw output if you want to debug furtherparseMcpSpec→ leave the existing message but suffix with— try: \name=command args` or an http(s):// URL`mcp inspect failed: <message>)Files to touch
src/cli/index.ts:411-416— branch the catch on error code / message shapedescribeMcpInspectFailure(err): stringhelper intosrc/cli/commands/mcp-inspect.tsand call it from the catchtests/mcp-inspect.test.ts— add 3-4 tests for the classifier (don't test against real subprocess; build fakeErrorobjects with.code = "ENOENT"etc. and assert the formatted output)Acceptance criteria
spawn ENOENT,ECONNREFUSED, and handshake-timeout errors all surface a " — try: …" tail with concrete next stepsparseMcpSpecerrors keep their existing message but gain a suffix pointing at valid spec formsmcp inspect failed: <message>— no regressionnpm run verifypassesHints
McpInspectErrorclass. A switch on(err as NodeJS.ErrnoException).codecovers ENOENT / ECONNREFUSED cleanly.src/mcp/client.tsfor the timeout error message it throws; classify by message-substring match.web_search/web_fetcherrors actionable #16 once it lands for the phrasing convention — keep them consistent.Errorobjects in tests, never spawn real processes.Out of scope
--json) — only the human-readable error tailDifficulty
2-3 hours.