fix(mcp): send Kiro client-identity headers on web_search MCP call#213
Open
severity1 wants to merge 1 commit into
Open
fix(mcp): send Kiro client-identity headers on web_search MCP call#213severity1 wants to merge 1 commit into
severity1 wants to merge 1 commit into
Conversation
5b092c8 to
9f28b7a
Compare
9f28b7a to
fcfd884
Compare
web_search via runtime.kiro.dev/mcp fails with 403 "User is not authorized to make this call" for IAM Identity Center (AWS SSO OIDC / kiro-cli) accounts, even when MCP is enabled on the profile. call_kiro_mcp_api sent only Authorization, x-amzn-codewhisperer-optout, and Content-Type. The completion path (get_kiro_headers in utils.py) sends a full Kiro client-identity set: User-Agent with the KiroIDE-<version>-<fingerprint> signature, x-amz-user-agent, x-amzn-kiro-agent-mode, and amz-sdk-*. The /mcp endpoint gates authorization on these signals, so a bare Authorization header is rejected with 403 even when the account is entitled. Build the MCP headers from the canonical get_kiro_headers (single source of truth, shared with the completion path) and override the three fields that differ for /mcp: Content-Type application/json (JSON-RPC, not x-amz-json), drop x-amz-target (completion-operation-specific), and set optout false. NOTE: a complete web_search fix also requires profileArn in the MCP request body (else 400, before the 403 this addresses). That is handled by separate contributions (jwadow#180/jwadow#189/jwadow#175); this PR is scoped to only the novel client-identity-headers fix and stacks on top of them. Add a regression test asserting the MCP request sends the Kiro client-identity headers.
fcfd884 to
adc1cb2
Compare
|
Hey, I ran into the same issue and combined this PR's header fix with the profileArn fix from #175/#180. One thing I found that neither PR addresses: if profile_arn = auth_manager.profile_arn or PROFILE_ARN or ""
if not profile_arn:
token = await auth_manager.force_refresh()
profile_arn = auth_manager.profile_arn or PROFILE_ARN or ""Without this, accounts that haven't done a token refresh since startup will still hit the 400 even with profileArn code in place. Might be worth adding to this PR or #175 since they stack together anyway. |
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Claude Code's native
web_searchserver-side tool, routed through the gateway toruntime.kiro.dev/mcp, fails with 403 for IAM Identity Center (AWS SSO OIDC / kiro-cli) accounts, even when MCP is enabled on the profile:{"message":"User is not authorized to make this call.","reason":null}This 403 is distinct from the
profileArn400 issue (#173, addressed by #180/#189/#175). It surfaces only onceprofileArnis present: the request is then authenticated, but the endpoint still declines it.Root Cause
call_kiro_mcp_api()inmcp_tools.pysent only three headers (Authorization,x-amzn-codewhisperer-optout,Content-Type). The completion path (/generateAssistantResponse, viaget_kiro_headersinutils.py) sends a full Kiro client-identity set:User-Agentwith theKiroIDE-<version>-<fingerprint>signature,x-amz-user-agent,x-amzn-kiro-agent-mode, and theamz-sdk-*pair.The
/mcpendpoint gates authorization on these client-identity signals. A bareAuthorizationheader is rejected with 403 even when the account is entitled. Completions work because they send the full identity; MCP did not.Fix
Build the MCP headers from the canonical
get_kiro_headers(single source of truth, shared with the completion path) and override only the three fields that differ for/mcp:Content-Type: application/json—/mcpis JSON-RPC, not thex-amz-json-1.0completion APIx-amz-target— completion-operation-specific, meaningless to/mcpx-amzn-codewhisperer-optout: false— preserves the original MCP valueReusing
get_kiro_headers(rather than duplicating the literals) means futureKiroIDEversion bumps flow to the MCP call automatically instead of silently drifting.Scope — depends on profileArn contributions
This PR is deliberately surgical: it contains only the novel client-identity-headers fix.
A complete
web_searchfix also requiresprofileArnin the MCP request body — without it the endpoint returns 400, before the 403 this PR addresses. ThatprofileArnwork is not included here; it is contributed separately by #180 / #189 / #175 (and tracked in #173). This change stacks on top of those: once aprofileArnPR merges, this header fix carries the call the rest of the way past the 403.Credit to those contributors for the
profileArnhalf of the puzzle.Testing
web_searchtool returns live results through the gateway on an enterprise SSO OIDC (kiro-cli) account, where it previously 403'd (withprofileArnapplied locally).tests/unit/test_mcp_tools.pypasses (22 tests).The header change is additive (sends more identity signal, matching the completion path), so it should not regress auth types that already worked.