fix(mcp): surface a short launch URL and log Windows opener failures for OAuth
Two independent defects broke /mcp reauth against S256-only providers on
Windows boxes whose PATH no longer references System32:
1. openPath spawned bare rundll32 and swallowed the
`Executable not found in $PATH` throw with a bare `catch {}`, so the MCP
controller's outer try/catch was dead and the transcript unconditionally
claimed "Opening browser automatically...".
2. TUI#prepareLine silently truncates any composed row wider than the
viewport. MCPAuthorizationLinkPrompt rendered `Copy URL: <full URL>` as a
single ~271-column line whose trailing parameter is
code_challenge_method=S256. On the reporter's 270-col terminal the cut
landed inside that parameter, dropping the method while keeping
code_challenge — which RFC 7636 §4.3 treats as plain PKCE, which Linear
correctly rejects with "The plain PKCE method is not allowed. Use S256
instead."
OAuthCallbackFlow now hosts a `GET /launch` route on the same loopback
callback server it already runs; the route 302-redirects to the pending
authorization URL and is advertised as `OAuthAuthInfo.launchUrl` — a
~30-char copy target no viewport can meaningfully truncate. The MCP OAuth
fallback, /login, setup wizard, auth-broker CLI, and login-dialog all
prefer the launch URL for the visible copy target, keep the full URL in
the OSC 8 hyperlink for click-through, and the MCP flow additionally
stages the copy target on the clipboard via OSC 52 (same pattern the
setup wizard uses).
openPath now resolves rundll32.exe through %SystemRoot%\System32 (with a
C:\Windows fallback when SystemRoot is unset) and logs both synchronous
spawn throws and non-zero exits via the shared logger, so silent
misconfigurations show up in ~/.omp/logs/omp.*.log. The dead try/catch
around openPath in the MCP controller is removed.
Fixes #4418
This commit is contained in:
@@ -1213,6 +1213,7 @@ export async function runRpcMode(
|
||||
id: Snowflake.next() as string,
|
||||
method: "open_url",
|
||||
url: info.url,
|
||||
launchUrl: info.launchUrl,
|
||||
instructions: info.instructions,
|
||||
} as RpcExtensionUIRequest);
|
||||
},
|
||||
|
||||
@@ -370,7 +370,19 @@ export type RpcExtensionUIRequest =
|
||||
}
|
||||
| { type: "extension_ui_request"; id: string; method: "setTitle"; title: string }
|
||||
| { type: "extension_ui_request"; id: string; method: "set_editor_text"; text: string }
|
||||
| { type: "extension_ui_request"; id: string; method: "open_url"; url: string; instructions?: string };
|
||||
| {
|
||||
type: "extension_ui_request";
|
||||
id: string;
|
||||
method: "open_url";
|
||||
url: string;
|
||||
/**
|
||||
* Short loopback URL that 302-redirects to {@link url}. When present,
|
||||
* hosts SHOULD surface it as the copy target so terminal viewport
|
||||
* truncation cannot corrupt OAuth query parameters on the full URL.
|
||||
*/
|
||||
launchUrl?: string;
|
||||
instructions?: string;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Host Tool Frames (bidirectional)
|
||||
|
||||
Reference in New Issue
Block a user