bantamkit-mcp 0.26.0 → 0.28.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/README.md +43 -0
- package/dist/cli.js +6 -7
- package/dist/mcp/identity.d.ts +34 -1
- package/dist/mcp/identity.js +32 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,49 @@ than reading stdin, but that is version-dependent and `-y` costs nothing.
|
|
|
38
38
|
machines can run different builds from one identical config line. See *Silent version
|
|
39
39
|
float* below — it is the failure this package makes easiest to hit and hardest to see.
|
|
40
40
|
|
|
41
|
+
### Connect it to a host
|
|
42
|
+
|
|
43
|
+
Every host below runs the same command; only the file and the key around it change.
|
|
44
|
+
|
|
45
|
+
**Claude Code** — one command, no file to edit. `-s user` makes it available in every
|
|
46
|
+
project; drop it for this project only.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
claude mcp add bantamkit -s user -- npx -y bantamkit-mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
53
|
+
on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Top-level key
|
|
54
|
+
`mcpServers`; each entry takes `command`, `args` and an optional `env`.
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**GitHub Copilot in VS Code** — `.vscode/mcp.json` for one workspace, or the user
|
|
61
|
+
profile via the **MCP: Open User Configuration** command. Note the top-level key is
|
|
62
|
+
`servers`, not `mcpServers`.
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{"servers": {"bantamkit": {"type": "stdio", "command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
There is a CLI equivalent: `code --add-mcp '{"name":"bantamkit","command":"npx","args":["-y","bantamkit-mcp"]}'`.
|
|
69
|
+
|
|
70
|
+
**Cursor** — `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally. Back
|
|
71
|
+
to `mcpServers`.
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Anything else that speaks MCP over stdio** runs `npx -y bantamkit-mcp` and talks
|
|
78
|
+
JSON-RPC on its stdin and stdout. Nothing about this package is host-specific.
|
|
79
|
+
|
|
80
|
+
The Claude Code and Claude Desktop forms were taken from this machine — `claude mcp add
|
|
81
|
+
--help` and an existing config file. The VS Code and Cursor forms are from those
|
|
82
|
+
projects' own documentation, not from a host installed here.
|
|
83
|
+
|
|
41
84
|
### Measured: what a cold start costs
|
|
42
85
|
|
|
43
86
|
`node tools/conformance/npx-cold-start.mjs` in the repo packs the tarball, installs it
|
package/dist/cli.js
CHANGED
|
@@ -51,12 +51,13 @@
|
|
|
51
51
|
* reaches for is answered on the wire instead, by `build_identity`. `runtime-ts/README.md`
|
|
52
52
|
* and `docs/install.md` carry the same correction in their own words.
|
|
53
53
|
*/
|
|
54
|
-
import { readFileSync
|
|
54
|
+
import { readFileSync } from 'node:fs';
|
|
55
55
|
import { assetsRoot } from './assets.js';
|
|
56
56
|
import { BantamError } from './errors.js';
|
|
57
57
|
import { buildReport, resolveEventLogPath } from './mcpreport.js';
|
|
58
58
|
import { Memory } from './memory/component.js';
|
|
59
59
|
import { DEFAULT_INDEX_BUDGET } from './memory/store.js';
|
|
60
|
+
import { packFileCount } from './mcp/identity.js';
|
|
60
61
|
import { buildServer } from './mcp/server.js';
|
|
61
62
|
import { RawStdioTransport } from './mcp/transport.js';
|
|
62
63
|
import { ArgvError, formatHelp, formatUsageBlock, HelpRequested, helpWidth, parseArgs as parseWithSpec, pyIntStrict, } from './pyargparse.js';
|
|
@@ -207,12 +208,10 @@ async function main(argv) {
|
|
|
207
208
|
const options = parseArgs(argv);
|
|
208
209
|
if (options.assetsRoot) {
|
|
209
210
|
const root = assetsRoot();
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
process.stdout.write(`${root}\n${files} files\n`);
|
|
211
|
+
// `packFileCount`, not a second walk: the count printed here and the count
|
|
212
|
+
// `build_identity` reports must be the same number for the same pack, and on a
|
|
213
|
+
// `pip install` the unfiltered version made one process contradict itself.
|
|
214
|
+
process.stdout.write(`${root}\n${packFileCount(root)} files\n`);
|
|
216
215
|
return 0;
|
|
217
216
|
}
|
|
218
217
|
if (options.mcpReport) {
|
package/dist/mcp/identity.d.ts
CHANGED
|
@@ -10,10 +10,43 @@ export declare const SERVER_NAME = "bantamkit";
|
|
|
10
10
|
* `as_posix()` is why the parts are joined with `/` here and not with `path.sep`: on Windows
|
|
11
11
|
* the walk yields the same components and the digest must not change with the separator.
|
|
12
12
|
*/
|
|
13
|
-
export declare function treeDigest(root: string): {
|
|
13
|
+
export declare function treeDigest(root: string, keep?: (parts: string[]) => boolean): {
|
|
14
14
|
digest: string;
|
|
15
15
|
files: number;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Fingerprint the asset pack this build would load — every file, not just the loaded ones.
|
|
19
|
+
*
|
|
20
|
+
* `contracts/default.yaml` is the reason: `RB-P84` measured it as the one asset that differed
|
|
21
|
+
* between two live builds while no resource template exposed it, so it was invisible on every
|
|
22
|
+
* probed surface. It is also why N1 ships all 84 files rather than the 20 that are read.
|
|
23
|
+
*
|
|
24
|
+
* EXCEPT bytecode caches, and that exception is the whole point of this field. The pack ships
|
|
25
|
+
* `.py` fixture files, so `pip install` byte-compiles them into `__pycache__` on the way in and
|
|
26
|
+
* the digest of an INSTALLED Python pack stopped matching the digest of the identical npm pack
|
|
27
|
+
* — measured on the published 0.27.0 artifacts, `sha256:fa8372f6…` over 98 files against
|
|
28
|
+
* `sha256:d47dcf4b…` over 87, and deleting `__pycache__` from the wheel's pack reproduced the
|
|
29
|
+
* npm digest byte for byte. `cross_runtime` tells the caller to compare `assets_digest` across
|
|
30
|
+
* runtimes; without this rule that instruction returned a false "different" on every real
|
|
31
|
+
* install. The pack is what was SHIPPED, never what an interpreter later wrote beside it.
|
|
32
|
+
*
|
|
33
|
+
* The rule is spelled identically in `runtime-py`'s `_assets_fingerprint`, and it has to be:
|
|
34
|
+
* this side never creates a `__pycache__`, so a Node-only exclusion would still agree today
|
|
35
|
+
* and diverge again the moment a pack carrying one reached both runtimes.
|
|
36
|
+
*/
|
|
37
|
+
export declare const notBytecodeCache: (parts: string[]) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The pack as SHIPPED, counted — what `--assets-root` prints.
|
|
40
|
+
*
|
|
41
|
+
* Exported so the CLI shares this walk rather than keeping a second one. There are TWO
|
|
42
|
+
* walks over this directory and a rule spelled twice is a rule that gets fixed once: the
|
|
43
|
+
* first version of this fix filtered the digest alone, and a `pip install` then had one
|
|
44
|
+
* process contradicting itself, `build_identity` answering 87 files while `--assets-root`
|
|
45
|
+
* printed 98 for the pack it had just loaded. The CLI's own `readdirSync(recursive)` is
|
|
46
|
+
* gone with it — `walkFiles` is the walk that mirrors CPython's `rglob`, which is what the
|
|
47
|
+
* reference's printer uses and what the conformance case compares the count against.
|
|
48
|
+
*/
|
|
49
|
+
export declare function packFileCount(root: string): number;
|
|
17
50
|
/** `sha256(json.dumps(inputs, sort_keys=True, separators=(",", ":")))` — the identity. */
|
|
18
51
|
export declare function buildIdFor(inputs: Record<string, string>): string;
|
|
19
52
|
/**
|
package/dist/mcp/identity.js
CHANGED
|
@@ -108,8 +108,9 @@ function walkFiles(root) {
|
|
|
108
108
|
* `as_posix()` is why the parts are joined with `/` here and not with `path.sep`: on Windows
|
|
109
109
|
* the walk yields the same components and the digest must not change with the separator.
|
|
110
110
|
*/
|
|
111
|
-
export function treeDigest(root) {
|
|
112
|
-
const
|
|
111
|
+
export function treeDigest(root, keep) {
|
|
112
|
+
const walked = walkFiles(root);
|
|
113
|
+
const files = keep === undefined ? walked : walked.filter(keep);
|
|
113
114
|
const running = createHash('sha256');
|
|
114
115
|
for (const parts of files) {
|
|
115
116
|
const payload = readFileSync(join(root, ...parts));
|
|
@@ -164,7 +165,35 @@ function codeFingerprint() {
|
|
|
164
165
|
* `contracts/default.yaml` is the reason: `RB-P84` measured it as the one asset that differed
|
|
165
166
|
* between two live builds while no resource template exposed it, so it was invisible on every
|
|
166
167
|
* probed surface. It is also why N1 ships all 84 files rather than the 20 that are read.
|
|
168
|
+
*
|
|
169
|
+
* EXCEPT bytecode caches, and that exception is the whole point of this field. The pack ships
|
|
170
|
+
* `.py` fixture files, so `pip install` byte-compiles them into `__pycache__` on the way in and
|
|
171
|
+
* the digest of an INSTALLED Python pack stopped matching the digest of the identical npm pack
|
|
172
|
+
* — measured on the published 0.27.0 artifacts, `sha256:fa8372f6…` over 98 files against
|
|
173
|
+
* `sha256:d47dcf4b…` over 87, and deleting `__pycache__` from the wheel's pack reproduced the
|
|
174
|
+
* npm digest byte for byte. `cross_runtime` tells the caller to compare `assets_digest` across
|
|
175
|
+
* runtimes; without this rule that instruction returned a false "different" on every real
|
|
176
|
+
* install. The pack is what was SHIPPED, never what an interpreter later wrote beside it.
|
|
177
|
+
*
|
|
178
|
+
* The rule is spelled identically in `runtime-py`'s `_assets_fingerprint`, and it has to be:
|
|
179
|
+
* this side never creates a `__pycache__`, so a Node-only exclusion would still agree today
|
|
180
|
+
* and diverge again the moment a pack carrying one reached both runtimes.
|
|
181
|
+
*/
|
|
182
|
+
export const notBytecodeCache = (parts) => !parts.includes('__pycache__');
|
|
183
|
+
/**
|
|
184
|
+
* The pack as SHIPPED, counted — what `--assets-root` prints.
|
|
185
|
+
*
|
|
186
|
+
* Exported so the CLI shares this walk rather than keeping a second one. There are TWO
|
|
187
|
+
* walks over this directory and a rule spelled twice is a rule that gets fixed once: the
|
|
188
|
+
* first version of this fix filtered the digest alone, and a `pip install` then had one
|
|
189
|
+
* process contradicting itself, `build_identity` answering 87 files while `--assets-root`
|
|
190
|
+
* printed 98 for the pack it had just loaded. The CLI's own `readdirSync(recursive)` is
|
|
191
|
+
* gone with it — `walkFiles` is the walk that mirrors CPython's `rglob`, which is what the
|
|
192
|
+
* reference's printer uses and what the conformance case compares the count against.
|
|
167
193
|
*/
|
|
194
|
+
export function packFileCount(root) {
|
|
195
|
+
return walkFiles(root).filter(notBytecodeCache).length;
|
|
196
|
+
}
|
|
168
197
|
function assetsFingerprint() {
|
|
169
198
|
let root;
|
|
170
199
|
try {
|
|
@@ -177,7 +206,7 @@ function assetsFingerprint() {
|
|
|
177
206
|
}
|
|
178
207
|
let walked;
|
|
179
208
|
try {
|
|
180
|
-
walked = treeDigest(root);
|
|
209
|
+
walked = treeDigest(root, notBytecodeCache);
|
|
181
210
|
}
|
|
182
211
|
catch (e) {
|
|
183
212
|
const error = e instanceof PyOSError ? e : asPyOSError(e, root);
|