mcpvitals 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.
- mcpvitals-0.1.0/.github/workflows/release.yml +20 -0
- mcpvitals-0.1.0/.github/workflows/tests.yml +12 -0
- mcpvitals-0.1.0/.gitignore +6 -0
- mcpvitals-0.1.0/.mcpvitals/badge.svg +1 -0
- mcpvitals-0.1.0/CONTRIBUTING.md +31 -0
- mcpvitals-0.1.0/LICENSE +21 -0
- mcpvitals-0.1.0/PKG-INFO +109 -0
- mcpvitals-0.1.0/README.md +95 -0
- mcpvitals-0.1.0/action.yml +15 -0
- mcpvitals-0.1.0/docs/DESIGN.md +108 -0
- mcpvitals-0.1.0/docs/PLAN.md +1354 -0
- mcpvitals-0.1.0/pyproject.toml +26 -0
- mcpvitals-0.1.0/src/mcpvitals/__init__.py +1 -0
- mcpvitals-0.1.0/src/mcpvitals/badge.py +28 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/__init__.py +33 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/conformance.py +24 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/confusion.py +29 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/migration.py +22 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/reliability.py +27 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/security.py +44 -0
- mcpvitals-0.1.0/src/mcpvitals/checks/tokens.py +34 -0
- mcpvitals-0.1.0/src/mcpvitals/cli.py +107 -0
- mcpvitals-0.1.0/src/mcpvitals/introspect.py +38 -0
- mcpvitals-0.1.0/src/mcpvitals/lock.py +32 -0
- mcpvitals-0.1.0/src/mcpvitals/models.py +59 -0
- mcpvitals-0.1.0/src/mcpvitals/monitor.py +26 -0
- mcpvitals-0.1.0/src/mcpvitals/report.py +28 -0
- mcpvitals-0.1.0/src/mcpvitals/scoring.py +13 -0
- mcpvitals-0.1.0/tests/conftest.py +20 -0
- mcpvitals-0.1.0/tests/fixtures/healthy.json +7 -0
- mcpvitals-0.1.0/tests/fixtures/messy.json +8 -0
- mcpvitals-0.1.0/tests/servers/reference_server.py +13 -0
- mcpvitals-0.1.0/tests/test_badge.py +20 -0
- mcpvitals-0.1.0/tests/test_cli.py +29 -0
- mcpvitals-0.1.0/tests/test_cli_watch.py +27 -0
- mcpvitals-0.1.0/tests/test_conformance.py +11 -0
- mcpvitals-0.1.0/tests/test_confusion.py +16 -0
- mcpvitals-0.1.0/tests/test_docs.py +14 -0
- mcpvitals-0.1.0/tests/test_introspect.py +15 -0
- mcpvitals-0.1.0/tests/test_lock.py +31 -0
- mcpvitals-0.1.0/tests/test_migration.py +20 -0
- mcpvitals-0.1.0/tests/test_models.py +17 -0
- mcpvitals-0.1.0/tests/test_monitor.py +17 -0
- mcpvitals-0.1.0/tests/test_package.py +4 -0
- mcpvitals-0.1.0/tests/test_registry.py +17 -0
- mcpvitals-0.1.0/tests/test_reliability.py +6 -0
- mcpvitals-0.1.0/tests/test_report.py +19 -0
- mcpvitals-0.1.0/tests/test_scoring.py +23 -0
- mcpvitals-0.1.0/tests/test_security.py +20 -0
- mcpvitals-0.1.0/tests/test_tokens.py +13 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags: ["v*"]
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # trusted publishing, no token needed
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
on: [push, pull_request, workflow_dispatch]
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/checkout@v4
|
|
8
|
+
- uses: actions/setup-python@v5
|
|
9
|
+
with:
|
|
10
|
+
python-version: "3.11"
|
|
11
|
+
- run: pip install -e ".[dev]" mcp
|
|
12
|
+
- run: pytest -q
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="20" role="img" aria-label="mcp health: 100 A"><rect width="90" height="20" fill="#555"/><rect x="90" width="60" height="20" fill="#3fb950"/><g fill="#fff" font-family="Verdana" font-size="11"><text x="8" y="14">mcp health</text><text x="98" y="14">100 A</text></g></svg>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Contributing to mcpvitals
|
|
2
|
+
|
|
3
|
+
Thanks for helping make MCP servers healthier.
|
|
4
|
+
|
|
5
|
+
## Add a check in three steps
|
|
6
|
+
|
|
7
|
+
Every check is a pure function over a `ServerSnapshot`, so adding one is small and testable:
|
|
8
|
+
|
|
9
|
+
1. Write a function in the right module under `src/mcpvitals/checks/`:
|
|
10
|
+
```python
|
|
11
|
+
from mcpvitals.checks import check
|
|
12
|
+
from mcpvitals.models import Finding, Level
|
|
13
|
+
|
|
14
|
+
@check
|
|
15
|
+
def my_rule(snapshot, config):
|
|
16
|
+
out = []
|
|
17
|
+
for t in snapshot.tools:
|
|
18
|
+
if is_bad(t):
|
|
19
|
+
out.append(Finding("MV0XX", Level.WARN, "what's wrong", hint="how to fix", tool=t.name))
|
|
20
|
+
return out
|
|
21
|
+
```
|
|
22
|
+
2. Give it a fresh, stable `MV###` code (never reuse or renumber an existing one).
|
|
23
|
+
3. Add a golden-fixture test in `tests/` asserting the exact finding on a fixture snapshot. No network in unit tests.
|
|
24
|
+
|
|
25
|
+
Run `pytest -q` before opening a PR. CI runs the full suite.
|
|
26
|
+
|
|
27
|
+
## Principles
|
|
28
|
+
|
|
29
|
+
- Checks do zero I/O. Only `introspect.py` touches the network.
|
|
30
|
+
- Deterministic output. If a check needs token counting, take a counter via `config` so tests stay stable.
|
|
31
|
+
- Human-voiced messages, no em-dashes.
|
mcpvitals-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ContextJet.ai
|
|
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.
|
mcpvitals-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcpvitals
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Vital signs for your MCP servers: health score, token cost, tool-confusion, migration readiness.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: mcp>=1.0
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
11
|
+
Provides-Extra: tokens
|
|
12
|
+
Requires-Dist: tiktoken>=0.7; extra == 'tokens'
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
<div align="center">
|
|
16
|
+
|
|
17
|
+
# mcpvitals
|
|
18
|
+
|
|
19
|
+
**Vital signs for your MCP servers. One command gives you a health score, plus the checks nobody else runs.**
|
|
20
|
+
|
|
21
|
+
[](https://github.com/ContextJet-ai/mcpvitals/actions/workflows/tests.yml)
|
|
22
|
+
[](https://pypi.org/project/mcpvitals/)
|
|
23
|
+
[](LICENSE)
|
|
24
|
+
[](https://www.contextjetai.com)
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
> [!NOTE]
|
|
29
|
+
> An audit of ~1,850 public MCP servers found **52% abandoned and only 17% production-ready**, and a separate benchmark traced **56.7% of agent failures to tool misuse** (wrong tool, bad arguments). Registries have no health signal, so a broken server looks identical to a good one. `mcpvitals` is the checkup.
|
|
30
|
+
|
|
31
|
+
## 60-second start
|
|
32
|
+
|
|
33
|
+
No install. Point it at any MCP server (a stdio command or an http url):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uvx mcpvitals check "npx -y @your/mcp-server"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
mcp health: 40 (F)
|
|
41
|
+
|
|
42
|
+
x MV020 [run_sql] tool 'run_sql' appears to contain a hard-coded secret
|
|
43
|
+
-> never ship keys in tool metadata; use env vars
|
|
44
|
+
x MV022 [run_sql] description contains model-directed instructions (poisoning surface)
|
|
45
|
+
-> tool descriptions should describe, not instruct the model
|
|
46
|
+
! MV030 [run_sql] tool 'run_sql' costs ~410 tokens to expose
|
|
47
|
+
-> trim the description/schema; it inflates every request
|
|
48
|
+
! MV040 tools 'get_user' and 'fetch_user' are 0.91 similar; agents may pick the wrong one
|
|
49
|
+
-> differentiate names/descriptions or merge them
|
|
50
|
+
i MV050 protocol 2025-03-26 predates the 2026-07-28 stateless spec
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## What it checks
|
|
54
|
+
|
|
55
|
+
Most linters stop at basic conformance. `mcpvitals` runs those, plus four things no other tool does:
|
|
56
|
+
|
|
57
|
+
| Area | What it catches |
|
|
58
|
+
|---|---|
|
|
59
|
+
| **Conformance** | empty tool descriptions, duplicate tool names, malformed schemas |
|
|
60
|
+
| **Reliability** | parameters with no `required` list, untyped params, error-path gaps |
|
|
61
|
+
| **Security hygiene** | secrets in tool metadata, over-broad tools (`run_sql`, `exec`), model-directed instructions in descriptions (the tool-poisoning surface) |
|
|
62
|
+
| **Token cost** | how many tokens each tool burns in the context window, and the total cost to connect the server |
|
|
63
|
+
| **Tool confusion** | pairs of tools an agent will mix up, predicted from name/description overlap *before* it happens in production |
|
|
64
|
+
| **Migration readiness** | what breaks under the 2026-07-28 stateless spec |
|
|
65
|
+
|
|
66
|
+
Every check is a pure function scored deterministically. Run `mcpvitals check --json` for machine output.
|
|
67
|
+
|
|
68
|
+
## Add the health badge to your README
|
|
69
|
+
|
|
70
|
+
`mcpvitals` emits a shareable badge so a good score is visible at a glance:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
mcpvitals check "npx your-server" --badge badge.svg
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Or use the shields.io endpoint output to keep it live.
|
|
77
|
+
|
|
78
|
+
## Use it in CI
|
|
79
|
+
|
|
80
|
+
Gate your server on every push with the bundled GitHub Action:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
- uses: ContextJet-ai/mcpvitals@v0
|
|
84
|
+
with:
|
|
85
|
+
target: "python -m your_server"
|
|
86
|
+
strict: "true" # fail the build on any error-level finding
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Track and monitor (not just a one-shot check)
|
|
90
|
+
|
|
91
|
+
Pin a server's tools and get alerted when they change. This catches **rug-pulls**, where a server you already approved silently mutates a tool's schema or description after the fact:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
mcpvitals watch "npx your-server" # pins tools to mcp.lock
|
|
95
|
+
mcpvitals watch "npx your-server" --check # re-run in CI; fails if a pinned tool changed
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Probe a running server for live health (uptime and latency):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
mcpvitals monitor "https://your-server/mcp" --count 5
|
|
102
|
+
# probe 1/5: up 210ms ... uptime 100.0% avg 207ms
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Why this exists
|
|
106
|
+
|
|
107
|
+
The MCP ecosystem grew faster than the tooling around it. There are thousands of servers and no standard way to tell whether one is any good, safe, or cheap to run. `mcpvitals` gives authors a one-command checkup before they publish, and gives everyone else a way to vet a server before they trust it.
|
|
108
|
+
|
|
109
|
+
Built by [ContextJet.ai](https://www.contextjetai.com). MIT licensed. Contributions welcome, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# mcpvitals
|
|
4
|
+
|
|
5
|
+
**Vital signs for your MCP servers. One command gives you a health score, plus the checks nobody else runs.**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/ContextJet-ai/mcpvitals/actions/workflows/tests.yml)
|
|
8
|
+
[](https://pypi.org/project/mcpvitals/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://www.contextjetai.com)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
> [!NOTE]
|
|
15
|
+
> An audit of ~1,850 public MCP servers found **52% abandoned and only 17% production-ready**, and a separate benchmark traced **56.7% of agent failures to tool misuse** (wrong tool, bad arguments). Registries have no health signal, so a broken server looks identical to a good one. `mcpvitals` is the checkup.
|
|
16
|
+
|
|
17
|
+
## 60-second start
|
|
18
|
+
|
|
19
|
+
No install. Point it at any MCP server (a stdio command or an http url):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uvx mcpvitals check "npx -y @your/mcp-server"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
mcp health: 40 (F)
|
|
27
|
+
|
|
28
|
+
x MV020 [run_sql] tool 'run_sql' appears to contain a hard-coded secret
|
|
29
|
+
-> never ship keys in tool metadata; use env vars
|
|
30
|
+
x MV022 [run_sql] description contains model-directed instructions (poisoning surface)
|
|
31
|
+
-> tool descriptions should describe, not instruct the model
|
|
32
|
+
! MV030 [run_sql] tool 'run_sql' costs ~410 tokens to expose
|
|
33
|
+
-> trim the description/schema; it inflates every request
|
|
34
|
+
! MV040 tools 'get_user' and 'fetch_user' are 0.91 similar; agents may pick the wrong one
|
|
35
|
+
-> differentiate names/descriptions or merge them
|
|
36
|
+
i MV050 protocol 2025-03-26 predates the 2026-07-28 stateless spec
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What it checks
|
|
40
|
+
|
|
41
|
+
Most linters stop at basic conformance. `mcpvitals` runs those, plus four things no other tool does:
|
|
42
|
+
|
|
43
|
+
| Area | What it catches |
|
|
44
|
+
|---|---|
|
|
45
|
+
| **Conformance** | empty tool descriptions, duplicate tool names, malformed schemas |
|
|
46
|
+
| **Reliability** | parameters with no `required` list, untyped params, error-path gaps |
|
|
47
|
+
| **Security hygiene** | secrets in tool metadata, over-broad tools (`run_sql`, `exec`), model-directed instructions in descriptions (the tool-poisoning surface) |
|
|
48
|
+
| **Token cost** | how many tokens each tool burns in the context window, and the total cost to connect the server |
|
|
49
|
+
| **Tool confusion** | pairs of tools an agent will mix up, predicted from name/description overlap *before* it happens in production |
|
|
50
|
+
| **Migration readiness** | what breaks under the 2026-07-28 stateless spec |
|
|
51
|
+
|
|
52
|
+
Every check is a pure function scored deterministically. Run `mcpvitals check --json` for machine output.
|
|
53
|
+
|
|
54
|
+
## Add the health badge to your README
|
|
55
|
+
|
|
56
|
+
`mcpvitals` emits a shareable badge so a good score is visible at a glance:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mcpvitals check "npx your-server" --badge badge.svg
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or use the shields.io endpoint output to keep it live.
|
|
63
|
+
|
|
64
|
+
## Use it in CI
|
|
65
|
+
|
|
66
|
+
Gate your server on every push with the bundled GitHub Action:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
- uses: ContextJet-ai/mcpvitals@v0
|
|
70
|
+
with:
|
|
71
|
+
target: "python -m your_server"
|
|
72
|
+
strict: "true" # fail the build on any error-level finding
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Track and monitor (not just a one-shot check)
|
|
76
|
+
|
|
77
|
+
Pin a server's tools and get alerted when they change. This catches **rug-pulls**, where a server you already approved silently mutates a tool's schema or description after the fact:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mcpvitals watch "npx your-server" # pins tools to mcp.lock
|
|
81
|
+
mcpvitals watch "npx your-server" --check # re-run in CI; fails if a pinned tool changed
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Probe a running server for live health (uptime and latency):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
mcpvitals monitor "https://your-server/mcp" --count 5
|
|
88
|
+
# probe 1/5: up 210ms ... uptime 100.0% avg 207ms
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Why this exists
|
|
92
|
+
|
|
93
|
+
The MCP ecosystem grew faster than the tooling around it. There are thousands of servers and no standard way to tell whether one is any good, safe, or cheap to run. `mcpvitals` gives authors a one-command checkup before they publish, and gives everyone else a way to vet a server before they trust it.
|
|
94
|
+
|
|
95
|
+
Built by [ContextJet.ai](https://www.contextjetai.com). MIT licensed. Contributions welcome, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: "mcpvitals"
|
|
2
|
+
description: "Run an MCP server health check in CI"
|
|
3
|
+
inputs:
|
|
4
|
+
target:
|
|
5
|
+
description: "stdio command or http url of the MCP server"
|
|
6
|
+
required: true
|
|
7
|
+
strict:
|
|
8
|
+
description: "fail the build on any error-level finding"
|
|
9
|
+
default: "false"
|
|
10
|
+
runs:
|
|
11
|
+
using: "composite"
|
|
12
|
+
steps:
|
|
13
|
+
- shell: bash
|
|
14
|
+
run: |
|
|
15
|
+
pipx run mcpvitals check "${{ inputs.target }}" ${{ inputs.strict == 'true' && '--strict' || '' }}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# mcpvitals - design spec
|
|
2
|
+
|
|
3
|
+
_Status: approved 2026-07-05. Vital signs for your MCP servers._
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
MCP servers exploded (7,000+ public, 2,000+ indexed), but the tooling to tell whether one is any good lagged far behind. Independent audits found ~52% abandoned and only ~17% production-ready; 56.7% of agent failures trace to tool misuse (wrong tool, bad args); connecting a few servers can burn 30%+ of the context window before the first message. The registries have "no health-check light," so a broken server looks identical to a solid one at discovery time. The 2026-07-28 spec RC adds six breaking changes (MCP goes stateless), so every production server must migrate this quarter.
|
|
8
|
+
|
|
9
|
+
Several people independently started "lint / diagnose an MCP server" tools (max ~15 stars, all abandoned, all doing only basic checks). Demand is validated; nobody has won; the basic linter alone is undifferentiated.
|
|
10
|
+
|
|
11
|
+
## What mcpvitals is
|
|
12
|
+
|
|
13
|
+
A single, language-agnostic CLI that gives any MCP server a **health checkup with a score**, plus differentiated analysis nobody else does. It speaks MCP over JSON-RPC, so it inspects TypeScript and Python servers alike. Deterministic and fully unit-testable offline.
|
|
14
|
+
|
|
15
|
+
Primary command:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
uvx mcpvitals check <server> # stdio command or http url
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Goals
|
|
22
|
+
|
|
23
|
+
- Give a server author a one-command, actionable health report before they publish.
|
|
24
|
+
- Produce a **standardized health score + shareable README badge** (the missing ecosystem quality signal, and the viral distribution loop).
|
|
25
|
+
- Surface things no other tool does: token cost, tool-confusion risk, migration readiness.
|
|
26
|
+
- Be deterministic and testable: the analysis engine is pure functions over introspected schema, tested against golden fixtures with zero network.
|
|
27
|
+
- Ship a GitHub Action so authors gate it in CI and auto-refresh the badge.
|
|
28
|
+
|
|
29
|
+
## Non-goals (v1)
|
|
30
|
+
|
|
31
|
+
- Not a gateway/proxy, not a runtime security enforcer, not a registry.
|
|
32
|
+
- Not a threat scanner for tool-poisoning/injection (that lane is closing: Cisco, Snyk, Invariant). We do *author-facing hygiene*, not *defender-facing threat detection*.
|
|
33
|
+
- Not a hosted service or dashboard.
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
Three layers, clean boundaries:
|
|
38
|
+
|
|
39
|
+
1. **Introspection layer** (`introspect/`) - connects to a server (stdio or streamable-http) via the MCP SDK, performs the handshake, and captures a plain-data snapshot: server info, protocol version, and the full list of tools/prompts/resources with their JSON schemas. Output is a pure dataclass/dict (`ServerSnapshot`). This is the only layer that touches the network.
|
|
40
|
+
2. **Checks engine** (`checks/`) - a registry of independent **pure-function checks**. Each check takes a `ServerSnapshot` (plus config) and returns a list of `Finding(level, code, message, hint)`. No I/O. This is where all the logic lives and where all the tests point. Adding a check = adding one pure function + its golden fixtures.
|
|
41
|
+
3. **Reporting layer** (`report/`) - aggregates findings into a **score**, renders human output (checklist + score), machine output (`--json`), and the **badge** (SVG + shields.io-compatible endpoint JSON). Deterministic given the findings.
|
|
42
|
+
|
|
43
|
+
The live commands (`monitor`, `watch`) are a thin shell that repeatedly calls the introspection layer and diffs/records snapshots; the diff and scoring logic they use are pure functions in the checks/report layers, so they stay testable.
|
|
44
|
+
|
|
45
|
+
### Data shapes
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
Finding(level: "error"|"warn"|"info", code: str, message: str, hint: str | None,
|
|
49
|
+
tool: str | None, weight: int)
|
|
50
|
+
ServerSnapshot(name, version, protocol_version, tools: list[ToolSpec], prompts, resources, raw)
|
|
51
|
+
Report(score: int, grade: "A".."F", findings: list[Finding], token_cost, confusions, migration)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## The checks (v1)
|
|
55
|
+
|
|
56
|
+
Core hygiene (deterministic rules over the snapshot):
|
|
57
|
+
- **Conformance**: JSON-RPC error semantics, `isError` handling, valid `resources/list` URIs + MIME types, required tool fields, schema validity.
|
|
58
|
+
- **Reliability smells**: numeric params typed as int but examples/coercion imply float; missing `required` on obviously-required params; empty/placeholder descriptions; no error-path signaling.
|
|
59
|
+
- **Security hygiene** (author-facing, keeps the ContextJet flavor): secrets-shaped strings in tool descriptions/defaults; over-broad generic tools (`execute_sql`, `run_command`, `read_file` with unconstrained path); tool descriptions containing imperative "instructions to the model" (poisoning surface); unauthenticated http endpoint.
|
|
60
|
+
|
|
61
|
+
The differentiated value-adds (the moat):
|
|
62
|
+
- **Token-cost X-ray**: compute the token footprint of each tool's name+description+schema (tiktoken-style, with a stdlib fallback estimator), total "cost to connect," and flag the biggest offenders with a suggested trim target.
|
|
63
|
+
- **Tool-confusion predictor**: pairwise similarity of tool names+descriptions (token-set / embedding-free cosine over n-grams); flag pairs above a threshold as likely mis-selection ("`get_user` vs `fetch_user`: 0.94"). Deterministic, no model call.
|
|
64
|
+
- **Migration readiness (2026-07-28)**: detect reliance on soon-removed features (session state assumptions, deprecated Roots/Sampling/Logging usage, missing forthcoming headers) and report what breaks.
|
|
65
|
+
|
|
66
|
+
## Scoring + badge
|
|
67
|
+
|
|
68
|
+
- Each finding carries a weight by level. Score = 100 minus weighted deductions, clamped to 0-100, mapped to a letter grade. Deterministic and documented so it's not a black box.
|
|
69
|
+
- `--badge` writes `badge.svg` and a shields.io endpoint JSON (`{schemaVersion, label:"mcp health", message:"92 A", color}`) so authors can embed either a static SVG or a live endpoint badge.
|
|
70
|
+
- The scoring weights live in one documented table so authors can see exactly why they lost points.
|
|
71
|
+
|
|
72
|
+
## CLI surface
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
mcpvitals check <server> [--json] [--badge out.svg] [--strict] [--config mcpvitals.toml]
|
|
76
|
+
mcpvitals migrate-check <server> # focused 2026-07-28 readiness report
|
|
77
|
+
mcpvitals watch <server> # v1.1: pin schemas to mcp.lock, diff on change (rug-pull/drift)
|
|
78
|
+
mcpvitals monitor <server> [--otel] # v1.1: periodic health probe, latency/error/uptime, OTel metrics
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Server arg accepts a stdio command (`"npx some-server"`) or an http(s) URL.
|
|
82
|
+
|
|
83
|
+
## Testing strategy (the whole point)
|
|
84
|
+
|
|
85
|
+
- **Golden fixtures**: a `tests/fixtures/` set of captured `ServerSnapshot` JSONs (a healthy server, a broken one, a token-bloated one, a confusable-tools one, a pre-2026-07-28 one). Every check has unit tests asserting exact findings against these. Zero network in the test suite.
|
|
86
|
+
- **Scoring tests**: fixed findings -> exact score/grade/badge output.
|
|
87
|
+
- **A tiny reference MCP server** (in `tests/servers/`) so a handful of end-to-end tests exercise the real introspection path in CI, but the bulk of coverage is the pure-function checks.
|
|
88
|
+
- CI (GitHub Actions) runs the suite on every push -> green tests badge.
|
|
89
|
+
|
|
90
|
+
## Distribution / trending
|
|
91
|
+
|
|
92
|
+
- `uvx mcpvitals check <server>` - zero-install one-liner.
|
|
93
|
+
- The **health badge** is the viral engine: every author who scores well embeds it, spreading the tool through READMEs (shields/codecov pattern).
|
|
94
|
+
- A **`mcpvitals` GitHub Action** for CI gating + badge refresh.
|
|
95
|
+
- Launch hook: "the 2026-07-28 spec breaks half the servers, run `mcpvitals` to see if yours survives" - rides the live migration wave. Plus the named-enemy hook: "52% of MCP servers are dead, here's a checkup."
|
|
96
|
+
- README-as-landing-page, searchable name/topics, one-screenshot demo (the scored checklist).
|
|
97
|
+
|
|
98
|
+
## Roadmap after v1
|
|
99
|
+
|
|
100
|
+
- `watch` / `mcp.lock` (dependency drift + rug-pull tracking).
|
|
101
|
+
- `monitor` (live latency/error/uptime, OpenTelemetry export).
|
|
102
|
+
- Optional live tool-selection eval (the harness from candidate B) as a `mcpvitals eval` subcommand once the static core has traction.
|
|
103
|
+
|
|
104
|
+
## Open decisions (resolve during planning)
|
|
105
|
+
|
|
106
|
+
- Package/impl language: Python (fits `uvx`, our testing muscle, tiktoken). Confirmed for v1.
|
|
107
|
+
- MCP client library: official `mcp` Python SDK for introspection.
|
|
108
|
+
- Token counter: `tiktoken` if available, deterministic stdlib fallback otherwise (so tests never depend on a model).
|