Bug: open-terminal mcp always sends empty Authorization header → 401 on all tool calls + stdio transport crashes with unexpected host kwarg
Environment
open-terminal version: latest (uvx open-terminal[mcp])
fastmcp version: 3.2.4
- OS: Windows 11
- Python: 3.14
Bug 1: MCP server always sends empty Authorization: Bearer header → 401 on every tool call
Steps to reproduce
$env:OPEN_TERMINAL_API_KEY = "12345678"
uvx "open-terminal[mcp]" mcp --transport streamable-http --host 0.0.0.0 --port 9000
Call any tool (e.g. run_command) → 401 Unauthorized
Also reproduces with --config pointing to a config.toml containing api_key = "12345678".
Error
HTTPStatusError: Client error '401 Unauthorized' for url 'http://fastapi/execute?wait=10'
ValueError: HTTP error 401: Unauthorized - {'detail': 'Invalid API key'}
Root cause
mcp_server.py captures API_KEY at module import time:
# open_terminal/mcp_server.py
from open_terminal.env import API_KEY # ← captured at import, always ""
mcp = FastMCP.from_fastapi(
app=app,
name="Open Terminal",
httpx_client_kwargs={
"headers": {
"Authorization": f"Bearer {API_KEY}", # ← always empty string
}
},
)
In cli.py, mcp_server is imported after config.init() runs, but open_terminal/env.py line 31 already executed at first import — before config.init() and before os.environ["OPEN_TERMINAL_API_KEY"] is set. So API_KEY is always "" regardless of env vars or config file.
The run command works correctly because it explicitly sets os.environ["OPEN_TERMINAL_API_KEY"] before anything reads it. The mcp command has no equivalent step and also has no --api-key CLI option.
Proposed fix
Option A — add --api-key to the mcp command and set the env var before importing mcp_server (mirrors what run does):
# open_terminal/cli.py
@main.command()
@click.option("--transport", default="stdio", type=click.Choice(["stdio", "streamable-http"]))
@click.option("--host", default=None)
@click.option("--port", default=None, type=int)
@click.option("--config", "config_path", default=None, type=click.Path(...))
@click.option("--cwd", default=None, type=click.Path(...))
@click.option(
"--api-key",
default="",
envvar="OPEN_TERMINAL_API_KEY",
help="Bearer API key (or set OPEN_TERMINAL_API_KEY env var)",
)
def mcp(transport, host, port, config_path, cwd, api_key):
from open_terminal import config
cfg = config.init(config_path)
host = host or cfg.get("host", "0.0.0.0")
port = port if port is not None else cfg.get("port", 8000)
# Resolve API key: CLI flag > env var > config file
if not api_key:
api_key = cfg.get("api_key", "")
# Must set BEFORE importing mcp_server so env.py picks it up at import time
if api_key:
os.environ["OPEN_TERMINAL_API_KEY"] = api_key
if cwd:
os.chdir(cwd)
from open_terminal.mcp_server import mcp as mcp_server
...
Option B — lazily resolve API_KEY in mcp_server.py instead of at import time:
# open_terminal/mcp_server.py
from fastmcp import FastMCP
from open_terminal.main import app
import os
def _auth_headers() -> dict:
key = os.environ.get("OPEN_TERMINAL_API_KEY", "")
return {"Authorization": f"Bearer {key}"} if key else {}
mcp = FastMCP.from_fastapi(
app=app,
name="Open Terminal",
httpx_client_kwargs={"headers": _auth_headers()},
)
Bug 2: stdio transport crashes — TypeError: unexpected keyword argument 'host'
Steps to reproduce
Use the following VS Code mcp.json:
{
"servers": {
"open-terminal": {
"type": "stdio",
"command": "uvx",
"args": ["open-terminal[mcp]", "mcp"],
"env": { "OPEN_TERMINAL_API_KEY": "12345678" }
}
}
}
Error
TypeError: TransportMixin.run_stdio_async() got an unexpected keyword argument 'host'
Root cause
cli.py line 187 unconditionally passes host and port to mcp_server.run() regardless of transport:
mcp_server.run(transport=transport, host=host, port=port) # always passes host/port
FastMCP's stdio transport does not accept host or port kwargs.
Proposed fix
# open_terminal/cli.py
kwargs: dict = {"transport": transport}
if transport == "streamable-http":
kwargs["host"] = host
kwargs["port"] = port
mcp_server.run(**kwargs)
Bug:
open-terminal mcpalways sends emptyAuthorizationheader → 401 on all tool calls +stdiotransport crashes with unexpectedhostkwargEnvironment
open-terminalversion: latest (uvx open-terminal[mcp])fastmcpversion: 3.2.4Bug 1: MCP server always sends empty
Authorization: Bearerheader → 401 on every tool callSteps to reproduce
Call any tool (e.g.
run_command) → 401 UnauthorizedAlso reproduces with
--configpointing to aconfig.tomlcontainingapi_key = "12345678".Error
Root cause
mcp_server.pycapturesAPI_KEYat module import time:In
cli.py,mcp_serveris imported afterconfig.init()runs, butopen_terminal/env.pyline 31 already executed at first import — beforeconfig.init()and beforeos.environ["OPEN_TERMINAL_API_KEY"]is set. SoAPI_KEYis always""regardless of env vars or config file.The
runcommand works correctly because it explicitly setsos.environ["OPEN_TERMINAL_API_KEY"]before anything reads it. Themcpcommand has no equivalent step and also has no--api-keyCLI option.Proposed fix
Option A — add
--api-keyto themcpcommand and set the env var before importingmcp_server(mirrors whatrundoes):Option B — lazily resolve
API_KEYinmcp_server.pyinstead of at import time:Bug 2:
stdiotransport crashes —TypeError: unexpected keyword argument 'host'Steps to reproduce
Use the following VS Code
mcp.json:{ "servers": { "open-terminal": { "type": "stdio", "command": "uvx", "args": ["open-terminal[mcp]", "mcp"], "env": { "OPEN_TERMINAL_API_KEY": "12345678" } } } }Error
Root cause
cli.pyline 187 unconditionally passeshostandporttomcp_server.run()regardless of transport:FastMCP's
stdiotransport does not accepthostorportkwargs.Proposed fix