Skip to content

Commit 37dde2a

Browse files
Merge pull request #147 from Altinity/fix-cimd-tolerate-unknown-grant-types
cimd: tolerate unknown grant_types in client metadata (fix claude.ai outage)
2 parents c1dc109 + 99f0e05 commit 37dde2a

2 files changed

Lines changed: 18 additions & 12 deletions

File tree

cmd/altinity-mcp/cimd.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,17 +483,20 @@ func parseCIMDMetadata(clientIDURL string, body []byte) (*statelessRegisteredCli
483483
switch gt {
484484
case "authorization_code":
485485
hasAuthCode = true
486-
case "refresh_token":
487-
// Tolerated in metadata, deliberately NOT honored in v1: a client
488-
// publishing ["authorization_code","refresh_token"] (which
489-
// claude.ai does today) silently gets no refresh capability —
490-
// .well-known/oauth-authorization-server only advertises
491-
// authorization_code and /token returns unsupported_grant_type
492-
// for refresh. If/when refresh ships, do NOT treat the CIMD
493-
// grant_types array as authoritative for what we issue — the AS
494-
// metadata is the source of truth.
495486
default:
496-
return nil, fmt.Errorf("%w: unsupported grant_type %q", errCIMDInvalidMetadata, gt)
487+
// Any other grant_type (refresh_token, and as of 2026-06 claude.ai
488+
// also publishes urn:ietf:params:oauth:grant-type:jwt-bearer) is
489+
// TOLERATED but deliberately NOT honored in v1. The CIMD grant_types
490+
// array is advertising what the *client* can do, not what we issue:
491+
// .well-known/oauth-authorization-server only lists authorization_code
492+
// and /token returns unsupported_grant_type for everything else, so a
493+
// client gets exactly the capabilities the AS metadata declares
494+
// regardless of what it lists here. Hard-rejecting unknown entries
495+
// just breaks resolution whenever a client adds a new grant_type to
496+
// its published doc (this is what took claude.ai connectors down when
497+
// jwt-bearer was added). Requiring authorization_code to be present is
498+
// the only real constraint. If refresh ever ships, the AS metadata —
499+
// not this array — remains the source of truth for what we issue.
497500
}
498501
}
499502
if !hasAuthCode {

cmd/altinity-mcp/cimd_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func TestParseCIMDMetadata_OK(t *testing.T) {
160160
"client_name": "Claude",
161161
"client_uri": "https://claude.ai",
162162
"redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
163-
"grant_types": ["authorization_code","refresh_token"],
163+
"grant_types": ["authorization_code","refresh_token","urn:ietf:params:oauth:grant-type:jwt-bearer"],
164164
"response_types": ["code"],
165165
"token_endpoint_auth_method": "none"
166166
}`)
@@ -183,7 +183,10 @@ func TestParseCIMDMetadata_Reject(t *testing.T) {
183183
"empty_redirect_uris": `{"client_id":"` + u + `","client_name":"X","redirect_uris":[],"token_endpoint_auth_method":"none"}`,
184184
"duplicate_redirect_uris": `{"client_id":"` + u + `","client_name":"X","redirect_uris":["https://x/cb","https://x/cb"],"token_endpoint_auth_method":"none"}`,
185185
"http_redirect_uri": `{"client_id":"` + u + `","client_name":"X","redirect_uris":["http://x/cb"],"token_endpoint_auth_method":"none"}`,
186-
"unsupported_grant": `{"client_id":"` + u + `","client_name":"X","redirect_uris":["https://x/cb"],"token_endpoint_auth_method":"none","grant_types":["password"]}`,
186+
// Unknown grant_types are now TOLERATED (claude.ai publishes jwt-bearer);
187+
// this case still rejects, but because authorization_code is absent — not
188+
// because "password" itself is unsupported. See parseCIMDMetadata.
189+
"grant_types_without_authcode": `{"client_id":"` + u + `","client_name":"X","redirect_uris":["https://x/cb"],"token_endpoint_auth_method":"none","grant_types":["password"]}`,
187190
"unsupported_response": `{"client_id":"` + u + `","client_name":"X","redirect_uris":["https://x/cb"],"token_endpoint_auth_method":"none","response_types":["token"]}`,
188191
"empty_name": `{"client_id":"` + u + `","client_name":"","redirect_uris":["https://x/cb"],"token_endpoint_auth_method":"none"}`,
189192
"oversize_name": `{"client_id":"` + u + `","client_name":"` + strings.Repeat("a", cimdMaxClientNameLength+1) + `","redirect_uris":["https://x/cb"],"token_endpoint_auth_method":"none"}`,

0 commit comments

Comments
 (0)