PrefectHQ/fastmcp · error · RuntimeError
User server did not start on port {mcp_port}
Error message
User server did not start on port {mcp_port} What it means
`fastmcp dev` for apps starts the dev UI only after the user's MCP server answers on the configured port. _wait_for_server polls for up to 15 seconds; if the server never becomes reachable, run_dev_apps raises this RuntimeError naming the port. It is a startup-failure guard, not a runtime crash of your server code.
Source
Thrown at fastmcp_slim/fastmcp/cli/apps_dev.py:1812
logger.info("Fetching app-bridge.js from npm…")
# Start the server first so user_proc is assigned before anything
# that might fail (e.g. npm fetch). This ensures the finally
# cleanup can kill the subprocess even if the bundle fetch raises.
user_proc = await _start_user_server(
server_spec, mcp_port, reload=reload, host=host
)
app_bridge_js, import_map_json = await _fetch_app_bridge_bundle(
_EXT_APPS_VERSION, _MCP_SDK_VERSION
)
import_map_tag = (
f' <script type="importmap">\n {import_map_json}\n </script>'
)
ready = await _wait_for_server(mcp_url, timeout=15.0)
if not ready:
raise RuntimeError(f"User server did not start on port {mcp_port}")
logger.info(f"FastMCP dev UI at {dev_url}")
dev_app = _make_dev_app(
mcp_url, app_bridge_js, import_map_tag, _MessageLog(), log_panel
)
config = uvicorn.Config(
dev_app,
host=host,
port=dev_port,
log_level="warning",
ws="websockets-sansio",
)
server = uvicorn.Server(config)
# Suppress uvicorn's own signal handlers — they use signal.signal() which
# conflicts with asyncio and causes hangs. We cancel the task instead.
server.install_signal_handlers = lambda: None # type: ignore[method-assign] # ty:ignore[unresolved-attribute]
View on GitHub (pinned to 1f02114297)
Solutions
- Run your server directly (e.g. fastmcp run or python your_server.py) to see the actual boot error
- Check the port isn't already in use (lsof -i :PORT) and kill the stale process
- Confirm host/port match between your server binding and the dev command's mcp_port
- If the server just starts slowly, increase the timeout or pre-warm imports
Example fix
# before: server binds elsewhere mcp.run(host='0.0.0.0', port=9999) # dev expects 8000 # after mcp.run(host='127.0.0.1', port=8000)
Defensive patterns
Strategy: retry
Validate before calling
import socket
s = socket.socket()
s.settimeout(2)
try:
s.connect(('127.0.0.1', mcp_port)); print('port in use')
except OSError:
print('port free; server not running yet')
finally:
s.close() Try / catch
try:
run_dev_apps(...)
except RuntimeError as exc:
if str(exc).startswith('User server did not start'):
logger.error('MCP server failed to boot; run it directly to see the underlying error')
else:
raise Prevention
- Boot your server standalone before running the dev UI
- Check for port conflicts with lsof/netstat
- Keep server module imports light to stay under the 15s startup timeout
- Confirm the dev command's port matches your server's binding
When it happens
Trigger: The MCP server process failed to boot (import error, bad config, port already bound by another process), or it listens on a different host/port than mcp_url expects, and the 15s poll times out.
Common situations: Syntax/import error in the user's server module; another process occupying the port; server bound to 0.0.0.0:9999 while the dev UI probes a different port; slow imports (heavy ML libs) exceeding the 15s timeout.
Related errors
- Overall timeout exceeded: {url}
- Timeout fetching {url}
- HTTP request timed out ({type(exc).__name__})
- Upstream request timed out, please retry
- 408
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/ec7463fe99f24314.
Report an issue: GitHub.