HTTP transport & authentication¶
iso20022-evidence-pack-mcp speaks stdio by default — launched by a local
MCP client, one process per operator, with no network surface and no
authentication. For shared, multi-tenant deployments, v0.0.2 adds an optional
streamable-HTTP transport with OAuth 2.1 resource-server authentication
(RFC 9728). This page is the reference for running and securing it.
Choosing a transport¶
The transport is selected on the command line:
# Default: stdio, for a local MCP client.
iso20022-evidence-pack-mcp
# Optional: authenticated streamable HTTP, for a shared service.
iso20022-evidence-pack-mcp --transport=http --bind=127.0.0.1:8080
--transportisstdio(default) orhttp.--bindtakesHOST:PORTand applies only to--transport=http. It defaults to loopback127.0.0.1:8080, so exposing the server to a network (for example--bind=0.0.0.0:8080) is an explicit opt-in.
The HTTP transport pulls in additional dependencies — pyjwt[crypto], httpx,
starlette, and uvicorn. The default stdio transport needs none of them.
HTTP with no auth is refused
Starting --transport=http without either OAuth 2.1 or a static dev-mode
token configured fails to start rather than silently serving an
unauthenticated endpoint.
Two auth modes apply, strongest first: OAuth 2.1 (when the
ISO20022_EVIDENCE_PACK_OAUTH_* variables are set) else the static dev-mode
token. If both are configured, OAuth wins and the static token is ignored.
OAuth 2.1 resource server (RFC 9728)¶
Point the server at your OAuth 2.1 authorization server with these environment variables:
| Variable | Required | Meaning |
|---|---|---|
ISO20022_EVIDENCE_PACK_OAUTH_ISSUER |
yes | The authorization server's issuer identifier; the JWT iss claim must match it exactly. |
ISO20022_EVIDENCE_PACK_OAUTH_AUDIENCE |
yes | This server's canonical resource URI (RFC 8707); the JWT aud claim must contain it. |
ISO20022_EVIDENCE_PACK_OAUTH_JWKS_URL |
no | JWKS document URL for signature checks. Defaults to <issuer>/.well-known/jwks.json. |
ISO20022_EVIDENCE_PACK_OAUTH_SCOPES |
no | Space-separated scopes every token must carry. Unset/empty means no scope gate. |
ISO20022_EVIDENCE_PACK_OAUTH_ISSUER=https://auth.example.com \
ISO20022_EVIDENCE_PACK_OAUTH_AUDIENCE=https://mcp.example.com/mcp \
iso20022-evidence-pack-mcp --transport=http --bind=0.0.0.0:8080
Setting some but not both of ISSUER and AUDIENCE is a partial
configuration and fails loudly at startup, so a typo cannot downgrade a
deployment to weaker auth.
How a request is validated¶
Every HTTP request must present Authorization: Bearer <jwt>. The JWT is
validated against the JWKS in order: structure, signing-key resolution (by
kid), signature, exp / nbf (with a 30-second clock-skew leeway), iss,
aud, and any required scopes. The verification algorithm is always taken from
the JWKS key, never from the attacker-controlled token header, so none /
HMAC downgrade attacks are structurally impossible against an asymmetric key
set. JWKS keys are cached with a short TTL and refreshed on key rotation (an
unknown kid).
Protected-resource metadata and challenges¶
- The protected-resource metadata document (RFC 9728 §2) is served
unauthenticated on
GET/HEADto/.well-known/oauth-protected-resource(and its audience-derived variant). It advertises theresource, theauthorization_servers,bearer_methods_supported, and anyscopes_supported. - A missing or invalid token is rejected
401; a valid token that lacks a required scope is rejected403. Both carry aWWW-Authenticate: Bearer …challenge with aresource_metadatapointer (RFC 6750 / RFC 9728 §5.1).
Static dev-mode bearer token¶
For local development, set a single shared secret instead of wiring up an authorization server:
ISO20022_EVIDENCE_PACK_TOKEN=s3cret \
iso20022-evidence-pack-mcp --transport=http --bind=127.0.0.1:8080
Every request must then send Authorization: Bearer s3cret (compared with a
constant-time hmac.compare_digest). This is dev-mode auth: a single shared
secret, no expiry, and no scopes. Prefer OAuth 2.1 for anything beyond local
testing.
Multi-tenant scoping¶
HTTP callers may send an optional X-MCP-Tenant header. On an authorized
request it is forwarded, together with the authenticated token's scopes, into a
per-request context that tools can read. Under the stdio transport both are
simply empty, so tool code never has to branch on the transport.
See also¶
- Evidence packs — the pack schema, sealing, and Ed25519 signing.
SECURITY.md— reporting practice, supported versions, and the threat-model note.ROADMAP.md— what is planned next.