@vantageos/mcp-doctor 0.2.0 → 0.3.0
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.
- package/CHANGELOG.md +43 -0
- package/dist/doctor.d.ts +44 -0
- package/dist/doctor.js +2924 -270
- package/package.json +2 -7
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
3
3
|
All notable changes to `@vantageos/mcp-doctor` are documented here.
|
|
4
4
|
This project adheres to [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## 0.3.0 — 2026-10-04
|
|
7
|
+
|
|
8
|
+
The documented invocation never ran. Through `node_modules/.bin/mcp-doctor` this
|
|
9
|
+
tool printed **nothing** and exited **0** — for every target, since the bin was
|
|
10
|
+
published. Every station that ran `npx mcp-doctor <tree>` and saw no output read a
|
|
11
|
+
pass that was never computed.
|
|
12
|
+
|
|
13
|
+
### READ THIS BEFORE UPGRADING
|
|
14
|
+
|
|
15
|
+
**A CI job that was passing may now fail, and that is the fix working.** If you
|
|
16
|
+
wired `npx mcp-doctor` into a pipeline and it has been green, it was green because
|
|
17
|
+
nothing ran. On a real target this tool has findings to report. Budget for a first
|
|
18
|
+
red run.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **The bin is a symlink, and the entrypoint guard compared raw paths.** npm installs
|
|
22
|
+
`bin` as a symlink, so `process.argv[1]` is the link path while `import.meta.url`
|
|
23
|
+
is the resolved real path; compared directly they never match and `main()` never
|
|
24
|
+
ran. Both sides now resolve through `realpathSync`, each side guarded: a path that
|
|
25
|
+
cannot be resolved answers "do not run" rather than either running on an ordinary
|
|
26
|
+
library import or failing silently.
|
|
27
|
+
Measured on the published 0.2.0 before the fix — `./node_modules/.bin/mcp-doctor t`
|
|
28
|
+
exit 0 / 0 bytes against `node .../dist/doctor.js t` exit 2 / 6308 bytes.
|
|
29
|
+
- **`--version`, `--help` and `-V` were silent for the same reason** and now answer.
|
|
30
|
+
The version is READ from the shipped manifest rather than compiled in, so it cannot
|
|
31
|
+
drift from the binary.
|
|
32
|
+
- **The usage line named a development command no consumer can type**
|
|
33
|
+
(`tsx src/doctor.ts`). It now names `mcp-doctor` and lists the exit codes.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- **D16 is judged at runtime, not only statically.** Health-route census plus a dynamic
|
|
37
|
+
mode: the version a server actually SERVES on its pre-auth `initialize` handshake is
|
|
38
|
+
read from `serverInfo.version` and compared against `package.json`. A served version
|
|
39
|
+
that drifts from the canonical one is now a finding rather than invisible.
|
|
40
|
+
- A static D16 verdict says out loud which mode produced it (`[static read]` prefix), so
|
|
41
|
+
a reader can tell an observation from a fallback.
|
|
42
|
+
|
|
43
|
+
### Changed — observable contract
|
|
44
|
+
- D16's static verdict strings carry the `[static read]` prefix. Anything parsing that
|
|
45
|
+
text rather than the `state` field must be updated.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
6
49
|
## 0.2.0 — 2026-08-16
|
|
7
50
|
|
|
8
51
|
The engine gains a live-session contract and an honest exit code; a second
|
package/dist/doctor.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ interface DetectorResult {
|
|
|
37
37
|
interface RuntimeTool {
|
|
38
38
|
/** The tool name the server actually advertises at runtime (post-startup). */
|
|
39
39
|
name: string;
|
|
40
|
+
/**
|
|
41
|
+
* The description the server actually SERVES over `tools/list`, post-
|
|
42
|
+
* startup — the surface C-19 measures (never the source-declared string,
|
|
43
|
+
* which can drift from what a real client receives). Unset only when the
|
|
44
|
+
* running server declares no description for the tool.
|
|
45
|
+
*/
|
|
46
|
+
description?: string;
|
|
40
47
|
/**
|
|
41
48
|
* Number of eval cases covering this tool, resolved by the runtime builder
|
|
42
49
|
* from the target's `evals/evals.json` (matched by tool name). Optional
|
|
@@ -65,9 +72,42 @@ interface RuntimeContext {
|
|
|
65
72
|
root: string;
|
|
66
73
|
tools: RuntimeTool[];
|
|
67
74
|
launchError?: string;
|
|
75
|
+
/**
|
|
76
|
+
* The `serverInfo` object the running server returned in its `initialize`
|
|
77
|
+
* response — the same non-authenticated discovery handshake a client reads
|
|
78
|
+
* `version` from (S-7). Additive field: existing dynamic detectors that
|
|
79
|
+
* never read it are unaffected. C-25 reads it for a build-identity field
|
|
80
|
+
* served alongside `version` (commit hash / build id). Unset when the
|
|
81
|
+
* launched server returned no `serverInfo` or the launch failed
|
|
82
|
+
* (`launchError` is then set instead).
|
|
83
|
+
*/
|
|
84
|
+
serverInfo?: Record<string, unknown>;
|
|
85
|
+
/**
|
|
86
|
+
* The commit the running server is EXPECTED to be serving, DERIVED from
|
|
87
|
+
* `git rev-parse HEAD` in the target tree — never hand-typed (see
|
|
88
|
+
* derive-never-type). Unset when the target is not a resolvable git
|
|
89
|
+
* checkout: C-25's dynamic served-vs-expected comparison is then reported
|
|
90
|
+
* as OWED (could-not-judge), never silently skipped as a pass.
|
|
91
|
+
* When set it is ALWAYS a full 40-hex commit id (`/^[0-9a-f]{40}$/`,
|
|
92
|
+
* enforced by `deriveExpectedCommit`): C-25's comparison reasons about
|
|
93
|
+
* length and asserts that shape rather than assuming it.
|
|
94
|
+
*/
|
|
95
|
+
expectedCommit?: string;
|
|
68
96
|
}
|
|
69
97
|
interface Detector {
|
|
70
98
|
id: string;
|
|
99
|
+
/**
|
|
100
|
+
* The canonical standard rule id this detector judges (e.g. "C-6"). Optional
|
|
101
|
+
* so the pre-existing detectors that predate this field still compile; every
|
|
102
|
+
* detector built or re-pinned against a standard rule MUST populate it.
|
|
103
|
+
* Coverage of the standard is DERIVED from this field across the registry
|
|
104
|
+
* (see `scripts/trunk-coverage.ts`) — never from a hand-kept list.
|
|
105
|
+
*/
|
|
106
|
+
rule?: string;
|
|
107
|
+
/** The standard commit this detector's `rule` was read against. Required
|
|
108
|
+
* alongside `rule`: a rule id with no pin is unverifiable against a moving
|
|
109
|
+
* doc. */
|
|
110
|
+
pin?: string;
|
|
71
111
|
/** Static verdict from the source tree. REQUIRED — static is never optional. */
|
|
72
112
|
run(tree: Tree): DetectorResult;
|
|
73
113
|
/**
|
|
@@ -129,6 +169,10 @@ interface Session {
|
|
|
129
169
|
*/
|
|
130
170
|
interface LiveDetector {
|
|
131
171
|
id: string;
|
|
172
|
+
/** See `Detector.rule` — same contract, same derivation. */
|
|
173
|
+
rule?: string;
|
|
174
|
+
/** See `Detector.pin` — same contract. */
|
|
175
|
+
pin?: string;
|
|
132
176
|
/**
|
|
133
177
|
* Live verdict from a running session. REQUIRED for a live detector. It owns
|
|
134
178
|
* the abstain contract: a session it cannot read (absent, throwing, timing
|