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.
- python_mcp_bootstrap-0.1.3/.gitignore +44 -0
- python_mcp_bootstrap-0.1.3/CHANGELOG.md +87 -0
- python_mcp_bootstrap-0.1.3/CONTRIBUTING.md +94 -0
- python_mcp_bootstrap-0.1.3/LICENSE +21 -0
- python_mcp_bootstrap-0.1.3/PKG-INFO +201 -0
- python_mcp_bootstrap-0.1.3/README.md +176 -0
- python_mcp_bootstrap-0.1.3/SECURITY.md +47 -0
- python_mcp_bootstrap-0.1.3/docs/contract.md +123 -0
- python_mcp_bootstrap-0.1.3/docs/integration.md +95 -0
- python_mcp_bootstrap-0.1.3/docs/releases/0.1.0.md +62 -0
- python_mcp_bootstrap-0.1.3/docs/releases/0.1.1.md +58 -0
- python_mcp_bootstrap-0.1.3/docs/releases/0.1.2.md +83 -0
- python_mcp_bootstrap-0.1.3/docs/releases/0.1.3.md +81 -0
- python_mcp_bootstrap-0.1.3/examples/README.md +21 -0
- python_mcp_bootstrap-0.1.3/examples/example_mcp/__init__.py +3 -0
- python_mcp_bootstrap-0.1.3/examples/first_run.py +49 -0
- python_mcp_bootstrap-0.1.3/examples/pyproject.toml +13 -0
- python_mcp_bootstrap-0.1.3/pyproject.toml +91 -0
- python_mcp_bootstrap-0.1.3/scripts/__init__.py +0 -0
- python_mcp_bootstrap-0.1.3/scripts/release_check.py +205 -0
- python_mcp_bootstrap-0.1.3/scripts/vendor.py +210 -0
- python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/__init__.py +58 -0
- python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/__main__.py +8 -0
- python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/cli.py +57 -0
- python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/core.py +729 -0
- python_mcp_bootstrap-0.1.3/src/python_mcp_bootstrap/py.typed +0 -0
- python_mcp_bootstrap-0.1.3/tests/test_bootstrap.py +1036 -0
- python_mcp_bootstrap-0.1.3/tests/test_cli.py +44 -0
- python_mcp_bootstrap-0.1.3/tests/test_core.py +355 -0
- python_mcp_bootstrap-0.1.3/tests/test_examples.py +27 -0
- python_mcp_bootstrap-0.1.3/tests/test_package.py +18 -0
- python_mcp_bootstrap-0.1.3/tests/test_release_check.py +121 -0
- 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.
|