Improve MCP safeStringify, OIDC error messages, and catalog model reference config

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
benjdlambert
2026-05-19 18:45:06 +02:00
parent ca8951ae87
commit 3f5e7ec2b4
10 changed files with 98 additions and 63 deletions
@@ -1197,7 +1197,7 @@ describe('OidcService', () => {
redirectUri: 'http://unauthorized.com/callback',
responseType: 'code',
}),
).rejects.toThrow('Redirect URI not registered');
).rejects.toThrow('not registered in client metadata');
});
it('should throw error when redirect_uri does not match allowedRedirectUriPatterns', async () => {
@@ -1284,7 +1284,7 @@ describe('OidcService', () => {
responseType: 'code',
...pkceParams,
}),
).rejects.toThrow('Redirect URI not registered');
).rejects.toThrow('not registered in client metadata');
});
it('should accept IPv6 loopback redirect_uri with a different port per RFC 8252', async () => {
@@ -1389,7 +1389,7 @@ describe('OidcService', () => {
responseType: 'code',
...pkceParams,
}),
).rejects.toThrow('Redirect URI not registered');
).rejects.toThrow('not registered in client metadata');
});
it('should reject redirect_uri not exactly matching CIMD metadata', async () => {
@@ -1413,7 +1413,7 @@ describe('OidcService', () => {
responseType: 'code',
...pkceParams,
}),
).rejects.toThrow('Redirect URI not registered');
).rejects.toThrow('not registered in client metadata');
});
it('should require PKCE for CIMD clients', async () => {
@@ -41,7 +41,7 @@ function validateRedirectUri(
const normalized = `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
if (!allowedPatterns.some(pattern => matcher.isMatch(normalized, pattern))) {
throw new InputError('Invalid redirect_uri');
throw new InputError(`Invalid redirect_uri '${normalized}'`);
}
}
@@ -221,7 +221,11 @@ export class OidcService {
const allowedRedirectUriPatterns = this.config.getOptionalStringArray(
'auth.experimentalDynamicClientRegistration.allowedRedirectUriPatterns',
) ?? ['cursor://*', ...LOOPBACK_REDIRECT_PATTERNS];
) ?? [
'cursor://*',
'https://www.cursor.com/*',
...LOOPBACK_REDIRECT_PATTERNS,
];
for (const redirectUri of opts.redirectUris ?? []) {
validateRedirectUri(redirectUri, allowedRedirectUriPatterns);
@@ -357,7 +361,7 @@ export class OidcService {
matcher.isMatch(opts.clientId, pattern),
)
) {
throw new InputError('Invalid client_id');
throw new InputError(`Invalid client_id '${opts.clientId}'`);
}
const cimdClient = await fetchCimdMetadata({
@@ -369,7 +373,9 @@ export class OidcService {
validateRedirectUri(opts.redirectUri, cimd.allowedRedirectUriPatterns);
if (!matchesRedirectUri(opts.redirectUri, cimdClient.redirectUris)) {
throw new InputError('Redirect URI not registered');
throw new InputError(
`Invalid redirect_uri '${opts.redirectUri}', not registered in client metadata`,
);
}
}
@@ -390,7 +396,7 @@ export class OidcService {
}
if (opts.redirectUri && !client.redirectUris.includes(opts.redirectUri)) {
throw new InputError('Invalid redirect_uri');
throw new InputError(`Invalid redirect_uri '${opts.redirectUri}'`);
}
return {