mcp-trust 0.1.0__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 (86) hide show
  1. mcp_trust-0.1.0/.dockerignore +19 -0
  2. mcp_trust-0.1.0/.github/workflows/ci.yml +25 -0
  3. mcp_trust-0.1.0/.github/workflows/publish.yml +34 -0
  4. mcp_trust-0.1.0/.gitignore +30 -0
  5. mcp_trust-0.1.0/AGENTS.md +89 -0
  6. mcp_trust-0.1.0/DEPLOY-VERCEL.md +92 -0
  7. mcp_trust-0.1.0/DEPLOY-VM.md +223 -0
  8. mcp_trust-0.1.0/Dockerfile.scan +74 -0
  9. mcp_trust-0.1.0/LAUNCH-CATALOG.md +205 -0
  10. mcp_trust-0.1.0/LAUNCH-GATE.md +117 -0
  11. mcp_trust-0.1.0/LAUNCH.md +213 -0
  12. mcp_trust-0.1.0/LICENSE +21 -0
  13. mcp_trust-0.1.0/PKG-INFO +163 -0
  14. mcp_trust-0.1.0/README.md +143 -0
  15. mcp_trust-0.1.0/SPEC.md +129 -0
  16. mcp_trust-0.1.0/deploy/Caddyfile +16 -0
  17. mcp_trust-0.1.0/deploy/backup-sqlite.sh +29 -0
  18. mcp_trust-0.1.0/deploy/launchd/com.d.mcp-trust-refresh.plist +44 -0
  19. mcp_trust-0.1.0/deploy/launchd/install.sh +56 -0
  20. mcp_trust-0.1.0/deploy/launchd/uninstall.sh +11 -0
  21. mcp_trust-0.1.0/deploy/mcp-trust-backup.service +10 -0
  22. mcp_trust-0.1.0/deploy/mcp-trust-backup.timer +10 -0
  23. mcp_trust-0.1.0/deploy/mcp-trust.env.example +16 -0
  24. mcp_trust-0.1.0/deploy/mcp-trust.service +23 -0
  25. mcp_trust-0.1.0/deploy/smoke-readonly.sh +40 -0
  26. mcp_trust-0.1.0/deploy/vercel.json +26 -0
  27. mcp_trust-0.1.0/pyproject.toml +44 -0
  28. mcp_trust-0.1.0/scripts/build_deploy_bundle.py +210 -0
  29. mcp_trust-0.1.0/scripts/build_site.py +172 -0
  30. mcp_trust-0.1.0/scripts/build_snapshot.py +101 -0
  31. mcp_trust-0.1.0/scripts/corpus_scan.py +93 -0
  32. mcp_trust-0.1.0/scripts/plan_reference_scans.py +50 -0
  33. mcp_trust-0.1.0/scripts/reference_scan_plan.py +306 -0
  34. mcp_trust-0.1.0/scripts/refresh_and_publish.sh +88 -0
  35. mcp_trust-0.1.0/scripts/scan_real.py +44 -0
  36. mcp_trust-0.1.0/scripts/validate_launch_state.py +187 -0
  37. mcp_trust-0.1.0/server.json +22 -0
  38. mcp_trust-0.1.0/src/mcp_trust/__init__.py +3 -0
  39. mcp_trust-0.1.0/src/mcp_trust/api/__init__.py +1 -0
  40. mcp_trust-0.1.0/src/mcp_trust/api/app.py +308 -0
  41. mcp_trust-0.1.0/src/mcp_trust/api/web.py +527 -0
  42. mcp_trust-0.1.0/src/mcp_trust/catalog/__init__.py +1 -0
  43. mcp_trust-0.1.0/src/mcp_trust/catalog/seed.py +54 -0
  44. mcp_trust-0.1.0/src/mcp_trust/catalog/seed_servers.json +222 -0
  45. mcp_trust-0.1.0/src/mcp_trust/catalog_snapshot.json +2373 -0
  46. mcp_trust-0.1.0/src/mcp_trust/cli/__init__.py +1 -0
  47. mcp_trust-0.1.0/src/mcp_trust/cli/main.py +249 -0
  48. mcp_trust-0.1.0/src/mcp_trust/core/__init__.py +1 -0
  49. mcp_trust-0.1.0/src/mcp_trust/core/grading.py +118 -0
  50. mcp_trust-0.1.0/src/mcp_trust/core/models.py +158 -0
  51. mcp_trust-0.1.0/src/mcp_trust/core/provenance.py +59 -0
  52. mcp_trust-0.1.0/src/mcp_trust/engine/__init__.py +1 -0
  53. mcp_trust-0.1.0/src/mcp_trust/engine/base.py +50 -0
  54. mcp_trust-0.1.0/src/mcp_trust/engine/credentials.py +57 -0
  55. mcp_trust-0.1.0/src/mcp_trust/engine/factory.py +32 -0
  56. mcp_trust-0.1.0/src/mcp_trust/engine/mcpaudit.py +296 -0
  57. mcp_trust-0.1.0/src/mcp_trust/engine/sandbox.py +144 -0
  58. mcp_trust-0.1.0/src/mcp_trust/engine/stub.py +157 -0
  59. mcp_trust-0.1.0/src/mcp_trust/mcp_server.py +122 -0
  60. mcp_trust-0.1.0/src/mcp_trust/receipts.py +102 -0
  61. mcp_trust-0.1.0/src/mcp_trust/site/__init__.py +8 -0
  62. mcp_trust-0.1.0/src/mcp_trust/site/badges.py +47 -0
  63. mcp_trust-0.1.0/src/mcp_trust/site/generator.py +154 -0
  64. mcp_trust-0.1.0/src/mcp_trust/store/__init__.py +1 -0
  65. mcp_trust-0.1.0/src/mcp_trust/store/db.py +52 -0
  66. mcp_trust-0.1.0/src/mcp_trust/store/repository.py +182 -0
  67. mcp_trust-0.1.0/tests/__init__.py +0 -0
  68. mcp_trust-0.1.0/tests/test_api.py +320 -0
  69. mcp_trust-0.1.0/tests/test_build_site_script.py +67 -0
  70. mcp_trust-0.1.0/tests/test_build_snapshot.py +72 -0
  71. mcp_trust-0.1.0/tests/test_cli.py +214 -0
  72. mcp_trust-0.1.0/tests/test_credentialed_scan.py +233 -0
  73. mcp_trust-0.1.0/tests/test_deploy_bundle_builder.py +148 -0
  74. mcp_trust-0.1.0/tests/test_grading.py +94 -0
  75. mcp_trust-0.1.0/tests/test_launch_state_validator.py +181 -0
  76. mcp_trust-0.1.0/tests/test_mcp_server.py +58 -0
  77. mcp_trust-0.1.0/tests/test_mcpaudit_adapter.py +85 -0
  78. mcp_trust-0.1.0/tests/test_models.py +51 -0
  79. mcp_trust-0.1.0/tests/test_provenance.py +91 -0
  80. mcp_trust-0.1.0/tests/test_reference_scan_plan.py +76 -0
  81. mcp_trust-0.1.0/tests/test_sandbox.py +84 -0
  82. mcp_trust-0.1.0/tests/test_site_generator.py +319 -0
  83. mcp_trust-0.1.0/tests/test_store.py +260 -0
  84. mcp_trust-0.1.0/tests/test_stub_engine.py +98 -0
  85. mcp_trust-0.1.0/tests/test_web.py +195 -0
  86. mcp_trust-0.1.0/uv.lock +980 -0
@@ -0,0 +1,19 @@
1
+ # Dockerfile.scan copies nothing from the build context (only the uv binaries
2
+ # from a build stage), so none of this would reach the image anyway — but keep
3
+ # the context small and never hand the local registry DB / receipts to the
4
+ # Docker daemon.
5
+ .venv/
6
+ .git/
7
+ registry.db
8
+ *.db
9
+ receipts/
10
+ site/
11
+ __pycache__/
12
+ *.pyc
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+ .serena/
17
+ node_modules/
18
+ dist/
19
+ build/
@@ -0,0 +1,25 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v5
17
+
18
+ - name: Set up Python
19
+ run: uv python install 3.11
20
+
21
+ - name: Install dependencies
22
+ run: uv sync --frozen --extra dev
23
+
24
+ - name: Run tests
25
+ run: uv run pytest -q
@@ -0,0 +1,34 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ name: Build and publish to PyPI
11
+ runs-on: ubuntu-latest
12
+ environment: pypi
13
+ permissions:
14
+ contents: read # checkout needs read on this (private) repo
15
+ id-token: write # OIDC trusted publishing
16
+
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+
20
+ - uses: astral-sh/setup-uv@v7
21
+ with:
22
+ python-version: "3.11"
23
+
24
+ # Gate the release on the test suite: a broken tag must not publish.
25
+ - name: Test gate
26
+ run: uv run --extra dev pytest -q
27
+
28
+ - name: Build wheel and sdist
29
+ run: uv build
30
+
31
+ - name: Publish to PyPI
32
+ uses: pypa/gh-action-pypi-publish@release/v1
33
+ with:
34
+ packages-dir: dist/
@@ -0,0 +1,30 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ *.db
11
+ *.sqlite3
12
+ .env
13
+ receipts/
14
+
15
+ # generated static-site output (build artifact)
16
+ /site/
17
+
18
+ # serena language-server project cache
19
+ .serena/
20
+
21
+ # sandbox/worktree build-cache symlinks
22
+ .build
23
+ .cargo
24
+ .next
25
+ dist/
26
+ node_modules/
27
+ target/
28
+
29
+ # agent worktree dir
30
+ .claude/
@@ -0,0 +1,89 @@
1
+ # AGENTS.md — MCP Trust Registry
2
+
3
+ ## Project Summary
4
+ MCP Trust Registry is a neutral public trust registry for MCP servers. Its product
5
+ loop is "check before you connect": register public MCP servers, scan them with a
6
+ pluggable engine, normalize the results into an A-F danger grade plus transparency
7
+ signal, persist the record, and serve it through a public API, web catalog, and
8
+ README badge endpoint.
9
+
10
+ This repo is not trying to win by being another scanner. The scanner is a
11
+ replaceable backend; the durable layer is the public catalog, stable lookup API,
12
+ trust-grade normalization, and author badge distribution loop. The current real
13
+ engine adapter wraps `mcp-audits`, while the default `StubEngine` keeps the full
14
+ system testable without launching untrusted code.
15
+
16
+ ## Current State
17
+ The MVP is built and tested end to end: seed catalog, scan, grade, persist,
18
+ serve JSON and web views, and emit shields.io-compatible badge JSON. The repo is
19
+ currently private/pre-launch. The seed catalog now contains official reference
20
+ MCP servers for launch calibration. Public launch is gated by validating
21
+ sandboxed real-engine scans, inspecting the grade distribution, deciding whether
22
+ to broaden beyond reference servers, deploying the FastAPI app with persistent
23
+ SQLite storage, and smoke-testing the badge loop against the public base URL.
24
+
25
+ ## Stack
26
+ - Python 3.11+
27
+ - FastAPI and Uvicorn for the API/web surface
28
+ - Typer for the CLI
29
+ - Pydantic domain models
30
+ - SQLite persistence
31
+ - Pytest and Ruff for local verification
32
+ - Optional `mcp-audits` engine extra for real MCP-server scanning
33
+
34
+ ## How To Run
35
+ Install and run the deterministic local path:
36
+
37
+ ```bash
38
+ uv venv .venv
39
+ . .venv/bin/activate
40
+ uv pip install -e ".[dev]"
41
+ python -m pytest -q
42
+ ruff check src tests
43
+ mcp-trust seed
44
+ mcp-trust scan mcp-reference-time
45
+ mcp-trust check mcp-reference-time
46
+ mcp-trust serve
47
+ ```
48
+
49
+ Run the real engine only when the target server is trusted or sandboxed:
50
+
51
+ ```bash
52
+ uv pip install -e ".[dev,engine]"
53
+ MCP_TRUST_ENGINE=mcpaudit mcp-trust scan mcp-reference-time
54
+ MCP_TRUST_ENGINE=mcpaudit MCP_TRUST_SANDBOX=docker mcp-trust scan mcp-reference-time
55
+ ```
56
+
57
+ Use `LAUNCH.md` as the public-launch runbook. Use `SPEC.md` as the product and
58
+ module-boundary contract.
59
+
60
+ ## Known Risks
61
+ - Real scans launch server processes. Never scan untrusted servers without an
62
+ isolation decision; prefer `MCP_TRUST_SANDBOX=docker` and a purpose-built
63
+ image for public catalog scans.
64
+ - API scan triggering with the real `mcpaudit` engine is operator-gated by
65
+ `MCP_TRUST_SCAN_TOKEN`; public callers must not be able to launch scans.
66
+ - The current seed catalog contains official reference servers. Public grades
67
+ are not meaningful until real sandbox scans run and grading bands are checked
68
+ against that distribution.
69
+ - Low-transparency servers can look risky because annotations are missing; keep
70
+ danger grade and transparency as separate signals instead of collapsing them
71
+ into one overconfident verdict.
72
+ - Public launch is a one-way trust event. Do not make the repository public or
73
+ send author-badge outreach until the live catalog, sandbox path, deployment,
74
+ and smoke tests are green.
75
+
76
+ ## Next Recommended Move
77
+ Start Docker/Colima, build `Dockerfile.scan`, run one sandboxed `mcp-audits`
78
+ smoke scan against `mcp-reference-time`, then run the full reference corpus,
79
+ inspect the resulting grade distribution, recalibrate bands if needed, and
80
+ deploy the API with persistent SQLite storage for a live badge-loop smoke test.
81
+
82
+ ## Agent Operating Notes
83
+ - Keep `core/` and `engine/base.py` contracts stable unless the spec is updated
84
+ first.
85
+ - Do not put secrets or environment values in server source specs; `env_keys`
86
+ are names only.
87
+ - Prefer adding tests beside the module being changed.
88
+ - Treat scanner behavior, grading changes, and public-launch steps as
89
+ high-trust-surface changes that require explicit verification.
@@ -0,0 +1,92 @@
1
+ # Deploy: static catalog → Vercel
2
+
3
+ Low-ops launch path: render the catalog to static HTML/JSON **locally**, then
4
+ deploy the rendered output to Vercel. This is the alternative to the always-on
5
+ VM service documented in `DEPLOY-VM.md`.
6
+
7
+ ## Why build locally (not on Vercel)
8
+
9
+ The site is generated from `registry.db`, which holds scan data and is **never
10
+ committed** (`.gitignore`). So Vercel cannot build from a fresh `git clone`.
11
+ Instead, the build runs where the data lives (your machine or a scheduled job),
12
+ and only the **public-safe rendered output** (`site/`) is uploaded. The raw scan
13
+ database and receipts stay local. Freshness comes from re-running the build on a
14
+ schedule (see `Scheduled freshness`), not from Vercel's Git integration.
15
+
16
+ ## Prerequisites
17
+
18
+ - The Vercel CLI is installed and you are logged in (`vercel login`).
19
+ - A Vercel project exists (or accept the prompts on first `vercel` run).
20
+ - A domain you control, to set `--base-url` (badge embeds resolve against it).
21
+
22
+ ## 1. Build the static site from real data
23
+
24
+ `DOMAIN` must be the final public URL so README badge-embed snippets point at the
25
+ live host. The build is read-only against `registry.db`; it never scans.
26
+
27
+ ```bash
28
+ DOMAIN="https://<your-domain>"
29
+ uv run python scripts/build_site.py \
30
+ --db ./registry.db \
31
+ --out site \
32
+ --base-url "$DOMAIN"
33
+ # Expect: "Built static site for 7 server(s) (7 scanned) ... VERIFY OK"
34
+ ```
35
+
36
+ Ship the deploy config with the rendered output so headers/CSP/clean-URLs apply:
37
+
38
+ ```bash
39
+ cp deploy/vercel.json site/vercel.json
40
+ ```
41
+
42
+ ## 2. Preview deploy (no production traffic)
43
+
44
+ ```bash
45
+ vercel deploy site # prints a preview URL
46
+ ```
47
+
48
+ Open the preview URL and confirm, on the real grades:
49
+
50
+ - Catalog (`/`) lists all 7 servers with A–F grades and **no `DEMO DATA` banner**
51
+ (real scans → no demo label).
52
+ - A detail page (`/ui/servers/mcp-reference-filesystem`) renders the grade,
53
+ transparency, findings, and the badge-embed snippet.
54
+ - `/servers/mcp-reference-time/badge.json` returns a shields.io endpoint payload
55
+ (`"message": "A"`, no `(demo)` suffix).
56
+ - An unknown path (e.g. `/nope`) serves the 404 page.
57
+
58
+ ## 3. Production deploy (operator action — public)
59
+
60
+ ```bash
61
+ vercel deploy site --prod # promotes to the production domain
62
+ ```
63
+
64
+ Then point your domain at the Vercel project (Vercel dashboard → Domains) and
65
+ re-run the badge check against the production URL.
66
+
67
+ ## 4. Scheduled freshness
68
+
69
+ `scripts/refresh_and_publish.sh` runs the whole loop: re-scan the corpus in the
70
+ network-off Docker sandbox, rebuild the site, and (only if `MCP_TRUST_AUTO_DEPLOY=1`)
71
+ deploy. Install it as a weekly launchd job:
72
+
73
+ ```bash
74
+ bash deploy/launchd/install.sh # weekly, Monday 09:00; deploy OFF by default
75
+ launchctl start com.d.mcp-trust-refresh # force one run to test
76
+ bash deploy/launchd/uninstall.sh # remove the job
77
+ ```
78
+
79
+ Deploy is opt-in: in the installed plist
80
+ (`~/Library/LaunchAgents/com.d.mcp-trust-refresh.plist`) set
81
+ `MCP_TRUST_SITE_BASE_URL` to your real domain and add `MCP_TRUST_AUTO_DEPLOY=1`,
82
+ then re-run the install script. Re-scanning a version-pinned image is
83
+ deterministic; to catch upstream drift, periodically rebuild `Dockerfile.scan`
84
+ with current server versions.
85
+
86
+ ## Safety notes
87
+
88
+ - `registry.db` and `receipts/` are **never** uploaded — only `site/`.
89
+ - The static site is read-only; there is no scan-trigger endpoint to protect
90
+ (unlike the VM service). Re-scans happen locally, behind the sandbox.
91
+ - Grades are honest by construction: stub/demo data carries a loud banner and
92
+ `(demo)`-suffixed badges; only real `mcpaudit` scans render bare grades.
@@ -0,0 +1,223 @@
1
+ # MCP Trust VM Deployment Package
2
+
3
+ This is the v1 deployment lane: one controlled VM/VPS, a read-only public app,
4
+ operator-run Docker scans, persistent SQLite, durable receipts, and nightly
5
+ backups.
6
+
7
+ Public traffic must never launch an MCP server. The public service runs with
8
+ `MCP_TRUST_PUBLIC_READONLY=1`.
9
+
10
+ ## Target Layout
11
+
12
+ ```text
13
+ /opt/mcp-trust/app
14
+ /etc/mcp-trust/mcp-trust.env
15
+ /data/mcp-trust/registry.db
16
+ /data/mcp-trust/receipts/
17
+ /data/mcp-trust/backups/
18
+ /var/log/mcp-trust/
19
+ ```
20
+
21
+ ## VM Baseline
22
+
23
+ Use a small Ubuntu VM with Docker, Caddy, Git, `uv`, and SQLite:
24
+
25
+ ```bash
26
+ sudo apt-get update
27
+ sudo apt-get install -y ca-certificates curl git sqlite3 caddy
28
+
29
+ curl -LsSf https://astral.sh/uv/install.sh | sh
30
+
31
+ sudo install -d -m 0755 /opt/mcp-trust /etc/mcp-trust /data/mcp-trust/receipts /data/mcp-trust/backups /var/log/mcp-trust
32
+ sudo useradd --system --home /opt/mcp-trust --shell /usr/sbin/nologin mcp-trust || true
33
+ sudo chown -R mcp-trust:mcp-trust /opt/mcp-trust /data/mcp-trust /var/log/mcp-trust
34
+ ```
35
+
36
+ Install Docker Engine using Docker's official Ubuntu instructions, then confirm:
37
+
38
+ ```bash
39
+ docker info
40
+ ```
41
+
42
+ ## App Install
43
+
44
+ Clone or copy the repo into `/opt/mcp-trust/app`, then install into a venv:
45
+
46
+ ```bash
47
+ cd /opt/mcp-trust/app
48
+ uv venv .venv
49
+ . .venv/bin/activate
50
+ uv pip install -e ".[engine]"
51
+ ```
52
+
53
+ Copy the env file and keep it secret-owned:
54
+
55
+ ```bash
56
+ sudo cp deploy/mcp-trust.env.example /etc/mcp-trust/mcp-trust.env
57
+ sudo chown root:mcp-trust /etc/mcp-trust/mcp-trust.env
58
+ sudo chmod 0640 /etc/mcp-trust/mcp-trust.env
59
+ ```
60
+
61
+ Required public env:
62
+
63
+ ```bash
64
+ MCP_TRUST_DB=/data/mcp-trust/registry.db
65
+ MCP_TRUST_ENGINE=mcpaudit
66
+ MCP_TRUST_PUBLIC_READONLY=1
67
+ ```
68
+
69
+ Do not set `MCP_TRUST_ALLOW_UNAUTHENTICATED_STUB_SCANS` on the VM.
70
+
71
+ ## Seed Data And Receipts
72
+
73
+ Build a sanitized transfer bundle from the workstation after scans pass:
74
+
75
+ ```bash
76
+ python scripts/build_deploy_bundle.py \
77
+ --db ./registry.db \
78
+ --receipts-dir ./receipts
79
+ ```
80
+
81
+ Upload the resulting `dist/mcp-trust-deploy-bundle-*.tar.gz` to the VM, extract
82
+ it, and copy its contents into `/data/mcp-trust/`:
83
+
84
+ ```bash
85
+ tar -xzf mcp-trust-deploy-bundle-*.tar.gz
86
+ sudo install -m 0644 mcp-trust-deploy-bundle-*/registry.db /data/mcp-trust/registry.db
87
+ sudo rsync -a --delete mcp-trust-deploy-bundle-*/receipts/ /data/mcp-trust/receipts/
88
+ sudo chown -R mcp-trust:mcp-trust /data/mcp-trust
89
+ ```
90
+
91
+ The bundle DB contains only latest scan rows, so historical local rehearsal rows
92
+ and absolute local receipt paths are not copied to the VM.
93
+
94
+ For a fresh VM rehearsal that scans directly on the VM, use the operator shell:
95
+
96
+ ```bash
97
+ cd /opt/mcp-trust/app
98
+ export MCP_TRUST_DB=/data/mcp-trust/registry.db
99
+ export MCP_TRUST_RECEIPTS_DIR=/data/mcp-trust/receipts
100
+ export MCP_TRUST_ENGINE=mcpaudit
101
+ export MCP_TRUST_SANDBOX=docker
102
+ export MCP_TRUST_SANDBOX_NETWORK=none
103
+ export MCP_TRUST_SANDBOX_IMAGE=mcp-trust-scan:reference-2026-06-19
104
+
105
+ .venv/bin/mcp-trust seed
106
+ docker build -f Dockerfile.scan -t mcp-trust-scan:reference-2026-06-19 .
107
+ .venv/bin/mcp-trust scan mcp-reference-time
108
+ python scripts/validate_launch_state.py \
109
+ --db /data/mcp-trust/registry.db \
110
+ --receipts-dir /data/mcp-trust/receipts
111
+ ```
112
+
113
+ Run additional approved scans only after the candidate/source/sandbox decision
114
+ is recorded in `LAUNCH-CATALOG.md`.
115
+
116
+ ## Systemd Service
117
+
118
+ Install and start the read-only API service:
119
+
120
+ ```bash
121
+ sudo cp deploy/mcp-trust.service /etc/systemd/system/mcp-trust.service
122
+ sudo systemctl daemon-reload
123
+ sudo systemctl enable --now mcp-trust.service
124
+ sudo systemctl status mcp-trust.service
125
+ ```
126
+
127
+ The service binds to `127.0.0.1:8000`. It should not be reachable directly from
128
+ the public internet.
129
+
130
+ ## Caddy Reverse Proxy
131
+
132
+ Edit `deploy/Caddyfile` and replace:
133
+
134
+ - `admin@example.com`
135
+ - `mcptrust.example.com`
136
+
137
+ Then install it:
138
+
139
+ ```bash
140
+ sudo cp deploy/Caddyfile /etc/caddy/Caddyfile
141
+ sudo caddy validate --config /etc/caddy/Caddyfile
142
+ sudo systemctl reload caddy
143
+ ```
144
+
145
+ ## Nightly Backups
146
+
147
+ Install the backup units:
148
+
149
+ ```bash
150
+ sudo cp deploy/mcp-trust-backup.service /etc/systemd/system/mcp-trust-backup.service
151
+ sudo cp deploy/mcp-trust-backup.timer /etc/systemd/system/mcp-trust-backup.timer
152
+ sudo systemctl daemon-reload
153
+ sudo systemctl enable --now mcp-trust-backup.timer
154
+ sudo systemctl start mcp-trust-backup.service
155
+ sudo systemctl status mcp-trust-backup.service
156
+ ```
157
+
158
+ The backup script writes:
159
+
160
+ ```text
161
+ /data/mcp-trust/backups/registry-<timestamp>.db
162
+ /data/mcp-trust/backups/receipts-<timestamp>.tar.gz
163
+ ```
164
+
165
+ After the first backup, copy at least one DB backup and one receipt tarball
166
+ off-box.
167
+
168
+ ## Read-Only Smoke
169
+
170
+ Run this from the VM or your workstation after DNS/HTTPS is live:
171
+
172
+ ```bash
173
+ BASE_URL=https://mcptrust.example.com SLUG=mcp-reference-time ./deploy/smoke-readonly.sh
174
+ ```
175
+
176
+ Before the smoke, run the offline state verifier on the VM:
177
+
178
+ ```bash
179
+ python scripts/validate_launch_state.py \
180
+ --db /data/mcp-trust/registry.db \
181
+ --receipts-dir /data/mcp-trust/receipts
182
+ ```
183
+
184
+ Manual checks:
185
+
186
+ ```bash
187
+ curl -s "$BASE_URL/healthz"
188
+ curl -s "$BASE_URL/servers" | head
189
+ open "$BASE_URL/"
190
+ open "$BASE_URL/ui/servers/mcp-reference-time"
191
+ curl -s "$BASE_URL/servers/mcp-reference-time/badge.json"
192
+ curl -i -X POST "$BASE_URL/servers/mcp-reference-time/scan"
193
+ ```
194
+
195
+ Expected `POST /scan` result: `403 Forbidden`.
196
+
197
+ ## Rollback
198
+
199
+ Use the last known-good git checkout plus the last known-good DB backup:
200
+
201
+ ```bash
202
+ sudo systemctl stop mcp-trust.service
203
+ sudo cp /data/mcp-trust/backups/registry-<timestamp>.db /data/mcp-trust/registry.db
204
+ sudo chown mcp-trust:mcp-trust /data/mcp-trust/registry.db
205
+ cd /opt/mcp-trust/app
206
+ git checkout <known-good-ref>
207
+ . .venv/bin/activate
208
+ uv pip install -e ".[engine]"
209
+ sudo systemctl start mcp-trust.service
210
+ ```
211
+
212
+ Then rerun the read-only smoke.
213
+
214
+ ## Launch Gate
215
+
216
+ Do not make the repo/site public until:
217
+
218
+ - `systemctl status mcp-trust.service` is healthy.
219
+ - Caddy serves HTTPS for the final domain.
220
+ - `deploy/smoke-readonly.sh` passes against the public base URL.
221
+ - `POST /servers/<slug>/scan` returns 403 publicly.
222
+ - At least one backup has been created and copied off-box.
223
+ - `LAUNCH-GATE.md` is updated with deployed evidence.
@@ -0,0 +1,74 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ # Purpose-built image for approval-gated, network-off reference scans.
4
+ # Build only after the sandbox decision is approved:
5
+ # docker build -f Dockerfile.scan -t mcp-trust-scan:corpus-2026-06-27 .
6
+ #
7
+ # Reference-server versions are pinned (metadata observed 2026-06-19); the
8
+ # archived official servers added for corpus expansion are unpinned because
9
+ # their releases are frozen (the repos are archived, no new versions ship).
10
+ # Scan-time execution should use MCP_TRUST_SANDBOX_NETWORK=none.
11
+
12
+ FROM ghcr.io/astral-sh/uv:0.8.15 AS uv
13
+ FROM node:22-slim
14
+
15
+ ARG SERVER_EVERYTHING_VERSION=2026.1.26
16
+ ARG SERVER_FILESYSTEM_VERSION=2026.1.14
17
+ ARG SERVER_MEMORY_VERSION=2026.1.26
18
+ ARG SERVER_SEQUENTIAL_THINKING_VERSION=2025.12.18
19
+ ARG SERVER_FETCH_VERSION=2026.6.4
20
+ ARG SERVER_GIT_VERSION=2026.6.16
21
+ ARG SERVER_TIME_VERSION=2026.6.4
22
+
23
+ ENV UV_TOOL_DIR=/opt/uv-tools
24
+ ENV UV_TOOL_BIN_DIR=/usr/local/bin
25
+
26
+ COPY --from=uv /uv /uvx /usr/local/bin/
27
+
28
+ RUN apt-get update \
29
+ && apt-get install -y --no-install-recommends ca-certificates git python3 \
30
+ && rm -rf /var/lib/apt/lists/*
31
+
32
+ RUN npm install --global \
33
+ "@modelcontextprotocol/server-everything@${SERVER_EVERYTHING_VERSION}" \
34
+ "@modelcontextprotocol/server-filesystem@${SERVER_FILESYSTEM_VERSION}" \
35
+ "@modelcontextprotocol/server-memory@${SERVER_MEMORY_VERSION}" \
36
+ "@modelcontextprotocol/server-sequential-thinking@${SERVER_SEQUENTIAL_THINKING_VERSION}"
37
+
38
+ RUN uv tool install --python python3 "mcp-server-fetch==${SERVER_FETCH_VERSION}" \
39
+ && uv tool install --python python3 "mcp-server-git==${SERVER_GIT_VERSION}" \
40
+ && uv tool install --python python3 "mcp-server-time==${SERVER_TIME_VERSION}"
41
+
42
+ # --- Archived official reference servers (corpus expansion 2026-06-27) ---
43
+ # Moved to modelcontextprotocol/servers-archived and no longer maintained.
44
+ # Baked because the sandbox blocks registry fetches at scan time (`npx -y` /
45
+ # `uvx` would fail without a pre-installed binary). npm archived releases are
46
+ # frozen so they're unpinned; mcp-server-sqlite is pinned because PyPI is mutable.
47
+ #
48
+ # github, aws-kb-retrieval, sqlite enumerate network-off with NO credentials.
49
+ RUN npm install --global \
50
+ "@modelcontextprotocol/server-github" \
51
+ "@modelcontextprotocol/server-aws-kb-retrieval"
52
+
53
+ RUN uv tool install --python python3 "mcp-server-sqlite==2025.4.25"
54
+
55
+ # --- Credentialed-sandboxed archived servers (corpus expansion 2026-06-28) ---
56
+ # Token/API-key gated. Now baked so the credentialed-sandboxed scan mode
57
+ # (MCP_TRUST_SCAN_CREDENTIALS=dummy) can launch them network-off with
58
+ # non-functional dummy values and enumerate their real tool surface.
59
+ RUN npm install --global \
60
+ "@modelcontextprotocol/server-gitlab" \
61
+ "@modelcontextprotocol/server-slack" \
62
+ "@modelcontextprotocol/server-brave-search" \
63
+ "@modelcontextprotocol/server-google-maps" \
64
+ "@modelcontextprotocol/server-everart"
65
+
66
+ RUN mkdir -p /fixtures/repo \
67
+ && git init /fixtures/repo \
68
+ && git -C /fixtures/repo config user.email "scan-fixture@example.invalid" \
69
+ && git -C /fixtures/repo config user.name "MCP Trust Scan Fixture" \
70
+ && printf "fixture repo for mcp-trust reference scans\n" > /fixtures/repo/README.md \
71
+ && git -C /fixtures/repo add README.md \
72
+ && git -C /fixtures/repo commit -m "Add scan fixture"
73
+
74
+ WORKDIR /scan