python-mcp-bootstrap 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. python_mcp_bootstrap-0.1.3/.gitignore +44 -0
  2. python_mcp_bootstrap-0.1.3/CHANGELOG.md +87 -0
  3. python_mcp_bootstrap-0.1.3/CONTRIBUTING.md +94 -0
  4. python_mcp_bootstrap-0.1.3/LICENSE +21 -0
  5. python_mcp_bootstrap-0.1.3/PKG-INFO +201 -0
  6. python_mcp_bootstrap-0.1.3/README.md +176 -0
  7. python_mcp_bootstrap-0.1.3/SECURITY.md +47 -0
  8. python_mcp_bootstrap-0.1.3/docs/contract.md +123 -0
  9. python_mcp_bootstrap-0.1.3/docs/integration.md +95 -0
  10. python_mcp_bootstrap-0.1.3/docs/releases/0.1.0.md +62 -0
  11. python_mcp_bootstrap-0.1.3/docs/releases/0.1.1.md +58 -0
  12. python_mcp_bootstrap-0.1.3/docs/releases/0.1.2.md +83 -0
  13. python_mcp_bootstrap-0.1.3/docs/releases/0.1.3.md +81 -0
  14. python_mcp_bootstrap-0.1.3/examples/README.md +21 -0
  15. python_mcp_bootstrap-0.1.3/examples/example_mcp/__init__.py +3 -0
  16. python_mcp_bootstrap-0.1.3/examples/first_run.py +49 -0
  17. python_mcp_bootstrap-0.1.3/examples/pyproject.toml +13 -0
  18. python_mcp_bootstrap-0.1.3/pyproject.toml +91 -0
  19. python_mcp_bootstrap-0.1.3/scripts/__init__.py +0 -0
  20. python_mcp_bootstrap-0.1.3/scripts/release_check.py +205 -0
  21. python_mcp_bootstrap-0.1.3/scripts/vendor.py +210 -0
  22. python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/__init__.py +58 -0
  23. python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/__main__.py +8 -0
  24. python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/cli.py +57 -0
  25. python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/core.py +729 -0
  26. python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/py.typed +0 -0
  27. python_mcp_bootstrap-0.1.3/tests/test_bootstrap.py +1036 -0
  28. python_mcp_bootstrap-0.1.3/tests/test_cli.py +44 -0
  29. python_mcp_bootstrap-0.1.3/tests/test_core.py +355 -0
  30. python_mcp_bootstrap-0.1.3/tests/test_examples.py +27 -0
  31. python_mcp_bootstrap-0.1.3/tests/test_package.py +18 -0
  32. python_mcp_bootstrap-0.1.3/tests/test_release_check.py +121 -0
  33. python_mcp_bootstrap-0.1.3/tests/test_vendor.py +80 -0
