@guuey/config 0.6.1 → 0.7.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/dist/agent.d.ts +72 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +106 -3
- package/package.json +1 -1
package/dist/agent.d.ts
CHANGED
|
@@ -134,9 +134,33 @@ export declare const McpServerEntrySchema: z.ZodUnion<readonly [z.ZodDiscriminat
|
|
|
134
134
|
}, z.core.$strict>], "kind">, z.ZodLiteral<false>]>;
|
|
135
135
|
export type DeclaredMcpServers = Record<string, GuueyAgentMcpServer | false>;
|
|
136
136
|
/**
|
|
137
|
-
* Tool-gate block — allowlist
|
|
138
|
-
*
|
|
139
|
-
*
|
|
137
|
+
* Tool-gate block — `allowlist` first (the model may call ONLY these), then
|
|
138
|
+
* `denylist` subtracts (removed from the model's catalog outright). Both
|
|
139
|
+
* optional; both empty/absent → every tool of every connected server.
|
|
140
|
+
*
|
|
141
|
+
* Entry shapes (guuey#234 — the ONE grammar, parsed by
|
|
142
|
+
* {@link parseToolGateEntry}, validated at deploy time by
|
|
143
|
+
* {@link validateToolGates}, and translated to the framework's own tool
|
|
144
|
+
* names by the host at turn time):
|
|
145
|
+
*
|
|
146
|
+
* - `"<server>.<tool>"` — one tool of one declared MCP server
|
|
147
|
+
* (`"todoist.create_task"`).
|
|
148
|
+
* - `"<server>.*"` — every tool of one declared server (`"ggui.*"`).
|
|
149
|
+
* - `"<tool>"` — a bare name: that tool on EVERY connected server
|
|
150
|
+
* (`"search"`), and — for a Claude agent on a GuueyFS-armed pod — the
|
|
151
|
+
* built-in file tool of that name (`"Bash"`, `"Write"`, …).
|
|
152
|
+
*
|
|
153
|
+
* `<server>` must name a server this agent connects: a declared
|
|
154
|
+
* `mcpServers` key, the platform default `ggui` (unless opted out with
|
|
155
|
+
* `ggui: false`), or a platform-injected reserved server
|
|
156
|
+
* ({@link RESERVED_MCP_SERVER_NAMES}). The framework-internal spellings
|
|
157
|
+
* (`mcp__server__tool`) are NOT accepted — write the config grammar and
|
|
158
|
+
* let the host translate.
|
|
159
|
+
*
|
|
160
|
+
* Runtime posture (Claude): a tool the model picks that is NOT in an explicit
|
|
161
|
+
* allowlist is DENIED with a message the model can read — never routed to an
|
|
162
|
+
* interactive prompt (a headless pod has no one to answer one). Deny-listed
|
|
163
|
+
* tools never reach the model's catalog at all.
|
|
140
164
|
*/
|
|
141
165
|
declare const ToolGatesSchema: z.ZodObject<{
|
|
142
166
|
allowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -409,6 +433,51 @@ export declare const RESERVED_MCP_SERVER_NAMES: readonly string[];
|
|
|
409
433
|
* {@link validateNoProxiedServers}'s shape.
|
|
410
434
|
*/
|
|
411
435
|
export declare function validateReservedServerNames(agent: GuueyAgent | undefined): string[];
|
|
436
|
+
/** One parsed `tools.allowlist` / `tools.denylist` entry. */
|
|
437
|
+
export type ToolGateEntry =
|
|
438
|
+
/** `"<server>.<tool>"` — one tool of one server. */
|
|
439
|
+
{
|
|
440
|
+
kind: 'server-tool';
|
|
441
|
+
server: string;
|
|
442
|
+
tool: string;
|
|
443
|
+
}
|
|
444
|
+
/** `"<server>.*"` — every tool of one server. */
|
|
445
|
+
| {
|
|
446
|
+
kind: 'server-all';
|
|
447
|
+
server: string;
|
|
448
|
+
}
|
|
449
|
+
/** `"<tool>"` — that tool on every connected server (and the built-in of that name). */
|
|
450
|
+
| {
|
|
451
|
+
kind: 'bare';
|
|
452
|
+
tool: string;
|
|
453
|
+
};
|
|
454
|
+
/**
|
|
455
|
+
* Parse one tool-gate entry per the {@link ToolGatesSchema} grammar. Returns
|
|
456
|
+
* the parsed shape, or a human-readable reason string when the entry is
|
|
457
|
+
* malformed (never throws — callers decide whether to reject or report).
|
|
458
|
+
*/
|
|
459
|
+
export declare function parseToolGateEntry(raw: string): ToolGateEntry | {
|
|
460
|
+
error: string;
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* The server names a tool-gate entry may qualify with: every EFFECTIVE server
|
|
464
|
+
* (declared map with the platform default seeded and `ggui: false` honoured —
|
|
465
|
+
* {@link effectiveMcpServers}) plus the platform-injected reserved servers
|
|
466
|
+
* ({@link RESERVED_MCP_SERVER_NAMES}: memory / profile, spliced at invoke time
|
|
467
|
+
* for authenticated callers).
|
|
468
|
+
*/
|
|
469
|
+
export declare function toolGateServerNames(agent: GuueyAgent | undefined): string[];
|
|
470
|
+
/**
|
|
471
|
+
* Validate `agent.tools.allowlist` / `agent.tools.denylist` at deploy time
|
|
472
|
+
* (guuey#234). Every entry must parse per {@link parseToolGateEntry}, and a
|
|
473
|
+
* server-qualified entry must name a server this agent connects
|
|
474
|
+
* ({@link toolGateServerNames}). Returns a list of human-readable violation
|
|
475
|
+
* messages (empty = clean). Tool-level existence against a server's live
|
|
476
|
+
* manifest is NOT checked here (a hosted server's tool set is only known once
|
|
477
|
+
* it is connected) — that is why the host DENIES an unlisted pick at turn time
|
|
478
|
+
* instead of prompting.
|
|
479
|
+
*/
|
|
480
|
+
export declare function validateToolGates(agent: GuueyAgent | undefined): string[];
|
|
412
481
|
/**
|
|
413
482
|
* Platform default MCP server map. Seeded under every declared map by
|
|
414
483
|
* {@link effectiveMcpServers} (opt out with `ggui: false`). Exposed here so
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,6EAKnB,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAS/D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;EAAiC,CAAC;AAClE,uEAAuE;AACvE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA+GhE;;;;;;;;GAQG;AACH,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAKnB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAA+C,CAAC;AACjF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,KAAK,CAAC,CAAC;AAE7E
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -193,9 +193,33 @@ const McpServerSchema = z.discriminatedUnion('kind', [
|
|
|
193
193
|
*/
|
|
194
194
|
export const McpServerEntrySchema = z.union([McpServerSchema, z.literal(false)]);
|
|
195
195
|
/**
|
|
196
|
-
* Tool-gate block — allowlist
|
|
197
|
-
*
|
|
198
|
-
*
|
|
196
|
+
* Tool-gate block — `allowlist` first (the model may call ONLY these), then
|
|
197
|
+
* `denylist` subtracts (removed from the model's catalog outright). Both
|
|
198
|
+
* optional; both empty/absent → every tool of every connected server.
|
|
199
|
+
*
|
|
200
|
+
* Entry shapes (guuey#234 — the ONE grammar, parsed by
|
|
201
|
+
* {@link parseToolGateEntry}, validated at deploy time by
|
|
202
|
+
* {@link validateToolGates}, and translated to the framework's own tool
|
|
203
|
+
* names by the host at turn time):
|
|
204
|
+
*
|
|
205
|
+
* - `"<server>.<tool>"` — one tool of one declared MCP server
|
|
206
|
+
* (`"todoist.create_task"`).
|
|
207
|
+
* - `"<server>.*"` — every tool of one declared server (`"ggui.*"`).
|
|
208
|
+
* - `"<tool>"` — a bare name: that tool on EVERY connected server
|
|
209
|
+
* (`"search"`), and — for a Claude agent on a GuueyFS-armed pod — the
|
|
210
|
+
* built-in file tool of that name (`"Bash"`, `"Write"`, …).
|
|
211
|
+
*
|
|
212
|
+
* `<server>` must name a server this agent connects: a declared
|
|
213
|
+
* `mcpServers` key, the platform default `ggui` (unless opted out with
|
|
214
|
+
* `ggui: false`), or a platform-injected reserved server
|
|
215
|
+
* ({@link RESERVED_MCP_SERVER_NAMES}). The framework-internal spellings
|
|
216
|
+
* (`mcp__server__tool`) are NOT accepted — write the config grammar and
|
|
217
|
+
* let the host translate.
|
|
218
|
+
*
|
|
219
|
+
* Runtime posture (Claude): a tool the model picks that is NOT in an explicit
|
|
220
|
+
* allowlist is DENIED with a message the model can read — never routed to an
|
|
221
|
+
* interactive prompt (a headless pod has no one to answer one). Deny-listed
|
|
222
|
+
* tools never reach the model's catalog at all.
|
|
199
223
|
*/
|
|
200
224
|
const ToolGatesSchema = z.strictObject({
|
|
201
225
|
allowlist: z.array(z.string().min(1)).optional(),
|
|
@@ -607,6 +631,85 @@ export function validateReservedServerNames(agent) {
|
|
|
607
631
|
}
|
|
608
632
|
return violations;
|
|
609
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* The framework-internal MCP tool-name prefix (Claude Agent SDK:
|
|
636
|
+
* `mcp__<server>__<tool>`). Rejected in config — builders write the
|
|
637
|
+
* `<server>.<tool>` grammar; the host translates.
|
|
638
|
+
*/
|
|
639
|
+
const SDK_INTERNAL_TOOL_PREFIX = /^mcp__/;
|
|
640
|
+
/**
|
|
641
|
+
* Parse one tool-gate entry per the {@link ToolGatesSchema} grammar. Returns
|
|
642
|
+
* the parsed shape, or a human-readable reason string when the entry is
|
|
643
|
+
* malformed (never throws — callers decide whether to reject or report).
|
|
644
|
+
*/
|
|
645
|
+
export function parseToolGateEntry(raw) {
|
|
646
|
+
const entry = raw.trim();
|
|
647
|
+
if (entry.length === 0)
|
|
648
|
+
return { error: 'empty entry' };
|
|
649
|
+
if (SDK_INTERNAL_TOOL_PREFIX.test(entry)) {
|
|
650
|
+
return {
|
|
651
|
+
error: `"${entry}" uses the framework-internal spelling — write "<server>.<tool>" (or "<server>.*", or a bare tool name) instead`,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
const dot = entry.indexOf('.');
|
|
655
|
+
if (dot === -1)
|
|
656
|
+
return { kind: 'bare', tool: entry };
|
|
657
|
+
const server = entry.slice(0, dot);
|
|
658
|
+
const tool = entry.slice(dot + 1);
|
|
659
|
+
if (server.length === 0)
|
|
660
|
+
return { error: `"${entry}" has an empty server name before the dot` };
|
|
661
|
+
if (tool.length === 0)
|
|
662
|
+
return { error: `"${entry}" has an empty tool name after the dot` };
|
|
663
|
+
if (tool === '*')
|
|
664
|
+
return { kind: 'server-all', server };
|
|
665
|
+
if (tool.includes('*')) {
|
|
666
|
+
return { error: `"${entry}": wildcards are only valid as the whole tool part ("${server}.*")` };
|
|
667
|
+
}
|
|
668
|
+
return { kind: 'server-tool', server, tool };
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* The server names a tool-gate entry may qualify with: every EFFECTIVE server
|
|
672
|
+
* (declared map with the platform default seeded and `ggui: false` honoured —
|
|
673
|
+
* {@link effectiveMcpServers}) plus the platform-injected reserved servers
|
|
674
|
+
* ({@link RESERVED_MCP_SERVER_NAMES}: memory / profile, spliced at invoke time
|
|
675
|
+
* for authenticated callers).
|
|
676
|
+
*/
|
|
677
|
+
export function toolGateServerNames(agent) {
|
|
678
|
+
return [
|
|
679
|
+
...Object.keys(effectiveMcpServers(agent?.mcpServers)),
|
|
680
|
+
...RESERVED_MCP_SERVER_NAMES,
|
|
681
|
+
];
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Validate `agent.tools.allowlist` / `agent.tools.denylist` at deploy time
|
|
685
|
+
* (guuey#234). Every entry must parse per {@link parseToolGateEntry}, and a
|
|
686
|
+
* server-qualified entry must name a server this agent connects
|
|
687
|
+
* ({@link toolGateServerNames}). Returns a list of human-readable violation
|
|
688
|
+
* messages (empty = clean). Tool-level existence against a server's live
|
|
689
|
+
* manifest is NOT checked here (a hosted server's tool set is only known once
|
|
690
|
+
* it is connected) — that is why the host DENIES an unlisted pick at turn time
|
|
691
|
+
* instead of prompting.
|
|
692
|
+
*/
|
|
693
|
+
export function validateToolGates(agent) {
|
|
694
|
+
const violations = [];
|
|
695
|
+
const gates = agent?.tools;
|
|
696
|
+
if (!gates)
|
|
697
|
+
return violations;
|
|
698
|
+
const known = new Set(toolGateServerNames(agent));
|
|
699
|
+
for (const list of ['allowlist', 'denylist']) {
|
|
700
|
+
for (const raw of gates[list] ?? []) {
|
|
701
|
+
const parsed = parseToolGateEntry(raw);
|
|
702
|
+
if ('error' in parsed) {
|
|
703
|
+
violations.push(`tools.${list}: ${parsed.error}`);
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
if (parsed.kind !== 'bare' && !known.has(parsed.server)) {
|
|
707
|
+
violations.push(`tools.${list}: "${raw}" names MCP server "${parsed.server}", which this agent does not connect — declare it under mcpServers or use one of: ${[...known].join(', ')}`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return violations;
|
|
712
|
+
}
|
|
610
713
|
/**
|
|
611
714
|
* Platform default MCP server map. Seeded under every declared map by
|
|
612
715
|
* {@link effectiveMcpServers} (opt out with `ggui: false`). Exposed here so
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guuey/config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Open-source schemas + loaders for the three guuey config files: agent.json (declarative agent definition), guuey.json (hosted-deploy overlay), and the helper types around them. Consumed by @guuey/cli, the guuey backend, and devs writing their own agent or MCP server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|