When an MCP tool schema declares a parameter with type 'object' (e.g.
Atlassian's editJiraIssue fields parameter), the generated CLI previously
passed the value as a raw string, causing MCP validation errors.
Root cause: inferType() didn't recognize 'object' as a valid type, so it
returned 'unknown'. optionParser() had no case for 'object', so no
JSON.parse was generated for the Commander option.
Changes:
- Add 'object' to GeneratedOption type union in tools.ts
- Add 'object' to resolveType whitelist in inferType()
- Add 'case object' returning JSON.parse in optionParser()
Fixes#113
In Bun compiled binaries, process.argv[1] is a virtual /$bunfs/...
path that Bun auto-injects into every spawned child process. The
daemon launcher was including this path explicitly in the spawn args,
causing it to appear twice in the child's argv. The child then parsed
the duplicate path as the CLI command instead of "daemon", silently
failing to start.
Detect the /$bunfs/ prefix and omit the entry from spawn args, letting
Bun handle it automatically.
Track OAuth flow failures separately from post-auth reconnect
failures so Streamable HTTP can still fall back to legacy SSE
on real 404/405 transport mismatches without masking terminal
provider errors.
Also recreate transports after finishAuth and add regression
coverage for generic 401 promotions, OAuth flow failures, and
post-auth retry paths.
When mcporter imports server definitions from external clients that
include static Authorization headers, these override the OAuth access
token in the SDK, causing 401 retry storms.
Fixes#121
MCP SDK's StreamableHTTPError/SseError store the HTTP status code in
error.code, but the message text may not contain the numeric status.
analyzeConnectionError now reads error.code (100-599) before falling
back to message-text parsing, so OAuth promotion triggers correctly
for 401 responses on Streamable HTTP transport.
Use the existing parseJsonBuffer helper (which leverages jsonc-parser)
instead of JSON.parse() when reading config files. This enables:
- Single-line comments (//)
- Multi-line comments (/* */)
- Trailing commas
The jsonc-parser dependency was already present but wasn't being used
for the main config file parsing.
Instead of hardcoding scope 'mcp:tools' during dynamic client
registration, fetch /.well-known/oauth-protected-resource from the
server to discover its supported scopes. This fixes InvalidScopeError
when connecting to servers like Todoist that only accept their own
scopes (e.g. 'data:read_write').
Also includes the fix from #38: remove the ad-hoc source restriction
in maybeEnableOAuth() so config-file servers can be promoted to OAuth.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP 405 (Method Not Allowed) was included in AUTH_STATUSES, causing it
to be treated as an authentication error. This leads to premature OAuth
session cleanup when StreamableHTTP returns 405, leaving the SSE
fallback without credentials. Remove 405 from AUTH_STATUSES so transport
errors are classified correctly.
Fixes#47
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ImageContent interface and images() method to CallResult
- Extract type: 'image' content blocks from MCP responses
- Save images to files in auto/image output modes
- Include images in JSON output when present
- Print images alongside text/markdown content
Fixes issue where MCP servers returning image content blocks
(e.g., photos_get_images) had their image data silently dropped.
Values like phone numbers, PINs, or codes with leading zeros (e.g. 000123)
are auto-coerced to numbers by default. The --raw-strings flag (or --no-coerce
alias) preserves them as strings.
Note: Cannot use --raw as the flag name because it conflicts with the
existing --raw output format shortcut in output-format.ts.
Fixes: numeric strings being silently converted to numbers
Ensure waitForAuthorizationCode uses the same deferred created by redirectToAuthorization instead of creating a new one. If waitForAuthorizationCode is called before redirectToAuthorization has been invoked, it now waits for the redirect to be initiated before proceeding. This fixes the race condition where the OAuth callback could resolve a different promise than what the runtime was waiting on, causing authentication to fail with a timeout.
Fixes#36
Previously json() in createCallResult returned early on the first
parseable JSON entry. When an MCP server returned multiple results
in the content array, only the first item was ever surfaced.
Now all parseable entries are collected. A single item still returns
as a single object (backward compatible); multiple items return as
an array.
Also increased inspect depth in printRaw from 2 to null to prevent
truncation of deeply nested list results.
Address review feedback: wrap the redirect URI mismatch check in
try/catch so that if readClientInfo() or clear() throws (malformed
cache JSON, filesystem permissions), the already-bound HTTP callback
server is closed before rethrowing. Prevents the process from hanging
with an open listener in failure paths.
1. Remove hardcoded scope='mcp:tools' from client metadata.
Providers like Granola reject this scope at the authorize endpoint
(invalid_scope). Let the MCP SDK derive scope from server metadata
instead, falling back to the auth server's scopes_supported.
2. Swallow xdg-open ENOENT on headless Linux servers.
On VPS/CI environments without a desktop, spawning xdg-open throws
an unhandled error event that crashes the process before the OAuth
callback server can receive the redirect.
3. Clear stale client registration when dynamic callback port changes.
With dynamic ports (the default), each run picks a different port.
If a previous client registration is cached with a different
redirect_uri, the auth server rejects subsequent requests with
invalid_redirect_uri. Now detects the mismatch and re-registers.
Fixes#67