@@ -0,0 +1,44 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+ .Python
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ .eggs/
10
+ .venv/
11
+ .venv.previous*/
12
+ venv/
13
+ env/
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .pip-cache/
18
+ .coverage
19
+ .coverage.*
20
+ htmlcov/
21
+ .tox/
22
+ .nox/
23
+
24
+ # Bootstrap-local artifacts
25
+ .uv-cache/
26
+ .uv-python/
27
+ UV-CACHE/
28
+ UV-PYTHON/
29
+
30
+ # Example app first-run artifacts
31
+ /examples/.python-version
32
+ /examples/_vendor/
33
+
34
+ # Secrets and local env
35
+ .env
36
+ .env.*
37
+ !.env.example
38
+ *.pem
39
+
40
+ # Editor and OS
41
+ .DS_Store
42
+ .idea/
43
+ .vscode/
44
+ *.swp
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ ## 0.1.3 — 2026-11-04
4
+
5
+ - Restore the single handoff that 0.1.2 removed. 0.1.2 stopped exec'ing on the
6
+ good-running path entirely, so a wrapper that branched on `spec.env_var` and
7
+ skipped `bootstrap()` after the handoff failed with `missing_continuation`
8
+ (exit `7`) on any machine whose first run was already on a supported
9
+ interpreter. It worked on machines that had to provision, which made the
10
+ failure depend on the host.
11
+ - The good-running path execs once when no handoff has been recorded, setting
12
+ `spec.env_var`; a later pass with that variable set and no continuation still
13
+ reports `missing_continuation` (exit `7`). The loop stays dead, and the
14
+ documented handoff signal works again.
15
+ - Correct the migration advice in the v0.1.2 release notes, which claimed
16
+ env-var branches were unaffected.
17
+ - Remove `CODE_OF_CONDUCT.md`: single maintainer, no community to govern yet;
18
+ `CONTRIBUTING.md` covers the checks a change must pass. Fix the issue template
19
+ front matter to use strings rather than empty YAML sequences.
20
+ - Drop the hand-maintained version line from the README; the tag is the source
21
+ of truth.
22
+
23
+ ## 0.1.2 — 2026-11-04
24
+
25
+ - Fix an infinite re-exec: when the running interpreter already met the floor
26
+ and neither `main_fn` nor `spec.package_main` was configured, `bootstrap()`
27
+ exec'd the same entry point on the same interpreter with the same arguments,
28
+ forever. That branch now returns a `missing_continuation` report (exit `7`,
29
+ new) and execs nothing. Reports carry `env_var` and `handed_off` so a
30
+ consumer can tell a first pass from a re-entry.
31
+ - `docs/contract.md` documents exit `7` and states the no-self-exec property;
32
+ `README.md` and `docs/integration.md` now say a continuation is required for
33
+ an entry point that always calls `bootstrap()`. Consumers that check
34
+ `spec.env_var` themselves keep working unchanged.
35
+ - Consent card: "private Python" became "project-local Python", which is what
36
+ it always meant.
37
+ - `SECURITY.md` points at GitHub private vulnerability reporting instead of
38
+ "the repository owner".
39
+ - Package metadata names a maintainer, and the README states that distribution
40
+ is GitHub Releases only (the project is not on PyPI).
41
+
42
+ ## 0.1.1 — 2026-11-04
43
+
44
+ - Fix the tag-run CI failure on every matrix cell and on the wheel/release
45
+ gate: `actions/checkout@v4` fetches the annotated release tag, then
46
+ re-fetches the commit as `refs/tags/<tag>`, replacing the tag object with a
47
+ lightweight ref to the same commit. `release_check.py` correctly reported
48
+ `tag '<tag>' is not annotated`. The jobs that run the suite or the release
49
+ gate now restore the annotated ref after checkout and assert its object
50
+ type. The annotated-tag requirement itself is unchanged.
51
+ - The local matching-tag test skips with a clear reason when the tag is absent
52
+ or not an annotated object, so a checkout artifact cannot mask the real
53
+ gate.
54
+ - Library behaviour is unchanged from 0.1.0.
55
+
56
+ ## 0.1.0 — 2026-11-04
57
+
58
+ - Initial release of the shared pre-install Python bootstrap for MCP
59
+ applications.
60
+ - `BootstrapSpec`, version parsing, platform-aware venv paths, and uv
61
+ discovery in a single stdlib-only `core.py` that stays importable on
62
+ Python 3.12.
63
+ - Selection order (`--python`, the running interpreter, an existing `.venv`,
64
+ then the consent card), explicit `--install-python` consent before any
65
+ download, project-local provisioning, install verification, atomic pin
66
+ writes, and exec handoff.
67
+ - Windows-aware handoff and uv discovery, managed-only interpreter selection,
68
+ project-path validation, `--` argument handling, and credential-redacted
69
+ diagnostics.
70
+ - `install_args` reject path-like entries (absolute, Windows-rooted, and `..`,
71
+ including attached short forms) and venv-redirecting flags (`--target`,
72
+ `--prefix`, `--root`, `--python`); non-path flags such as `--index-url`
73
+ pass through.
74
+ - `pin` is a plain `X[.Y[.Z]]` final version at or above `required`, so
75
+ `.post` and `+local` strings and pre-releases fail before any download.
76
+ - A broken or mismatched `.venv` is moved aside, never deleted, and
77
+ `verify_import` runs isolated (`-I -P`).
78
+ - Vendor tooling (`scripts/vendor.py`) with `VENDOR.json` manifests and a
79
+ `--check` drift test, plus the vendored example first run in CI.
80
+ - `scripts/release_check.py` validates metadata, the changelog, release notes,
81
+ the Python pin, tracked-file hygiene, annotated tags, and published release
82
+ assets.
83
+ - CI on Python 3.14.10 and 3.15.2 on Ubuntu, macOS, and Windows, plus a 3.12
84
+ compatibility job, a wheel/release gate, and the vendored example first run.
85
+ - Development pin 3.15.2 and MIT license.
86
+ - Honest limits: path checks are lexical (symlinks are not resolved), and
87
+ concurrent first runs against one project are unsupported.
@@ -0,0 +1,94 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ The development pin is Python 3.15.2. The package floor is 3.14.
6
+
7
+ ```bash
8
+ python3 -m venv .venv
9
+ . .venv/bin/activate
10
+ python -m pip install -e '.[dev]'
11
+ ```
12
+
13
+ ## Checks
14
+
15
+ Run all four before proposing a change:
16
+
17
+ ```bash
18
+ python -m pytest --cov=python_mcp_bootstrap --cov-fail-under=90
19
+ python -m ruff format --check
20
+ python -m ruff check
21
+ python -m mypy
22
+ ```
23
+
24
+ Build the distribution as a final packaging check:
25
+
26
+ ```bash
27
+ python -m build
28
+ ```
29
+
30
+ Exercise the vendored consumer path as CI does:
31
+
32
+ ```bash
33
+ python scripts/vendor.py --target examples --dest _vendor/python_mcp_bootstrap.py
34
+ python scripts/vendor.py --target examples --dest _vendor/python_mcp_bootstrap.py --check
35
+ ```
36
+
37
+ ## CI status
38
+
39
+ CI is advisory for now: there is no branch protection and there are no
40
+ required status checks. Check the matrix before merging; a pending cell is not
41
+ green. A green tag run is the strongest evidence for a release.
42
+
43
+ ## Rules
44
+
45
+ - `src/python_mcp_bootstrap/core.py` stays stdlib-only.
46
+ - `core.py` must remain importable and runnable on Python 3.12; CI runs the
47
+ suite on 3.12 as well as on the 3.14 and 3.15 matrix.
48
+ - Never import `mcp` from the bootstrap path.
49
+ - Never add an install, download, or provisioning subprocess before explicit
50
+ consent. Version probes and the isolated import check may run before consent.
51
+ - Never use `shell=True`.
52
+ - Keep machine-specific paths, credentials, and private labels out of tracked
53
+ files.
54
+
55
+ ## Release
56
+
57
+ Before tagging, from the commit that will be tagged:
58
+
59
+ ```bash
60
+ python scripts/release_check.py
61
+ python -m pytest --cov=python_mcp_bootstrap --cov-fail-under=90
62
+ python -m build
63
+ ```
64
+
65
+ Rebuild `dist/` from that tip (`dist/` is gitignored), regenerate
66
+ `dist/SHA256SUMS` for the wheel and sdist, and verify the wheel in a clean
67
+ environment before attaching them:
68
+
69
+ ```bash
70
+ python -m venv /tmp/wheel-check
71
+ /tmp/wheel-check/bin/python -m pip install dist/*.whl
72
+ /tmp/wheel-check/bin/python -m python_mcp_bootstrap --check
73
+ ```
74
+
75
+ Tag with an annotated tag, push it, and attach the wheel and sdist to the
76
+ GitHub release:
77
+
78
+ ```bash
79
+ git tag -a v<version> -m "python-mcp-bootstrap v<version>"
80
+ git push origin v<version>
81
+ python scripts/release_check.py --tag v<version>
82
+ ```
83
+
84
+ Use annotated tags for releases. CI’s package job fails a tag/version mismatch
85
+ and a lightweight tag when the tag is present; the `release-gate` workflow
86
+ verifies the published release’s wheel, sdist, and `SHA256SUMS` assets. The
87
+ release notes live in `docs/releases/`. Tags are unsigned for now; do not
88
+ present a tag as a signature.
89
+
90
+ ## Scope
91
+
92
+ The core owns interpreter selection, consent, provisioning, verification, and
93
+ handoff. MCP server behavior and consumer-specific install steps belong in the
94
+ consumer repositories.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 python-mcp-bootstrap contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.5
2
+ Name: python-mcp-bootstrap
3
+ Version: 0.1.3
4
+ Summary: Pre-install Python runtime bootstrap for MCP applications.
5
+ Project-URL: Repository, https://github.com/4zhmv6zvj2-afk/python-mcp-bootstrap
6
+ Author-email: Ron <4zhmv6zvj2-afk@users.noreply.github.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: bootstrap,mcp,python,runtime,uv
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Programming Language :: Python :: 3.15
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.14
18
+ Provides-Extra: dev
19
+ Requires-Dist: build>=1.2; extra == 'dev'
20
+ Requires-Dist: mypy>=1.13; extra == 'dev'
21
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
22
+ Requires-Dist: pytest>=8.3; extra == 'dev'
23
+ Requires-Dist: ruff>=0.9; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # python-mcp-bootstrap
27
+
28
+ A small setup helper for Python apps that use MCP.
29
+
30
+ MCP (Model Context Protocol) is a way for AI assistants to use tools and data.
31
+ Before one of those apps starts, this helper makes sure it runs on a supported
32
+ version of Python. If your computer does not have one, it explains what is
33
+ missing and asks before downloading anything. It never changes the Python that
34
+ is already installed.
35
+
36
+ This is a bootstrap *for* MCP applications, not an MCP implementation. It has
37
+ no runtime dependency on the MCP SDK and never imports one.
38
+
39
+ **Most people do not need to run this directly.** The app's setup script uses
40
+ it. If you are a developer adding it to an app, jump to
41
+ [For developers](#for-developers).
42
+
43
+
44
+ ## Do I need this?
45
+
46
+ - If an app's setup tells you to run `python first_run.py`, that script uses
47
+ this helper. Follow the app's instructions.
48
+ - If you are building or packaging an MCP app and need a first-run Python
49
+ check, use this library.
50
+ - If you just want to run an app that is already set up, no.
51
+
52
+ ## What it does
53
+
54
+ 1. Looks for Python 3.14 or newer.
55
+ 2. Looks for a working `.venv` in the project.
56
+ 3. If the Python or the app environment is missing or incomplete, prints a
57
+ JSON report with a `card` and a `next` command. Nothing is downloaded.
58
+ 4. If you agree, the wrapper re-runs with `--install-python`, which installs
59
+ what is missing inside the project.
60
+ 5. Continues setup with that Python.
61
+
62
+ It can also check a Python you name:
63
+
64
+ ```bash
65
+ python first_run.py --python /path/to/python
66
+ ```
67
+
68
+ ## What it will not do
69
+
70
+ - It will not download Python without `--install-python`.
71
+ - It will not change your system Python or system packages.
72
+ - It will not delete an existing `.venv`; a wrong one is moved aside.
73
+ - It will not run `curl | sh`. If `uv` is missing, it prints a tip with the
74
+ official uv installation page and stops. It never runs that tip.
75
+ - It will not run commands through a shell.
76
+ - It masks credential-shaped values in its reports and captured output.
77
+
78
+ ## For developers
79
+
80
+ This repository is a library, not the app. The command-line tool is a
81
+ diagnostic:
82
+
83
+ ```bash
84
+ python -m python_mcp_bootstrap --check
85
+ python -m python_mcp_bootstrap --version
86
+ ```
87
+
88
+ Distribution is GitHub Releases only: install the wheel or sdist from the
89
+ [releases page](https://github.com/4zhmv6zvj2-afk/python-mcp-bootstrap/releases).
90
+ This project is **not published on PyPI**, so `pip install python-mcp-bootstrap`
91
+ does not resolve.
92
+
93
+ Use `BootstrapSpec` and `bootstrap()` from an app's first-run wrapper:
94
+
95
+ ```python
96
+ import sys
97
+ from pathlib import Path
98
+
99
+ from python_mcp_bootstrap import BootstrapSpec, bootstrap
100
+
101
+
102
+ def continue_setup(args: list[str]) -> int:
103
+ # The rest of setup goes here.
104
+ del args
105
+ return 0
106
+
107
+
108
+ root = Path(__file__).resolve().parent
109
+ spec = BootstrapSpec(
110
+ app="example-mcp",
111
+ entrypoint="first_run.py",
112
+ env_var="EXAMPLE_MCP_INTERPRETER",
113
+ install_args=("-e", "."),
114
+ verify_import="example_mcp",
115
+ package_main=continue_setup,
116
+ )
117
+ raise SystemExit(bootstrap(sys.argv[1:], root, spec))
118
+ ```
119
+
120
+ `package_main` is the function `bootstrap()` calls when the current Python is
121
+ already suitable. Pass it: an entry point that calls `bootstrap()`
122
+ unconditionally needs somewhere to continue.
123
+
124
+ The first pass may hand off once, and it records the chosen interpreter in
125
+ `spec.env_var`. A later pass that reaches `bootstrap()` with that variable
126
+ already set and no continuation gets a `missing_continuation` report (exit
127
+ `7`) instead of another exec, so the re-exec loop is gone. A wrapper that
128
+ branches on `spec.env_var` and skips `bootstrap()` after the handoff keeps
129
+ working, which is what the variable is for.
130
+
131
+ `bootstrap()` checks `--python`, the current interpreter, and an existing
132
+ `.venv`, in that order. It only offers to install the pinned Python after
133
+ `--install-python`. An existing `.venv` is also checked with `verify_import`;
134
+ the check runs isolated (`-I -P`), so only that venv's installed packages
135
+ count. If the app or MCP module is missing, the repair card asks for
136
+ `--install-python` before running the installer.
137
+
138
+ `install_args` are consumer-controlled. Path-like entries are rejected when
139
+ the spec is built if they are absolute, Windows-rooted, or contain `..`,
140
+ including attached short-option values (`-t/tmp/x`). Venv-redirecting flags
141
+ (`--target`, `--prefix`, `--root`, `--python` and their short forms) are
142
+ rejected. Non-path flags such as `--index-url` pass through; credentials in
143
+ reports are masked.
144
+
145
+ The core is one stdlib-only file, `core.py`. It must stay importable on Python
146
+ 3.12 because it runs before the app's dependencies are installed; CI runs the
147
+ suite on 3.12 as well as on the supported 3.14 and 3.15 interpreters.
148
+
149
+ ### Vendoring
150
+
151
+ Consumers copy `core.py` and a `VENDOR.json` manifest instead of taking a
152
+ runtime dependency:
153
+
154
+ ```bash
155
+ python scripts/vendor.py \
156
+ --target /path/to/consumer \
157
+ --dest src/example/_vendor/python_mcp_bootstrap.py
158
+ ```
159
+
160
+ Use `--check` to verify a pinned copy. The example app vendors `core.py` into
161
+ `examples/_vendor/` and CI runs the same `vendor.py --check` sequence.
162
+
163
+ - Contract: [docs/contract.md](docs/contract.md)
164
+ - Integration details: [docs/integration.md](docs/integration.md)
165
+ - Example first run: [examples/first_run.py](examples/first_run.py)
166
+ - Changelog: [CHANGELOG.md](CHANGELOG.md)
167
+ - Contributing and release checks: [CONTRIBUTING.md](CONTRIBUTING.md)
168
+
169
+ ## Development
170
+
171
+ Requires Python 3.14+. The development pin is 3.15.2.
172
+
173
+ ```bash
174
+ python3 -m venv .venv
175
+ . .venv/bin/activate
176
+ python -m pip install -e '.[dev]'
177
+ python -m pytest --cov=python_mcp_bootstrap --cov-fail-under=90
178
+ python -m ruff format --check
179
+ python -m ruff check
180
+ python -m mypy
181
+ python -m build
182
+ ```
183
+
184
+ CI targets Python 3.14.10 and 3.15.2 on Ubuntu, macOS, and Windows, plus a 3.12
185
+ compatibility job, a wheel/release gate, and the vendored example first run.
186
+ CI is advisory for now (no required status checks); check the current matrix
187
+ before merging, and treat a pending cell as not green.
188
+
189
+ ## Who maintains this
190
+
191
+ Maintained by Ron as a small single-maintainer project. It exists because
192
+ first-run setup for MCP apps kept re-solving the same problem: make sure a
193
+ supported interpreter is present before the app's dependencies are, without
194
+ touching the system Python.
195
+
196
+ Issues and pull requests are welcome. There is no support SLA. `SECURITY.md`
197
+ lists what the bootstrap does and does not guarantee.
198
+
199
+ ## License
200
+
201
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,176 @@
1
+ # python-mcp-bootstrap
2
+
3
+ A small setup helper for Python apps that use MCP.
4
+
5
+ MCP (Model Context Protocol) is a way for AI assistants to use tools and data.
6
+ Before one of those apps starts, this helper makes sure it runs on a supported
7
+ version of Python. If your computer does not have one, it explains what is
8
+ missing and asks before downloading anything. It never changes the Python that
9
+ is already installed.
10
+
11
+ This is a bootstrap *for* MCP applications, not an MCP implementation. It has
12
+ no runtime dependency on the MCP SDK and never imports one.
13
+
14
+ **Most people do not need to run this directly.** The app's setup script uses
15
+ it. If you are a developer adding it to an app, jump to
16
+ [For developers](#for-developers).
17
+
18
+
19
+ ## Do I need this?
20
+
21
+ - If an app's setup tells you to run `python first_run.py`, that script uses
22
+ this helper. Follow the app's instructions.
23
+ - If you are building or packaging an MCP app and need a first-run Python
24
+ check, use this library.
25
+ - If you just want to run an app that is already set up, no.
26
+
27
+ ## What it does
28
+
29
+ 1. Looks for Python 3.14 or newer.
30
+ 2. Looks for a working `.venv` in the project.
31
+ 3. If the Python or the app environment is missing or incomplete, prints a
32
+ JSON report with a `card` and a `next` command. Nothing is downloaded.
33
+ 4. If you agree, the wrapper re-runs with `--install-python`, which installs
34
+ what is missing inside the project.
35
+ 5. Continues setup with that Python.
36
+
37
+ It can also check a Python you name:
38
+
39
+ ```bash
40
+ python first_run.py --python /path/to/python
41
+ ```
42
+
43
+ ## What it will not do
44
+
45
+ - It will not download Python without `--install-python`.
46
+ - It will not change your system Python or system packages.
47
+ - It will not delete an existing `.venv`; a wrong one is moved aside.
48
+ - It will not run `curl | sh`. If `uv` is missing, it prints a tip with the
49
+ official uv installation page and stops. It never runs that tip.
50
+ - It will not run commands through a shell.
51
+ - It masks credential-shaped values in its reports and captured output.
52
+
53
+ ## For developers
54
+
55
+ This repository is a library, not the app. The command-line tool is a
56
+ diagnostic:
57
+
58
+ ```bash
59
+ python -m python_mcp_bootstrap --check
60
+ python -m python_mcp_bootstrap --version
61
+ ```
62
+
63
+ Distribution is GitHub Releases only: install the wheel or sdist from the
64
+ [releases page](https://github.com/4zhmv6zvj2-afk/python-mcp-bootstrap/releases).
65
+ This project is **not published on PyPI**, so `pip install python-mcp-bootstrap`
66
+ does not resolve.
67
+
68
+ Use `BootstrapSpec` and `bootstrap()` from an app's first-run wrapper:
69
+
70
+ ```python
71
+ import sys
72
+ from pathlib import Path
73
+
74
+ from python_mcp_bootstrap import BootstrapSpec, bootstrap
75
+
76
+
77
+ def continue_setup(args: list[str]) -> int:
78
+ # The rest of setup goes here.
79
+ del args
80
+ return 0
81
+
82
+
83
+ root = Path(__file__).resolve().parent
84
+ spec = BootstrapSpec(
85
+ app="example-mcp",
86
+ entrypoint="first_run.py",
87
+ env_var="EXAMPLE_MCP_INTERPRETER",
88
+ install_args=("-e", "."),
89
+ verify_import="example_mcp",
90
+ package_main=continue_setup,
91
+ )
92
+ raise SystemExit(bootstrap(sys.argv[1:], root, spec))
93
+ ```
94
+
95
+ `package_main` is the function `bootstrap()` calls when the current Python is
96
+ already suitable. Pass it: an entry point that calls `bootstrap()`
97
+ unconditionally needs somewhere to continue.
98
+
99
+ The first pass may hand off once, and it records the chosen interpreter in
100
+ `spec.env_var`. A later pass that reaches `bootstrap()` with that variable
101
+ already set and no continuation gets a `missing_continuation` report (exit
102
+ `7`) instead of another exec, so the re-exec loop is gone. A wrapper that
103
+ branches on `spec.env_var` and skips `bootstrap()` after the handoff keeps
104
+ working, which is what the variable is for.
105
+
106
+ `bootstrap()` checks `--python`, the current interpreter, and an existing
107
+ `.venv`, in that order. It only offers to install the pinned Python after
108
+ `--install-python`. An existing `.venv` is also checked with `verify_import`;
109
+ the check runs isolated (`-I -P`), so only that venv's installed packages
110
+ count. If the app or MCP module is missing, the repair card asks for
111
+ `--install-python` before running the installer.
112
+
113
+ `install_args` are consumer-controlled. Path-like entries are rejected when
114
+ the spec is built if they are absolute, Windows-rooted, or contain `..`,
115
+ including attached short-option values (`-t/tmp/x`). Venv-redirecting flags
116
+ (`--target`, `--prefix`, `--root`, `--python` and their short forms) are
117
+ rejected. Non-path flags such as `--index-url` pass through; credentials in
118
+ reports are masked.
119
+
120
+ The core is one stdlib-only file, `core.py`. It must stay importable on Python
121
+ 3.12 because it runs before the app's dependencies are installed; CI runs the
122
+ suite on 3.12 as well as on the supported 3.14 and 3.15 interpreters.
123
+
124
+ ### Vendoring
125
+
126
+ Consumers copy `core.py` and a `VENDOR.json` manifest instead of taking a
127
+ runtime dependency:
128
+
129
+ ```bash
130
+ python scripts/vendor.py \
131
+ --target /path/to/consumer \
132
+ --dest src/example/_vendor/python_mcp_bootstrap.py
133
+ ```
134
+
135
+ Use `--check` to verify a pinned copy. The example app vendors `core.py` into
136
+ `examples/_vendor/` and CI runs the same `vendor.py --check` sequence.
137
+
138
+ - Contract: [docs/contract.md](docs/contract.md)
139
+ - Integration details: [docs/integration.md](docs/integration.md)
140
+ - Example first run: [examples/first_run.py](examples/first_run.py)
141
+ - Changelog: [CHANGELOG.md](CHANGELOG.md)
142
+ - Contributing and release checks: [CONTRIBUTING.md](CONTRIBUTING.md)
143
+
144
+ ## Development
145
+
146
+ Requires Python 3.14+. The development pin is 3.15.2.
147
+
148
+ ```bash
149
+ python3 -m venv .venv
150
+ . .venv/bin/activate
151
+ python -m pip install -e '.[dev]'
152
+ python -m pytest --cov=python_mcp_bootstrap --cov-fail-under=90
153
+ python -m ruff format --check
154
+ python -m ruff check
155
+ python -m mypy
156
+ python -m build
157
+ ```
158
+
159
+ CI targets Python 3.14.10 and 3.15.2 on Ubuntu, macOS, and Windows, plus a 3.12
160
+ compatibility job, a wheel/release gate, and the vendored example first run.
161
+ CI is advisory for now (no required status checks); check the current matrix
162
+ before merging, and treat a pending cell as not green.
163
+
164
+ ## Who maintains this
165
+
166
+ Maintained by Ron as a small single-maintainer project. It exists because
167
+ first-run setup for MCP apps kept re-solving the same problem: make sure a
168
+ supported interpreter is present before the app's dependencies are, without
169
+ touching the system Python.
170
+
171
+ Issues and pull requests are welcome. There is no support SLA. `SECURITY.md`
172
+ lists what the bootstrap does and does not guarantee.
173
+
174
+ ## License
175
+
176
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,47 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ | Version | Supported |
6
+ |---|---|
7
+ | 0.1.x | yes |
8
+
9
+ ## Reporting
10
+
11
+ Use GitHub's private vulnerability reporting: open the repository's
12
+ **Security** tab and choose **Report a vulnerability**. That goes to the
13
+ maintainers privately and keeps the report out of the public timeline.
14
+
15
+ If that channel is unavailable, open a minimal public issue saying only that
16
+ you have a security report and how to reach you. Do not put credentials,
17
+ tokens, or exploit details in a public issue.
18
+
19
+ ## Bootstrap-specific guarantees
20
+
21
+ - The bootstrap does not download Python unless the caller passes the explicit
22
+ `--install-python` consent flag.
23
+ - The bootstrap never runs `curl | sh`; if uv is missing it returns a human
24
+ `tip` with the official uv installation docs link and stops. That tip is
25
+ never executed.
26
+ - The bootstrap never modifies the system Python or its site-packages.
27
+ - The bootstrap does not use `shell=True` and has no shell executor.
28
+ - A project `.venv` from another interpreter is moved aside, not deleted.
29
+ - Credential-shaped values (URL userinfo on any scheme, key/value fields, and
30
+ Bearer headers) in command arguments and captured output are redacted before
31
+ they enter a report.
32
+ - Project-local paths and path-like `install_args` may not escape the project
33
+ root (absolute, Windows-rooted, and `..` values are rejected before any
34
+ subprocess starts, including attached short flag forms). Venv-redirecting
35
+ flags (`--target`, `--prefix`, `--root`, `--python`) are rejected.
36
+ - Path checks are lexical: they do not resolve symlinks. A symlink inside the
37
+ project can still point outside; the consumer owns that boundary.
38
+ - Concurrent first runs are not supported; there is no lock around the
39
+ `.venv` move or the provisioning steps.
40
+ - `root` is the consumer's project directory and the working directory for
41
+ every step; the bootstrap never works outside it on its own.
42
+ - The `verify_import` check runs in isolated mode (`-I -P`), so the project
43
+ cwd, script directory, and `PYTHONPATH` cannot satisfy it.
44
+ - Release tags are annotated. Tags are unsigned for now. An unsigned tag is not
45
+ a signature; verify release artifacts by digest when that matters.
46
+
47
+ A change that weakens any of these properties requires review before merge.