agentsclimarketplace

Mcp server auth

Skill Paldom/mcp-server-skills/skills/mcp-server-auth

Implements MCP server authorization - OAuth 2.1 resource server role, RFC 9728/8414 discovery, PKCE, RFC 8707 audience validation, scopes, client registration. Use when adding auth, OAuth, tokens, or credentials to an MCP server, or debugging 401/403/discovery failures. Not for general threat hardening, transport wiring, or non-MCP app login.From its SKILL.md

Install
npx -y skills add Paldom/mcp-server-skills --skill mcp-server-auth

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.4 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

mcp-server-auth

Make an MCP server authenticate its callers correctly. The spec profiles OAuth 2.1 precisely; the documented failures this skill fixes are servers that invent bearer-token schemes, pass client tokens through to downstream APIs, skip discovery metadata (so no client can connect), or accept any validly-signed token regardless of audience.

Targets spec revision 2025-11-25 (verified 2026-07-20): https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization.

When NOT to use

  • Threat modeling / injection / sandboxing → mcp-server-security (auth is one control; that skill owns the attack taxonomy).
  • Transport mechanics (Origin validation, sessions, headers) → mcp-server-implementation. Hosting/gateways → mcp-server-deployment.
  • OAuth for ordinary web/mobile apps — this is the MCP profile specifically.

Workflow

1. Pick the auth model by transport

  • stdio (local subprocess): the OAuth spec does NOT apply — read credentials from the environment, scope the underlying API key minimally, never put secrets in client-config args.
  • Streamable HTTP: authorization is OPTIONAL in the spec, and HTTP transports SHOULD conform to the OAuth 2.1 profile. Once you implement it, the MUSTs below are normative. Strong recommendation: any internet-exposed server implements it — scans keep finding thousands of open MCP endpoints. (Many secondary sources say "OAuth is mandatory for remote" — that is not what the spec says; don't repeat it.)
  • A static shared API key is not a substitute for identity-scoped tokens: no per-user scoping, no revocation story, total blast radius. If a gateway terminates auth for you, the requirements below move there.

2. Be a resource server, not an authorization server

Your MCP server validates tokens; an AS (Auth0/Okta/Keycloak/Entra or your IdP) issues them. Building your own AS is almost always the wrong call — delegate. If the server must broker access to a third-party API, see step 6.

3. Publish discovery metadata (or no client can connect)

  • RFC 9728 Protected Resource Metadata (MUST): serve /.well-known/oauth-protected-resource with your canonical resource URI and authorization_servers; AND/OR return WWW-Authenticate: Bearer resource_metadata="<url>" on 401 (clients try header first, then well-known — support both).
  • The AS must offer RFC 8414 metadata or OIDC Discovery (2025-11-25 accepts either; clients must support both).
  • Every 401/403 carries the right challenge — see the exact HTTP exchanges in references/oauth-wire.md.

4. Validate every token, every request

  • Authorization: Bearer <token> on every request — sessions never carry auth (spec MUST NOT). Tokens never in query strings.
  • Audience validation (RFC 8707): accept only tokens whose audience is your canonical resource URI; a validly-signed, unexpired token for another resource → 401. Clients send resource= on authorization and token requests; you enforce it on receipt.
  • Validate locally: cache the AS JWKS and verify signature/exp/aud in-process (sub-ms) instead of a network introspection per call; re-fetch on key rotation.
  • Insufficient scope at runtime → 403 with error="insufficient_scope" + the required scope in WWW-Authenticate (SEP-835) so clients can step up incrementally. Publish minimal scopes; separate read from write.
  • PKCE: clients MUST use S256 and MUST refuse an AS whose metadata lacks code_challenge_methods_supported — when you operate the AS config, make sure that field is present or every spec-conforming client will refuse you.

5. Client registration: CIMD first

Priority order (2025-11-25): pre-registered credentials → Client ID Metadata Documents (the client_id is an HTTPS URL serving the client's metadata; recommended when the AS advertises client_id_metadata_document_supported) → RFC 7591 Dynamic Client Registration only as back-compat fallback (deprecated in the next revision) → prompt the user. If you allow DCR: allowlist/exact redirect URIs, no wildcards — open DCR + arbitrary redirect URI is a disclosed one-click account-takeover class.

6. Never pass tokens through; proxy with consent

  • Token passthrough is forbidden: never accept a token not issued for your server, never forward the client's token upstream. Downstream APIs are called with credentials the server owns (or an explicit token exchange).
  • If your server fronts a third-party AS with a static client_id (the "OAuth proxy" shape): obtain per-client consent before every forward, exact-match redirect URIs, bind and verify state — the confused-deputy writeups that broke real products in 2025 all violated one of these.

7. Verify the flow end to end

python3 "${CLAUDE_SKILL_DIR}/scripts/check_auth_endpoints.py" https://your-host/mcp

probes: unauthenticated request → 401 + parseable challenge; PRM well-known resolves and matches the server URL; AS metadata reachable with S256 advertised. Then run a real client (MCP Inspector supports the OAuth flow) and confirm a wrong-audience token is rejected. Conformance suite: npx @modelcontextprotocol/conformance server --url ....

Output spec

A server that: serves RFC 9728 PRM (+ challenge headers), validates signature/expiry/audience on every request via cached JWKS, returns the 401/403 contract with correct WWW-Authenticate, scopes split read/write with step-up, registers clients via CIMD (DCR only as fallback, allowlisted), touches downstream APIs only with its own credentials, and passes the probe script + a live client flow.

Gotchas

  • Sessions are not auth — an Mcp-Session-Id proves nothing; validate the bearer token on every request even mid-session.
  • SSRF in discovery: SDK clients have fetched attacker-controlled resource_metadata URLs before validating them (disclosed against both major SDKs) — if you implement client-side discovery anywhere, validate scheme/host before fetching; as a server, never reflect user input into challenge URLs. Full taxonomy: mcp-server-security.
  • Issuer validation: verify AS metadata issuer matches where you fetched it (RFC 8414 §3.3); mixed-endpoint metadata (legit authorization_endpoint, attacker token_endpoint) is a disclosed credential-theft class. The 2026-07-28 revision adds RFC 9207 iss checks and requires client credentials keyed per-issuer — align now.
  • Access tokens short-lived (minutes-hours); refresh handled by the client and AS, not you. Log auth failures with reasons; never log tokens.
  • The auth extension ecosystem (modelcontextprotocol/ext-auth) hosts optional additions — check it before inventing an extension.

Pointers

  • references/oauth-wire.md — the exact HTTP exchanges (401/403 challenges, PRM and AS metadata JSON, CIMD document, token validation pseudocode, RFC map, IdP wiring notes).
  • scripts/check_auth_endpoints.py — deterministic discovery/challenge probe (stdlib-only; non-zero exit on failures).

What ships with it: 3 files

16.7 KB alongside SKILL.md, 1 of them executable

evals/

references/

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.