mcptest docs GitHub

Auth-hardening conformance checks

The 2026-07-28 spec tightens six aspects of the OAuth / OIDC surface a Model Context Protocol server may expose. Each tightening is its own SEP. mcptest ships a library of pure functions that take the relevant metadata input and return one of pass, fail, or not-applicable, so a conformance run can score a server against the set without a custom auth client per check.

This page is the operator-level reference: what each check asks, what input it consumes, and what a violation looks like. The implementation lives in mcptest_core::auth::conformance.

The six checks

SEPFunctionWhat it asks
2468check_iss_presentDoes the authorization response carry iss, and does it match the configured issuer (RFC 9207)?
837check_dcr_application_typeDid the DCR registration declare application_type, and does it match the client's deployment shape (native for CLI, web for browser apps)?
2352check_as_bound_credentialsIf the resource migrated to a new authorization server, did the client re-register before reusing its credentials?
2207check_oidc_refreshIf offline_access was granted, did the client rotate the refresh token on use?
2350check_scope_step_up_accumulationDid the step-up grant accumulate the previously held scopes with the newly requested ones, instead of silently downgrading?
2351check_well_known_suffixIs the .well-known URI a terminal /.well-known/<id> form, with no path component after the identifier?

Outcome shape

Every check returns a CheckOutcome:

pub enum CheckOutcome {
    Pass,
    Fail { reason: String },
    NotApplicable { reason: String },
}

Pass means the metadata satisfies the rule. Fail carries a one-line reason the reporter renders next to the check name. NotApplicable is for checks that do not exercise against the captured input (for example, check_oidc_refresh returns NotApplicable when the grant did not include offline_access).

What v1 does and does not do

v1 ships the library: each check is a pure function that takes a typed input struct and returns the outcome.

Bridge to a compliance report

mcptest_core::compliance::auth_hardening is the bridge between captured OAuth/OIDC metadata and the six checks. The runner populates an AuthHardeningProbe from a real OAuth handshake:

let probe = AuthHardeningProbe {
    iss: Some(IssCapture {
        iss_from_response: Some(callback.iss.clone()),
        expected_issuer: as_metadata.issuer.clone(),
    }),
    dcr: Some(DcrCapture {
        declared: registration.application_type.clone(),
        is_native_client: true,
    }),
    // ... three more optional captures ...
    well_known_url: Some(resolved_well_known.clone()),
};
let report = run_checks(&probe);

run_checks(probe) returns an AuthHardeningReport with one AuthHardeningRow per SEP. Each row carries the SEP id, a human-readable name, and the underlying CheckOutcome. A missing field on the probe maps to NotApplicable rather than a failure so a partial capture (a flow that did not exercise the OIDC refresh, say) still produces a usable scorecard.

Planned follow-up

Cross-references