SEP-837: application_type check in DCR registration (#284)
* Add SEP-837 application_type check to DCR registration SEP-837 requires MCP clients to specify an appropriate application_type during Dynamic Client Registration so OIDC authorization servers can apply the correct redirect-URI constraints. - Traceability yaml: 1 check (presence + valid value), 4 excluded (class-specific SHOULDs unobservable; UI/robustness) - Check added in the shared createAuthServer DCR handler so it fires in every auth scenario that performs DCR (no new scenario) - withOAuthRetry now sets application_type: native (passing example; the conformance example clients are CLI tools) - New auth-test-no-application-type negative client + vitest case * Widen ConformanceOAuthProvider metadata type for application_type Fixes CI typecheck (TS2353 at withOAuthRetry.ts:76): the SDK's OAuthClientMetadataSchema doesn't include application_type yet. registerClient() spreads clientMetadata verbatim into the /register POST body, so a local type intersection is sufficient to get the field on the wire without an SDK release. * Set application_type in runAuthMigrationClient The SEP-2352 authorization-server-migration handler constructs its own ConformanceOAuthProvider (not via withOAuthRetry), so it was missing application_type after rebasing onto main. The scenario does DCR twice (old AS, new AS) and the SEP-837 check fires on each. --------- Co-authored-by: Paul Carleton <paulc@anthropic.com>
This commit is contained in:
parent
e6fffa2b30
commit
12252466e6
3 changed files with 103 additions and 4 deletions
|
|
@ -386,6 +386,25 @@ export function createAuthServer(
|
|||
}
|
||||
});
|
||||
|
||||
// SEP-837: clients MUST specify an appropriate application_type during DCR.
|
||||
// The harness can't know the client's real class (native vs web), so this
|
||||
// checks presence + that the value is one of the two OIDC-defined values.
|
||||
const appType = req.body.application_type;
|
||||
const validAppType = appType === 'native' || appType === 'web';
|
||||
checks.push({
|
||||
id: 'sep-837-application-type-present',
|
||||
name: 'DCR application_type specified',
|
||||
description: validAppType
|
||||
? `Client specified application_type "${appType}" during Dynamic Client Registration`
|
||||
: appType === undefined
|
||||
? 'Client MUST specify an appropriate application_type during Dynamic Client Registration (SEP-837); field was omitted'
|
||||
: `Client MUST specify an appropriate application_type during Dynamic Client Registration (SEP-837); got "${appType}", expected "native" or "web"`,
|
||||
status: validAppType ? 'SUCCESS' : 'FAILURE',
|
||||
timestamp: new Date().toISOString(),
|
||||
specReferences: [SpecReferences.MCP_DCR],
|
||||
details: { application_type: appType ?? '(omitted)' }
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
client_id: clientId,
|
||||
...(clientSecret && { client_secret: clientSecret }),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { runClient as ignore403Client } from '../../../../examples/clients/types
|
|||
import { runClient as noRetryLimitClient } from '../../../../examples/clients/typescript/auth-test-no-retry-limit';
|
||||
import { runClient as noPkceClient } from '../../../../examples/clients/typescript/auth-test-no-pkce';
|
||||
import { runClient as reuseCredsClient } from '../../../../examples/clients/typescript/auth-test-reuse-credentials';
|
||||
import { runClient as noAppTypeClient } from '../../../../examples/clients/typescript/auth-test-no-application-type';
|
||||
import { getHandler } from '../../../../examples/clients/typescript/everything-client';
|
||||
import { setLogLevel } from '../../../../examples/clients/typescript/helpers/logger';
|
||||
|
||||
|
|
@ -155,6 +156,13 @@ describe('Negative tests', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('client omits application_type during DCR (SEP-837)', async () => {
|
||||
const runner = new InlineClientRunner(noAppTypeClient);
|
||||
await runClientAgainstScenario(runner, 'auth/metadata-default', {
|
||||
expectedFailureSlugs: ['sep-837-application-type-present']
|
||||
});
|
||||
});
|
||||
|
||||
test('client does not use PKCE', async () => {
|
||||
const runner = new InlineClientRunner(noPkceClient);
|
||||
await runClientAgainstScenario(runner, 'auth/metadata-default', {
|
||||
|
|
|
|||
14
src/seps/sep-837.yaml
Normal file
14
src/seps/sep-837.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
sep: 837
|
||||
spec_url: https://modelcontextprotocol.io/specification/draft/basic/authorization#application-type-and-redirect-uri-constraints
|
||||
requirements:
|
||||
- check: sep-837-application-type-present
|
||||
text: 'MCP clients MUST specify an appropriate application_type during Dynamic Client Registration.'
|
||||
|
||||
- text: 'Native applications (desktop applications, mobile apps, CLI tools, and locally-hosted web applications accessed via localhost) SHOULD use application_type: "native".'
|
||||
excluded: 'harness cannot determine the client-under-test application class (native vs web) out-of-band; only presence and value validity are wire-observable'
|
||||
- text: 'Web applications (remote browser-based applications served from a non-local host) SHOULD use application_type: "web".'
|
||||
excluded: 'harness cannot determine the client-under-test application class (native vs web) out-of-band; only presence and value validity are wire-observable'
|
||||
- text: 'MCP clients MUST be prepared to handle registration failures due to redirect URI constraints when authorization servers implement OIDC.'
|
||||
excluded: 'robustness requirement with no defined wire-level success criterion'
|
||||
- text: 'When a registration request is rejected, clients SHOULD surface a meaningful error to the user or developer.'
|
||||
excluded: 'UI/DX behavior, not protocol-observable'
|
||||
Loading…
Reference in a new issue