Skip to content

fix(mcp): document python -I -m cli; test the entry point as clients run it - #150

Merged
IkarusAILabs merged 2 commits into
mainfrom
fix/mcp-python-m-cli-safe-path
Oct 25, 2026
Merged

IkarusAILabs merged 2 commits into
mainfrom
fix/mcp-python-m-cli-safe-path

Conversation

@IkarusAILabs

Copy link
Copy Markdown
Owner

Why

#146 (merged) documents this MCP interpreter config:

"args": ["-m", "cli", "mcp"]

MCP clients start stdio servers inside the user's project, and python -m puts the working directory first on sys.path. Any project with its own cli/ package, which is a common name, therefore runs its cli/__main__.py instead of OpenPulse. In an untrusted repository, its code executes as soon as the client starts the server. I reproduced this, and tests/test_cli_entrypoints.py::test_bare_python_m_cli_is_shadowed_by_a_project_cli now pins it.

The #146 tests didn't catch it because they ran from inside the OpenPulse checkout.

What

  • docs/MCP.md:
    • The interpreter config uses ["-I", "-m", "cli", "mcp"]. -I is isolated mode (Python 3.10+): it ignores the working directory, user site-packages and PYTHON* variables. -P is mentioned as the 3.11+ option that drops only the working directory.
    • A Windows example (C:\path\to\venv\Scripts\python.exe, with escaped backslashes).
    • A troubleshooting row for "something other than OpenPulse starts".
  • cli/__main__.py: cli(prog_name="openpulse"), so usage lines say openpulse instead of python -m cli.
  • tests/test_mcp_server.py: the stdio end-to-end test now launches python -P|-I -m cli mcp from tmp_path, the way a real client does.
  • tests/test_cli_entrypoints.py (new): replaces the cli: add cli/__main__.py so MCP clients can run python -m cli mcp #146 test in test_packaging.py, whose module-level tomllib skip hid it on Python 3.10.
    • Every subprocess has a timeout and runs outside the checkout.
    • The tests cover --version, prog_name, a project-local cli/ not winning when the flag is used, and the bare form being shadowed.
  • CHANGELOG: an Unreleased entry.

Checks

  • Entry-point tests pass on Python 3.10, 3.11 and 3.14.
  • Regression checks: reverting prog_name fails the help test, and the bare python -m cli mcp form run from a project with cli/ executes the project's code.
  • Full suite: 860 passed; ruff clean; CI test guard clean.

Follow-up to the #146 review findings.

🤖 Generated with Claude Code

IkarusAILabs and others added 2 commits October 25, 2026 17:16
…s run it

#146 documented `"args": ["-m", "cli", "mcp"]`. MCP clients start servers
inside the user's project, and `python -m` puts the working directory
first on sys.path, so any project with its own `cli/` package runs ITS
`cli/__main__.py` instead of OpenPulse - in an untrusted repository, its
code executes when the client starts the server. Reproduced, and now
pinned by a test.

- docs/MCP.md: interpreter config uses `-I` (isolated mode, 3.10+; `-P`
  on 3.11+ drops only the cwd) with the reason spelled out; Windows
  `Scripts\python.exe` example with escaped backslashes; troubleshooting
  row for "something other than OpenPulse starts".
- cli/__main__.py: `cli(prog_name="openpulse")` - usage lines no longer
  say `python -m cli`; docstring states the -I requirement.
- tests/test_mcp_server.py: the stdio end-to-end test launches
  `python -P|-I -m cli mcp` from tmp_path, not the checkout, as a real
  client does.
- tests/test_cli_entrypoints.py (new, replaces the test in
  test_packaging.py, whose module-level tomllib skip hid it on 3.10):
  every subprocess has a timeout and runs outside the checkout; covers
  --version, prog_name, a project-local `cli/` NOT winning with the
  flag, and the bare form being shadowed (why the docs insist on -I).
- CHANGELOG Unreleased entry.

Verified on Python 3.10, 3.11 and 3.14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IkarusAILabs
IkarusAILabs merged commit 3e63629 into main Oct 25, 2026
15 checks passed
@WintersCoder
WintersCoder deleted the fix/mcp-python-m-cli-safe-path branch October 28, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants