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.
- mcp_trust-0.1.0/.dockerignore +19 -0
- mcp_trust-0.1.0/.github/workflows/ci.yml +25 -0
- mcp_trust-0.1.0/.github/workflows/publish.yml +34 -0
- mcp_trust-0.1.0/.gitignore +30 -0
- mcp_trust-0.1.0/AGENTS.md +89 -0
- mcp_trust-0.1.0/DEPLOY-VERCEL.md +92 -0
- mcp_trust-0.1.0/DEPLOY-VM.md +223 -0
- mcp_trust-0.1.0/Dockerfile.scan +74 -0
- mcp_trust-0.1.0/LAUNCH-CATALOG.md +205 -0
- mcp_trust-0.1.0/LAUNCH-GATE.md +117 -0
- mcp_trust-0.1.0/LAUNCH.md +213 -0
- mcp_trust-0.1.0/LICENSE +21 -0
- mcp_trust-0.1.0/PKG-INFO +163 -0
- mcp_trust-0.1.0/README.md +143 -0
- mcp_trust-0.1.0/SPEC.md +129 -0
- mcp_trust-0.1.0/deploy/Caddyfile +16 -0
- mcp_trust-0.1.0/deploy/backup-sqlite.sh +29 -0
- mcp_trust-0.1.0/deploy/launchd/com.d.mcp-trust-refresh.plist +44 -0
- mcp_trust-0.1.0/deploy/launchd/install.sh +56 -0
- mcp_trust-0.1.0/deploy/launchd/uninstall.sh +11 -0
- mcp_trust-0.1.0/deploy/mcp-trust-backup.service +10 -0
- mcp_trust-0.1.0/deploy/mcp-trust-backup.timer +10 -0
- mcp_trust-0.1.0/deploy/mcp-trust.env.example +16 -0
- mcp_trust-0.1.0/deploy/mcp-trust.service +23 -0
- mcp_trust-0.1.0/deploy/smoke-readonly.sh +40 -0
- mcp_trust-0.1.0/deploy/vercel.json +26 -0
- mcp_trust-0.1.0/pyproject.toml +44 -0
- mcp_trust-0.1.0/scripts/build_deploy_bundle.py +210 -0
- mcp_trust-0.1.0/scripts/build_site.py +172 -0
- mcp_trust-0.1.0/scripts/build_snapshot.py +101 -0
- mcp_trust-0.1.0/scripts/corpus_scan.py +93 -0
- mcp_trust-0.1.0/scripts/plan_reference_scans.py +50 -0
- mcp_trust-0.1.0/scripts/reference_scan_plan.py +306 -0
- mcp_trust-0.1.0/scripts/refresh_and_publish.sh +88 -0
- mcp_trust-0.1.0/scripts/scan_real.py +44 -0
- mcp_trust-0.1.0/scripts/validate_launch_state.py +187 -0
- mcp_trust-0.1.0/server.json +22 -0
- mcp_trust-0.1.0/src/mcp_trust/__init__.py +3 -0
- mcp_trust-0.1.0/src/mcp_trust/api/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/api/app.py +308 -0
- mcp_trust-0.1.0/src/mcp_trust/api/web.py +527 -0
- mcp_trust-0.1.0/src/mcp_trust/catalog/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/catalog/seed.py +54 -0
- mcp_trust-0.1.0/src/mcp_trust/catalog/seed_servers.json +222 -0
- mcp_trust-0.1.0/src/mcp_trust/catalog_snapshot.json +2373 -0
- mcp_trust-0.1.0/src/mcp_trust/cli/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/cli/main.py +249 -0
- mcp_trust-0.1.0/src/mcp_trust/core/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/core/grading.py +118 -0
- mcp_trust-0.1.0/src/mcp_trust/core/models.py +158 -0
- mcp_trust-0.1.0/src/mcp_trust/core/provenance.py +59 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/base.py +50 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/credentials.py +57 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/factory.py +32 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/mcpaudit.py +296 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/sandbox.py +144 -0
- mcp_trust-0.1.0/src/mcp_trust/engine/stub.py +157 -0
- mcp_trust-0.1.0/src/mcp_trust/mcp_server.py +122 -0
- mcp_trust-0.1.0/src/mcp_trust/receipts.py +102 -0
- mcp_trust-0.1.0/src/mcp_trust/site/__init__.py +8 -0
- mcp_trust-0.1.0/src/mcp_trust/site/badges.py +47 -0
- mcp_trust-0.1.0/src/mcp_trust/site/generator.py +154 -0
- mcp_trust-0.1.0/src/mcp_trust/store/__init__.py +1 -0
- mcp_trust-0.1.0/src/mcp_trust/store/db.py +52 -0
- mcp_trust-0.1.0/src/mcp_trust/store/repository.py +182 -0
- mcp_trust-0.1.0/tests/__init__.py +0 -0
- mcp_trust-0.1.0/tests/test_api.py +320 -0
- mcp_trust-0.1.0/tests/test_build_site_script.py +67 -0
- mcp_trust-0.1.0/tests/test_build_snapshot.py +72 -0
- mcp_trust-0.1.0/tests/test_cli.py +214 -0
- mcp_trust-0.1.0/tests/test_credentialed_scan.py +233 -0
- mcp_trust-0.1.0/tests/test_deploy_bundle_builder.py +148 -0
- mcp_trust-0.1.0/tests/test_grading.py +94 -0
- mcp_trust-0.1.0/tests/test_launch_state_validator.py +181 -0
- mcp_trust-0.1.0/tests/test_mcp_server.py +58 -0
- mcp_trust-0.1.0/tests/test_mcpaudit_adapter.py +85 -0
- mcp_trust-0.1.0/tests/test_models.py +51 -0
- mcp_trust-0.1.0/tests/test_provenance.py +91 -0
- mcp_trust-0.1.0/tests/test_reference_scan_plan.py +76 -0
- mcp_trust-0.1.0/tests/test_sandbox.py +84 -0
- mcp_trust-0.1.0/tests/test_site_generator.py +319 -0
- mcp_trust-0.1.0/tests/test_store.py +260 -0
- mcp_trust-0.1.0/tests/test_stub_engine.py +98 -0
- mcp_trust-0.1.0/tests/test_web.py +195 -0
- 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
|