mcp-context-cost 0.6.0 → 0.7.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/dist/audit/audit.d.ts +9 -4
- package/dist/audit/audit.js +6 -3
- package/dist/audit/config.d.ts +25 -0
- package/dist/audit/config.js +32 -3
- package/dist/cli.js +20 -3
- package/package.json +1 -1
package/dist/audit/audit.d.ts
CHANGED
|
@@ -101,14 +101,19 @@ export interface AuditReport {
|
|
|
101
101
|
contextWindow: number;
|
|
102
102
|
configs: AuditConfigResult[];
|
|
103
103
|
/**
|
|
104
|
-
* Client configs that were read and parsed
|
|
105
|
-
* no report line
|
|
106
|
-
*
|
|
107
|
-
*
|
|
104
|
+
* Client configs that were read and parsed and have nothing to total. They
|
|
105
|
+
* get no report line, but they are the record that a client is installed
|
|
106
|
+
* here, which is not the same machine as one with no client at all.
|
|
107
|
+
*
|
|
108
|
+
* `allDisabled`, when present, is why there is nothing to total: the file
|
|
109
|
+
* declares those servers and every one of them is switched off. A config
|
|
110
|
+
* without it declares no servers at all. The two are different facts about a
|
|
111
|
+
* file this opened, so they are not published as one.
|
|
108
112
|
*/
|
|
109
113
|
emptyConfigs: {
|
|
110
114
|
client: string;
|
|
111
115
|
source: string;
|
|
116
|
+
allDisabled?: string[];
|
|
112
117
|
}[];
|
|
113
118
|
budget?: {
|
|
114
119
|
limit: number;
|
package/dist/audit/audit.js
CHANGED
|
@@ -177,10 +177,13 @@ export function buildReport(configs, measured, opts = {}) {
|
|
|
177
177
|
problems.push(`${cfg.source}: ${cfg.error}`);
|
|
178
178
|
continue;
|
|
179
179
|
}
|
|
180
|
-
// Parsed, and
|
|
181
|
-
// recorded as itself, so a reader is told what this machine actually has
|
|
180
|
+
// Parsed, and nothing to total. Not a problem and not a report line: it is
|
|
181
|
+
// recorded as itself, so a reader is told what this machine actually has —
|
|
182
|
+
// including, where that is the case, that what it has is servers turned off.
|
|
182
183
|
if (cfg.declaresNothing || cfg.servers.length === 0) {
|
|
183
|
-
emptyConfigs.push(
|
|
184
|
+
emptyConfigs.push(cfg.allDisabled?.length
|
|
185
|
+
? { client: cfg.client, source: cfg.source, allDisabled: cfg.allDisabled }
|
|
186
|
+
: { client: cfg.client, source: cfg.source });
|
|
184
187
|
continue;
|
|
185
188
|
}
|
|
186
189
|
const ok = [];
|
package/dist/audit/config.d.ts
CHANGED
|
@@ -32,6 +32,23 @@ export declare function extractServers(doc: unknown, meta: {
|
|
|
32
32
|
source: string;
|
|
33
33
|
cwd?: string;
|
|
34
34
|
}): ConfiguredServer[];
|
|
35
|
+
/**
|
|
36
|
+
* What one config document declares, servers and switched-off entries both.
|
|
37
|
+
*
|
|
38
|
+
* `extractServers` above answers "what is there to measure", which is the
|
|
39
|
+
* question almost every caller has. This answers the wider one, because a file
|
|
40
|
+
* that declares three servers and switches all three off has nothing to measure
|
|
41
|
+
* and is still not a file that declares nothing — and the only place that
|
|
42
|
+
* difference is still visible is here, before the off ones are dropped.
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractDeclaration(doc: unknown, meta: {
|
|
45
|
+
client: string;
|
|
46
|
+
source: string;
|
|
47
|
+
cwd?: string;
|
|
48
|
+
}): {
|
|
49
|
+
servers: ConfiguredServer[];
|
|
50
|
+
disabled: string[];
|
|
51
|
+
};
|
|
35
52
|
export interface ConfigCandidate {
|
|
36
53
|
client: string;
|
|
37
54
|
path: string;
|
|
@@ -57,6 +74,14 @@ export interface LoadedConfig {
|
|
|
57
74
|
* first.
|
|
58
75
|
*/
|
|
59
76
|
declaresNothing?: true;
|
|
77
|
+
/**
|
|
78
|
+
* Set instead of `declaresNothing` when the file was read and parsed cleanly,
|
|
79
|
+
* declares servers, and every one of them is switched off — the names, in the
|
|
80
|
+
* file's own words. There is nothing to total either way, but a person who
|
|
81
|
+
* turned their servers off is not a person who declared none, and telling
|
|
82
|
+
* them the file declares nothing is a false statement about a file this read.
|
|
83
|
+
*/
|
|
84
|
+
allDisabled?: string[];
|
|
60
85
|
}
|
|
61
86
|
/** Read + parse the candidates that exist. Unreadable files are reported, not thrown. */
|
|
62
87
|
export declare function loadConfigs(candidates: ConfigCandidate[], cwd: string): LoadedConfig[];
|
package/dist/audit/config.js
CHANGED
|
@@ -113,16 +113,34 @@ function toServer(name, raw, client, source) {
|
|
|
113
113
|
* servers by absolute directory.
|
|
114
114
|
*/
|
|
115
115
|
export function extractServers(doc, meta) {
|
|
116
|
+
return extractDeclaration(doc, meta).servers;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* What one config document declares, servers and switched-off entries both.
|
|
120
|
+
*
|
|
121
|
+
* `extractServers` above answers "what is there to measure", which is the
|
|
122
|
+
* question almost every caller has. This answers the wider one, because a file
|
|
123
|
+
* that declares three servers and switches all three off has nothing to measure
|
|
124
|
+
* and is still not a file that declares nothing — and the only place that
|
|
125
|
+
* difference is still visible is here, before the off ones are dropped.
|
|
126
|
+
*/
|
|
127
|
+
export function extractDeclaration(doc, meta) {
|
|
116
128
|
if (!doc || typeof doc !== 'object')
|
|
117
|
-
return [];
|
|
129
|
+
return { servers: [], disabled: [] };
|
|
118
130
|
const d = doc;
|
|
119
131
|
const out = [];
|
|
132
|
+
const off = [];
|
|
120
133
|
const addBlock = (block) => {
|
|
121
134
|
if (!block || typeof block !== 'object')
|
|
122
135
|
return;
|
|
123
136
|
for (const [name, raw] of Object.entries(block)) {
|
|
124
137
|
if (!raw || typeof raw !== 'object')
|
|
125
138
|
continue;
|
|
139
|
+
// Recorded before `toServer` drops it, which is the only difference this
|
|
140
|
+
// can still see: an entry it returns null for because the person turned
|
|
141
|
+
// it off, rather than because it is malformed or absent.
|
|
142
|
+
if (raw.disabled === true)
|
|
143
|
+
off.push(name);
|
|
126
144
|
const s = toServer(name, raw, meta.client, meta.source);
|
|
127
145
|
if (s)
|
|
128
146
|
out.push(s);
|
|
@@ -137,7 +155,11 @@ export function extractServers(doc, meta) {
|
|
|
137
155
|
}
|
|
138
156
|
// A name can legitimately appear in both blocks of the same file; keep the first.
|
|
139
157
|
const seen = new Set();
|
|
140
|
-
|
|
158
|
+
const servers = out.filter((s) => (seen.has(s.name) ? false : (seen.add(s.name), true)));
|
|
159
|
+
// A name that is off in one block and live in another is a live server, not a
|
|
160
|
+
// switched-off one, so it is not reported as both.
|
|
161
|
+
const disabled = [...new Set(off.filter((n) => !seen.has(n)))].sort();
|
|
162
|
+
return { servers, disabled };
|
|
141
163
|
}
|
|
142
164
|
/** Every place a client config is known to live, whether or not it exists. */
|
|
143
165
|
export function configCandidates(env) {
|
|
@@ -165,12 +187,19 @@ export function loadConfigs(candidates, cwd) {
|
|
|
165
187
|
continue;
|
|
166
188
|
try {
|
|
167
189
|
const doc = parseJsonc(readFileSync(c.path, 'utf8'));
|
|
168
|
-
const servers =
|
|
190
|
+
const { servers, disabled } = extractDeclaration(doc, { client: c.client, source: c.path, cwd });
|
|
169
191
|
// A config with no MCP block at all (e.g. a ~/.claude.json holding only
|
|
170
192
|
// session history) is not worth a line in the report — it has no total.
|
|
171
193
|
// It is still worth carrying: it is the evidence that a client is on this
|
|
172
194
|
// machine, which is what tells an empty client apart from no client.
|
|
173
195
|
if (servers.length === 0) {
|
|
196
|
+
// ...and one whose every declared server is switched off is carried as
|
|
197
|
+
// that, not as one declaring nothing: the second is a claim about the
|
|
198
|
+
// file that the file itself contradicts.
|
|
199
|
+
if (disabled.length) {
|
|
200
|
+
out.push({ client: c.client, source: c.path, servers: [], allDisabled: disabled });
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
174
203
|
out.push({ client: c.client, source: c.path, servers: [], declaresNothing: true });
|
|
175
204
|
continue;
|
|
176
205
|
}
|
package/dist/cli.js
CHANGED
|
@@ -176,9 +176,26 @@ if (cmd === 'audit') {
|
|
|
176
176
|
const empty = report.emptyConfigs ?? [];
|
|
177
177
|
if (json)
|
|
178
178
|
console.log(JSON.stringify(report));
|
|
179
|
-
// A machine whose client config was found, opened and parsed, and
|
|
180
|
-
//
|
|
181
|
-
// would send a reader looking for an install they already have.
|
|
179
|
+
// A machine whose client config was found, opened and parsed, and has
|
|
180
|
+
// nothing to total, is told that — being told no client was found anywhere
|
|
181
|
+
// would send a reader looking for an install they already have. Which of
|
|
182
|
+
// the two reasons it is gets said, because "declares nothing" is a false
|
|
183
|
+
// statement about a file that declares servers and switches them off.
|
|
184
|
+
else if (empty.some((c) => c.allDisabled?.length))
|
|
185
|
+
console.error(`${empty.length === 1 ? 'an MCP client config was found' : `${empty.length} MCP client configs were found`}, ` +
|
|
186
|
+
`and ${empty.length === 1 ? 'it has no server' : 'none of them has a server'} to measure:\n` +
|
|
187
|
+
empty
|
|
188
|
+
.map((c) => {
|
|
189
|
+
const off = c.allDisabled ?? [];
|
|
190
|
+
if (!off.length)
|
|
191
|
+
return ` ${c.client}: ${c.source} — declares no servers at all`;
|
|
192
|
+
return (` ${c.client}: ${c.source} — declares ${off.length} server${off.length === 1 ? '' : 's'}, ` +
|
|
193
|
+
`and ${off.length === 1 ? 'it is' : 'every one of them is'} switched off: ${off.join(', ')}`);
|
|
194
|
+
})
|
|
195
|
+
.join('\n') +
|
|
196
|
+
`${where}\n` +
|
|
197
|
+
`${empty.length === 1 ? 'It was' : 'They were'} read and parsed; a switched-off server is not started, so it costs nothing to measure.\n` +
|
|
198
|
+
`Switch one back on, declare one, or point at a different config: mcp-context-cost audit --config <path/to/mcp.json>`);
|
|
182
199
|
else if (empty.length)
|
|
183
200
|
console.error(`${empty.length === 1 ? 'an MCP client config was found' : `${empty.length} MCP client configs were found`}, ` +
|
|
184
201
|
`and ${empty.length === 1 ? 'it declares' : 'they declare'} no servers:\n` +
|
package/package.json
CHANGED