fix(desktop): omit a null iss from the oauth.callback relay; hoist the loopback parse import
The Electron listener now always emits iss (null when the server sent none) and McpOauthCallbackParams is extra="forbid", so a new Desktop against a backend without this change would fail every remote MCP OAuth login with a 4000 - including providers that never send iss. Send the key only when set. Also drop the deliver_callback_flow test the RPC test subsumes.
This commit is contained in:
@@ -135,7 +135,9 @@ export async function completeMcpDesktopOAuth({
|
||||
throw new Error(callback.error || 'OAuth callback did not include state')
|
||||
}
|
||||
|
||||
await request('callback', { session_id: flowId, ...callback })
|
||||
// Omit a null iss: a backend that predates the RFC 9207 relay rejects unknown params (4000).
|
||||
const { iss, ...rest } = callback
|
||||
await request('callback', { session_id: flowId, ...rest, ...(iss ? { iss } : {}) })
|
||||
})
|
||||
.catch(error => {
|
||||
relayError = error
|
||||
|
||||
@@ -189,18 +189,6 @@ def test_deliver_callback_accepts_matching_state():
|
||||
assert flow._callback == ("abc", "s3cr3tstate", None)
|
||||
|
||||
|
||||
def test_deliver_callback_forwards_iss():
|
||||
"""The client-redirect relay carries RFC 9207 ``iss`` into the flow. Desktop drives this path
|
||||
against a remote backend, and mcp 2.x rejects a response missing ``iss`` when the authorization
|
||||
server advertised ``authorization_response_iss_parameter_supported``."""
|
||||
flow = _make_session()
|
||||
out = deliver_callback_flow(
|
||||
"sess-relay-1", "hosp", code="abc", state="s3cr3tstate", iss="https://as.example.com"
|
||||
)
|
||||
assert out["ok"] is True
|
||||
assert flow._callback == ("abc", "s3cr3tstate", "https://as.example.com")
|
||||
|
||||
|
||||
def test_oauth_callback_rpc_relays_iss():
|
||||
"""The gateway ``mcp.servers.oauth.callback`` RPC accepts ``iss`` under the extra=forbid contract
|
||||
and forwards it to the flow; the desktop renderer always sends the key (possibly null)."""
|
||||
|
||||
@@ -49,6 +49,8 @@ def _validate_client_redirect_uri(uri: str) -> str:
|
||||
def _start_loopback_listener(flow) -> "http.server.HTTPServer":
|
||||
"""Bind a loopback callback listener feeding ``flow.deliver_callback``; returns the
|
||||
HTTPServer already serving on a daemon thread (caller pins ``flow.redirect_uri`` from it)."""
|
||||
from tools.mcp_oauth import _parse_redirect_query
|
||||
|
||||
class _Handler(http.server.BaseHTTPRequestHandler):
|
||||
def do_GET(self): # noqa: N802 — stdlib naming
|
||||
parsed = urlparse(self.path)
|
||||
@@ -56,8 +58,6 @@ def _start_loopback_listener(flow) -> "http.server.HTTPServer":
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
return
|
||||
from tools.mcp_oauth import _parse_redirect_query
|
||||
|
||||
body = b"<h1>Authorization received</h1><p>You can close this tab and return to Hermes.</p>"
|
||||
status = 200
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user