token-goat 2.6.36 → 2.8.1
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 +36 -8
- package/SECURITY.md +46 -17
- package/dist/{token-goat-chunk-UFOVM7ZN.mjs → token-goat-chunk-2G6RAB4G.mjs} +1391 -378
- package/dist/token-goat-chunk-324QOJYZ.mjs +91 -0
- package/dist/token-goat-chunk-5CVKO3DA.mjs +185 -0
- package/dist/{token-goat-chunk-65BKISIS.mjs → token-goat-chunk-73MF6YWW.mjs} +4 -4
- package/dist/{token-goat-chunk-MGOUYAA2.mjs → token-goat-chunk-7JDXDERZ.mjs} +1 -1
- package/dist/{token-goat-hook-chunk-BDR6C6IE.mjs → token-goat-chunk-AOBZUFNJ.mjs} +318 -51
- package/dist/{token-goat-chunk-V465YKOR.mjs → token-goat-chunk-ELDJRLHZ.mjs} +492 -28
- package/dist/{token-goat-chunk-CNDOJ3ZP.mjs → token-goat-chunk-I6TOUPLP.mjs} +2 -2
- package/dist/token-goat-chunk-R4SR7MQY.mjs +486 -0
- package/dist/{token-goat-chunk-IYTVE6KN.mjs → token-goat-chunk-RMDQFTQD.mjs} +226 -150
- package/dist/{token-goat-chunk-KYFJC37X.mjs → token-goat-chunk-VBXBLGTO.mjs} +792 -144
- package/dist/{token-goat-chunk-DG53MVNJ.mjs → token-goat-chunk-WN5T5EW5.mjs} +212 -212
- package/dist/{token-goat-chunk-VYMGEVZS.mjs → token-goat-chunk-XEDQH5DA.mjs} +317 -11
- package/dist/{token-goat-chunk-LN6OUHTV.mjs → token-goat-chunk-Y2SYNH3S.mjs} +5 -5
- package/dist/token-goat-chunk-YUGNM3KL.mjs +23 -0
- package/dist/token-goat-hook.mjs +7 -7
- package/dist/token-goat.core.mjs +5 -5
- package/package.json +12 -8
- package/dist/token-goat-chunk-FRTBMRP7.mjs +0 -10048
- package/dist/token-goat-hook-chunk-3QYSN4QV.mjs +0 -14764
- package/dist/token-goat-hook-chunk-3ZDBWJDF.mjs +0 -13659
- package/dist/token-goat-hook-chunk-5UH54CW6.mjs +0 -912
- package/dist/token-goat-hook-chunk-6ODM3MP7.mjs +0 -706
- package/dist/token-goat-hook-chunk-A77A26A7.mjs +0 -18184
- package/dist/token-goat-hook-chunk-BUOCULAM.mjs +0 -29
- package/dist/token-goat-hook-chunk-C6GIABOX.mjs +0 -15971
- package/dist/token-goat-hook-chunk-E257IGSN.mjs +0 -153
- package/dist/token-goat-hook-chunk-MW5HPEGD.mjs +0 -10411
- package/dist/token-goat-hook-chunk-QSCYNJ2B.mjs +0 -23
- package/dist/token-goat-hook-chunk-RFRLWOQH.mjs +0 -11
- package/dist/token-goat-hook-chunk-XUMIVYEN.mjs +0 -109
- package/dist/token-goat-hook-chunk-Y2WHX2P3.mjs +0 -6463
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
4
|
+
|
|
5
|
+
// src/mcp_stdio.ts
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
var STDIO_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
8
|
+
var StdioServerTransport = class {
|
|
9
|
+
stdin;
|
|
10
|
+
stdout;
|
|
11
|
+
buffer;
|
|
12
|
+
started = false;
|
|
13
|
+
onmessage;
|
|
14
|
+
onclose;
|
|
15
|
+
onerror;
|
|
16
|
+
// Arrow properties rather than bound methods so `off()` can remove the exact same function
|
|
17
|
+
// reference `on()` added -- a fresh `.bind(this)` at removal time would leave the listener
|
|
18
|
+
// attached, and a second `mcp-serve` in the same process would then see every message twice.
|
|
19
|
+
ondata = (chunk) => {
|
|
20
|
+
const size = (this.buffer?.length ?? 0) + chunk.length;
|
|
21
|
+
if (size > STDIO_MAX_BUFFER_BYTES) {
|
|
22
|
+
this.buffer = void 0;
|
|
23
|
+
this.onerror?.(new Error(`MCP stdio read buffer exceeded ${STDIO_MAX_BUFFER_BYTES} bytes`));
|
|
24
|
+
void this.close();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.buffer = this.buffer === void 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
28
|
+
this.drain();
|
|
29
|
+
};
|
|
30
|
+
onstreamerror = (error) => {
|
|
31
|
+
this.onerror?.(error);
|
|
32
|
+
};
|
|
33
|
+
constructor(stdin = process.stdin, stdout = process.stdout) {
|
|
34
|
+
this.stdin = stdin;
|
|
35
|
+
this.stdout = stdout;
|
|
36
|
+
}
|
|
37
|
+
async start() {
|
|
38
|
+
if (this.started) throw new Error("StdioServerTransport already started");
|
|
39
|
+
this.started = true;
|
|
40
|
+
this.stdin.on("data", this.ondata);
|
|
41
|
+
this.stdin.on("error", this.onstreamerror);
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Consumes every complete line currently buffered. A line that is not valid JSON is reported and
|
|
46
|
+
* skipped rather than closing the connection: one malformed message is not a reason to drop a
|
|
47
|
+
* working session, and the next line may well be fine.
|
|
48
|
+
*/
|
|
49
|
+
drain() {
|
|
50
|
+
for (; ; ) {
|
|
51
|
+
const buffer = this.buffer;
|
|
52
|
+
if (buffer === void 0) return;
|
|
53
|
+
const index = buffer.indexOf("\n");
|
|
54
|
+
if (index === -1) return;
|
|
55
|
+
const line = buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
56
|
+
this.buffer = buffer.subarray(index + 1);
|
|
57
|
+
if (line.trim().length === 0) continue;
|
|
58
|
+
let message;
|
|
59
|
+
try {
|
|
60
|
+
message = JSON.parse(line);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
this.onerror?.(err instanceof Error ? err : new Error(String(err)));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
this.onmessage?.(message);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Resolves once the message is handed off. Waiting for `drain` when the stream says it is full
|
|
70
|
+
* is what keeps a long reply from being silently truncated on a slow or small pipe.
|
|
71
|
+
*/
|
|
72
|
+
send(message) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
if (this.stdout.write(`${JSON.stringify(message)}
|
|
75
|
+
`)) resolve();
|
|
76
|
+
else this.stdout.once("drain", resolve);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async close() {
|
|
80
|
+
this.stdin.off("data", this.ondata);
|
|
81
|
+
this.stdin.off("error", this.onstreamerror);
|
|
82
|
+
if (this.stdin.listenerCount("data") === 0) this.stdin.pause();
|
|
83
|
+
this.buffer = void 0;
|
|
84
|
+
this.onclose?.();
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
export {
|
|
89
|
+
STDIO_MAX_BUFFER_BYTES,
|
|
90
|
+
StdioServerTransport
|
|
91
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
|
+
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
external_exports
|
|
5
|
+
} from "./token-goat-chunk-WN5T5EW5.mjs";
|
|
6
|
+
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
7
|
+
|
|
8
|
+
// src/mcp_jsonrpc.ts
|
|
9
|
+
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
10
|
+
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
11
|
+
LATEST_PROTOCOL_VERSION,
|
|
12
|
+
"2025-06-18",
|
|
13
|
+
"2025-03-26",
|
|
14
|
+
"2024-11-05",
|
|
15
|
+
"2024-10-07"
|
|
16
|
+
];
|
|
17
|
+
var JSONRPC_INVALID_REQUEST = -32600;
|
|
18
|
+
var JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
19
|
+
var JSONRPC_INVALID_PARAMS = -32602;
|
|
20
|
+
var DRAFT_07_SCHEMA_ID = "http://json-schema.org/draft-07/schema#";
|
|
21
|
+
var MCP_INVALID_PARAMS_PREFIX = `MCP error ${JSONRPC_INVALID_PARAMS}: `;
|
|
22
|
+
var EMPTY_OBJECT_JSON_SCHEMA = { type: "object", properties: {} };
|
|
23
|
+
function buildJsonSchema(shape) {
|
|
24
|
+
if (shape === void 0 || Object.keys(shape).length === 0) return { ...EMPTY_OBJECT_JSON_SCHEMA };
|
|
25
|
+
const schema = external_exports.toJSONSchema(external_exports.object(shape), { io: "input" });
|
|
26
|
+
return { ...schema, $schema: DRAFT_07_SCHEMA_ID };
|
|
27
|
+
}
|
|
28
|
+
function describeParseError(error) {
|
|
29
|
+
return error.issues.map((issue) => {
|
|
30
|
+
if (issue.path.length === 0) return issue.message;
|
|
31
|
+
const dotted = issue.path.reduce(
|
|
32
|
+
(acc, seg, i) => i === 0 ? String(seg) : typeof seg === "number" ? `${acc}[${seg}]` : `${acc}.${String(seg)}`,
|
|
33
|
+
""
|
|
34
|
+
);
|
|
35
|
+
return `${issue.message} at ${dotted}`;
|
|
36
|
+
}).join("\n");
|
|
37
|
+
}
|
|
38
|
+
function errorText(message) {
|
|
39
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
40
|
+
}
|
|
41
|
+
function isRequest(message) {
|
|
42
|
+
return "method" in message && "id" in message && message.id !== void 0 && message.id !== null;
|
|
43
|
+
}
|
|
44
|
+
var McpServer = class {
|
|
45
|
+
info;
|
|
46
|
+
tools = /* @__PURE__ */ new Map();
|
|
47
|
+
handlers = /* @__PURE__ */ new Map();
|
|
48
|
+
transport;
|
|
49
|
+
/** Set by the caller to learn when the peer hung up; `mcp-serve` waits on exactly this. */
|
|
50
|
+
onclose;
|
|
51
|
+
constructor(info) {
|
|
52
|
+
this.info = info;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Registers a tool. Schema generation happens here rather than at `tools/list` time, which also
|
|
56
|
+
* means a malformed shape fails loudly at startup instead of on a client's first listing.
|
|
57
|
+
*/
|
|
58
|
+
registerTool(name, definition, handler) {
|
|
59
|
+
if (this.tools.has(name)) throw new Error(`MCP tool registered twice: ${name}`);
|
|
60
|
+
const shape = definition.inputSchema;
|
|
61
|
+
this.tools.set(name, {
|
|
62
|
+
name,
|
|
63
|
+
description: definition.description,
|
|
64
|
+
jsonSchema: buildJsonSchema(shape),
|
|
65
|
+
// An absent shape still needs a validator, so an argumentless tool called with arguments is
|
|
66
|
+
// not silently handed them.
|
|
67
|
+
validator: external_exports.object(shape ?? {})
|
|
68
|
+
});
|
|
69
|
+
this.handlers.set(name, handler);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Wires this server to a transport and starts it.
|
|
73
|
+
*
|
|
74
|
+
* `onmessage` is assigned before `start()` on purpose: a transport may have buffered messages
|
|
75
|
+
* that arrive the moment it starts (the SDK's in-memory transport queues anything sent before a
|
|
76
|
+
* handler exists and drains the queue inside `start()`), so a server that started first would
|
|
77
|
+
* drop the client's `initialize`.
|
|
78
|
+
*/
|
|
79
|
+
async connect(transport) {
|
|
80
|
+
this.transport = transport;
|
|
81
|
+
transport.onmessage = (message) => {
|
|
82
|
+
void this.handleMessage(message);
|
|
83
|
+
};
|
|
84
|
+
transport.onclose = () => {
|
|
85
|
+
this.transport = void 0;
|
|
86
|
+
this.onclose?.();
|
|
87
|
+
};
|
|
88
|
+
await transport.start();
|
|
89
|
+
}
|
|
90
|
+
async close() {
|
|
91
|
+
const transport = this.transport;
|
|
92
|
+
this.transport = void 0;
|
|
93
|
+
await transport?.close();
|
|
94
|
+
}
|
|
95
|
+
async send(message) {
|
|
96
|
+
try {
|
|
97
|
+
await this.transport?.send(message);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async handleMessage(message) {
|
|
102
|
+
if (!isRequest(message)) return;
|
|
103
|
+
const { id, method } = message;
|
|
104
|
+
const params = message.params ?? {};
|
|
105
|
+
try {
|
|
106
|
+
switch (method) {
|
|
107
|
+
case "initialize":
|
|
108
|
+
await this.send({ jsonrpc: "2.0", id, result: this.initializeResult(params) });
|
|
109
|
+
return;
|
|
110
|
+
case "ping":
|
|
111
|
+
await this.send({ jsonrpc: "2.0", id, result: {} });
|
|
112
|
+
return;
|
|
113
|
+
case "tools/list":
|
|
114
|
+
await this.send({ jsonrpc: "2.0", id, result: { tools: this.listTools() } });
|
|
115
|
+
return;
|
|
116
|
+
case "tools/call":
|
|
117
|
+
await this.send({ jsonrpc: "2.0", id, result: await this.callTool(params) });
|
|
118
|
+
return;
|
|
119
|
+
default:
|
|
120
|
+
await this.sendError(id, JSONRPC_METHOD_NOT_FOUND, `Method not found: ${method}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
await this.sendError(id, JSONRPC_INVALID_REQUEST, err instanceof Error ? err.message : String(err));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async sendError(id, code, message) {
|
|
128
|
+
await this.send({ jsonrpc: "2.0", id, error: { code, message } });
|
|
129
|
+
}
|
|
130
|
+
initializeResult(params) {
|
|
131
|
+
const requested = params["protocolVersion"];
|
|
132
|
+
const protocolVersion = typeof requested === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : LATEST_PROTOCOL_VERSION;
|
|
133
|
+
return {
|
|
134
|
+
protocolVersion,
|
|
135
|
+
// Tools only, and they never change after startup, so no `listChanged`. This is the one
|
|
136
|
+
// place we deliberately do not copy the SDK, which declares `listChanged: true` because its
|
|
137
|
+
// McpServer is *able* to send that notification. Token-goat registers every tool before it
|
|
138
|
+
// connects and never adds or removes one, so we would be promising a notification we can
|
|
139
|
+
// never have cause to send. No client behaviour turns on it either way -- a subscription
|
|
140
|
+
// that never fires and an absent subscription are the same thing when the list is fixed --
|
|
141
|
+
// so the honest declaration wins. Contrast the tool-error text below, which a model reads as
|
|
142
|
+
// content and is therefore matched to the SDK exactly.
|
|
143
|
+
capabilities: { tools: {} },
|
|
144
|
+
serverInfo: { name: this.info.name, version: this.info.version }
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
listTools() {
|
|
148
|
+
return [...this.tools.values()].map((tool) => ({
|
|
149
|
+
name: tool.name,
|
|
150
|
+
...tool.description !== void 0 ? { description: tool.description } : {},
|
|
151
|
+
inputSchema: tool.jsonSchema,
|
|
152
|
+
// The SDK emits this for every tool it registers, and it is literally true of ours: we do
|
|
153
|
+
// not implement task augmentation, so a client that asks for it gets refused. Emitting the
|
|
154
|
+
// same thing keeps `tools/list` byte-identical to what token-goat sent before, which is what
|
|
155
|
+
// the differential test in tests/mcp_jsonrpc.test.ts pins.
|
|
156
|
+
execution: { taskSupport: "forbidden" }
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
async callTool(params) {
|
|
160
|
+
const name = params["name"];
|
|
161
|
+
if (typeof name !== "string") return errorText('Invalid params: tools/call requires a string "name"');
|
|
162
|
+
const tool = this.tools.get(name);
|
|
163
|
+
const handler = this.handlers.get(name);
|
|
164
|
+
if (tool === void 0 || handler === void 0) return errorText(`${MCP_INVALID_PARAMS_PREFIX}Tool ${name} not found`);
|
|
165
|
+
const parsed = tool.validator.safeParse(params["arguments"] ?? {});
|
|
166
|
+
if (!parsed.success) {
|
|
167
|
+
return errorText(
|
|
168
|
+
`${MCP_INVALID_PARAMS_PREFIX}Input validation error: Invalid arguments for tool ${name}: ${describeParseError(parsed.error)}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
return await handler(parsed.data);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
return errorText(err instanceof Error ? err.message : String(err));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
export {
|
|
179
|
+
JSONRPC_INVALID_PARAMS,
|
|
180
|
+
JSONRPC_INVALID_REQUEST,
|
|
181
|
+
JSONRPC_METHOD_NOT_FOUND,
|
|
182
|
+
LATEST_PROTOCOL_VERSION,
|
|
183
|
+
McpServer,
|
|
184
|
+
SUPPORTED_PROTOCOL_VERSIONS
|
|
185
|
+
};
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
runSkeleton,
|
|
26
26
|
runSymbol,
|
|
27
27
|
withPinnedReads
|
|
28
|
-
} from "./token-goat-chunk-
|
|
28
|
+
} from "./token-goat-chunk-RMDQFTQD.mjs";
|
|
29
29
|
import {
|
|
30
30
|
buildProjectMap,
|
|
31
31
|
embeddingsDepsAvailable,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
getProjectIndexCounts,
|
|
35
35
|
isWorkerRunning,
|
|
36
36
|
mapLookupBytesSaved
|
|
37
|
-
} from "./token-goat-chunk-
|
|
37
|
+
} from "./token-goat-chunk-2G6RAB4G.mjs";
|
|
38
38
|
import {
|
|
39
39
|
VERSION,
|
|
40
40
|
dataDir,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
normalizePath,
|
|
46
46
|
recordStat,
|
|
47
47
|
resolveProjectRoot
|
|
48
|
-
} from "./token-goat-chunk-
|
|
48
|
+
} from "./token-goat-chunk-ELDJRLHZ.mjs";
|
|
49
49
|
import "./token-goat-chunk-AO2QD2AG.mjs";
|
|
50
50
|
import "./token-goat-chunk-AEX54RUZ.mjs";
|
|
51
51
|
|
|
@@ -201,7 +201,7 @@ function withConfinedRead(pins, fn) {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
async function createMcpServer() {
|
|
204
|
-
const [{ McpServer }, { z }] = await Promise.all([import("
|
|
204
|
+
const [{ McpServer }, { z }] = await Promise.all([import("./token-goat-chunk-5CVKO3DA.mjs"), import("./token-goat-chunk-R4SR7MQY.mjs")]);
|
|
205
205
|
const server = new McpServer({ name: "token-goat", version: VERSION });
|
|
206
206
|
const makeProjectRootField = (verb) => z.string().optional().describe(
|
|
207
207
|
`absolute path to the workspace root to scope this ${verb} to; defaults to the MCP server process's cwd, which is not always the actual workspace root for MCP clients -- pass this explicitly when it might differ`
|