@wootsup/mcp 0.3.0 → 0.4.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 +14 -5
- package/dist/catalog/build-catalog.d.ts +31 -0
- package/dist/catalog/build-catalog.js +68 -0
- package/dist/catalog/build-catalog.js.map +1 -0
- package/dist/index.js +37 -5
- package/dist/index.js.map +1 -1
- package/dist/modules/apimapper/auto-layout.d.ts +21 -0
- package/dist/modules/apimapper/auto-layout.js +54 -0
- package/dist/modules/apimapper/auto-layout.js.map +1 -0
- package/dist/modules/apimapper/client.d.ts +54 -4
- package/dist/modules/apimapper/client.js +145 -14
- package/dist/modules/apimapper/client.js.map +1 -1
- package/dist/modules/apimapper/connections-format.d.ts +31 -1
- package/dist/modules/apimapper/connections-format.js +97 -5
- package/dist/modules/apimapper/connections-format.js.map +1 -1
- package/dist/modules/apimapper/connections.d.ts +9 -7
- package/dist/modules/apimapper/connections.js +225 -58
- package/dist/modules/apimapper/connections.js.map +1 -1
- package/dist/modules/apimapper/credentials.js +86 -14
- package/dist/modules/apimapper/credentials.js.map +1 -1
- package/dist/modules/apimapper/elicitation.d.ts +29 -0
- package/dist/modules/apimapper/elicitation.js +62 -0
- package/dist/modules/apimapper/elicitation.js.map +1 -1
- package/dist/modules/apimapper/example-extract.d.ts +13 -0
- package/dist/modules/apimapper/example-extract.js +111 -0
- package/dist/modules/apimapper/example-extract.js.map +1 -0
- package/dist/modules/apimapper/filter-operators.d.ts +24 -0
- package/dist/modules/apimapper/filter-operators.js +103 -0
- package/dist/modules/apimapper/filter-operators.js.map +1 -0
- package/dist/modules/apimapper/flows-format.js +92 -22
- package/dist/modules/apimapper/flows-format.js.map +1 -1
- package/dist/modules/apimapper/flows.d.ts +8 -7
- package/dist/modules/apimapper/flows.js +216 -44
- package/dist/modules/apimapper/flows.js.map +1 -1
- package/dist/modules/apimapper/gateway/advanced-read-tool.d.ts +9 -0
- package/dist/modules/apimapper/gateway/advanced-read-tool.js +172 -0
- package/dist/modules/apimapper/gateway/advanced-read-tool.js.map +1 -0
- package/dist/modules/apimapper/gateway/advanced-tool.js +39 -130
- package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -1
- package/dist/modules/apimapper/gateway/collect-module-tools.d.ts +17 -0
- package/dist/modules/apimapper/gateway/collect-module-tools.js +44 -0
- package/dist/modules/apimapper/gateway/collect-module-tools.js.map +1 -0
- package/dist/modules/apimapper/gateway/essentials.d.ts +1 -1
- package/dist/modules/apimapper/gateway/essentials.js +19 -7
- package/dist/modules/apimapper/gateway/essentials.js.map +1 -1
- package/dist/modules/apimapper/gateway/gateway-shared.d.ts +21 -0
- package/dist/modules/apimapper/gateway/gateway-shared.js +124 -0
- package/dist/modules/apimapper/gateway/gateway-shared.js.map +1 -0
- package/dist/modules/apimapper/gateway/test-support.d.ts +1 -17
- package/dist/modules/apimapper/gateway/test-support.js +4 -33
- package/dist/modules/apimapper/gateway/test-support.js.map +1 -1
- package/dist/modules/apimapper/get-skill-cores.d.ts +4 -0
- package/dist/modules/apimapper/get-skill-cores.js +220 -0
- package/dist/modules/apimapper/get-skill-cores.js.map +1 -0
- package/dist/modules/apimapper/get-skill.d.ts +1 -1
- package/dist/modules/apimapper/get-skill.js +30 -3
- package/dist/modules/apimapper/get-skill.js.map +1 -1
- package/dist/modules/apimapper/graph-builder.d.ts +85 -2
- package/dist/modules/apimapper/graph-builder.js +151 -15
- package/dist/modules/apimapper/graph-builder.js.map +1 -1
- package/dist/modules/apimapper/graph.js +115 -15
- package/dist/modules/apimapper/graph.js.map +1 -1
- package/dist/modules/apimapper/index.js +25 -13
- package/dist/modules/apimapper/index.js.map +1 -1
- package/dist/modules/apimapper/jmespath-test.d.ts +4 -0
- package/dist/modules/apimapper/jmespath-test.js +152 -0
- package/dist/modules/apimapper/jmespath-test.js.map +1 -0
- package/dist/modules/apimapper/library.js +131 -8
- package/dist/modules/apimapper/library.js.map +1 -1
- package/dist/modules/apimapper/list-footer.d.ts +27 -0
- package/dist/modules/apimapper/list-footer.js +57 -0
- package/dist/modules/apimapper/list-footer.js.map +1 -0
- package/dist/modules/apimapper/local-sources.js +88 -31
- package/dist/modules/apimapper/local-sources.js.map +1 -1
- package/dist/modules/apimapper/mcp-client-identity.d.ts +32 -0
- package/dist/modules/apimapper/mcp-client-identity.js +70 -0
- package/dist/modules/apimapper/mcp-client-identity.js.map +1 -0
- package/dist/modules/apimapper/merge-constants.d.ts +6 -0
- package/dist/modules/apimapper/merge-constants.js +26 -0
- package/dist/modules/apimapper/merge-constants.js.map +1 -0
- package/dist/modules/apimapper/node-schema.d.ts +52 -2
- package/dist/modules/apimapper/node-schema.js +95 -4
- package/dist/modules/apimapper/node-schema.js.map +1 -1
- package/dist/modules/apimapper/onboarding.d.ts +29 -0
- package/dist/modules/apimapper/onboarding.js +117 -9
- package/dist/modules/apimapper/onboarding.js.map +1 -1
- package/dist/modules/apimapper/read-cache.d.ts +16 -3
- package/dist/modules/apimapper/read-cache.js +59 -4
- package/dist/modules/apimapper/read-cache.js.map +1 -1
- package/dist/modules/apimapper/render/index.js +26 -5
- package/dist/modules/apimapper/render/index.js.map +1 -1
- package/dist/modules/apimapper/resource-id.d.ts +13 -0
- package/dist/modules/apimapper/resource-id.js +69 -0
- package/dist/modules/apimapper/resource-id.js.map +1 -0
- package/dist/modules/apimapper/tool-result.d.ts +20 -0
- package/dist/modules/apimapper/tool-result.js +67 -5
- package/dist/modules/apimapper/tool-result.js.map +1 -1
- package/dist/modules/apimapper/toolslist-size.d.ts +10 -10
- package/dist/modules/apimapper/toolslist-size.js +29 -18
- package/dist/modules/apimapper/toolslist-size.js.map +1 -1
- package/dist/modules/apimapper/types.d.ts +13 -0
- package/dist/modules/apimapper/types.js +1 -1
- package/dist/modules/apimapper/types.js.map +1 -1
- package/dist/modules/apimapper/whitelist-drift.js +16 -1
- package/dist/modules/apimapper/whitelist-drift.js.map +1 -1
- package/dist/modules/apimapper/workflows.js +221 -32
- package/dist/modules/apimapper/workflows.js.map +1 -1
- package/dist/modules/apimapper/yootheme-binding.js +103 -22
- package/dist/modules/apimapper/yootheme-binding.js.map +1 -1
- package/dist/platform/index.js +7 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/proxy/bridge.d.ts +35 -0
- package/dist/proxy/bridge.js +129 -0
- package/dist/proxy/bridge.js.map +1 -0
- package/dist/proxy/mode.d.ts +9 -0
- package/dist/proxy/mode.js +20 -0
- package/dist/proxy/mode.js.map +1 -0
- package/dist/setup/probe-auth.d.ts +51 -0
- package/dist/setup/probe-auth.js +141 -0
- package/dist/setup/probe-auth.js.map +1 -0
- package/dist/setup-cli.d.ts +9 -0
- package/dist/setup-cli.js +34 -0
- package/dist/setup-cli.js.map +1 -1
- package/dist/sites/loader.d.ts +7 -0
- package/dist/sites/loader.js +16 -1
- package/dist/sites/loader.js.map +1 -1
- package/dist/skill-instructions.d.ts +14 -1
- package/dist/skill-instructions.js +30 -6
- package/dist/skill-instructions.js.map +1 -1
- package/manifest.json +2 -2
- package/package.json +3 -2
- package/skills/apimapper/SKILL.md +78 -3
- package/skills/apimapper/reference/dynamize-existing-layout.md +158 -0
- package/skills/apimapper/reference/jmespath-cookbook.md +241 -0
- package/skills/apimapper/reference/jmespath-pitfalls.md +81 -0
- package/skills/apimapper/reference/library-template-discovery.md +1 -1
- package/skills/apimapper/reference/merge-two-sources-on-key.md +117 -12
- package/skills/apimapper/reference/oauth.md +143 -52
- package/skills/apimapper/reference/troubleshooting.md +2 -2
- package/skills/apimapper/reference/yootheme-source-to-builder-handoff.md +348 -0
- package/skills/apimapper/reference/yootheme.md +75 -44
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// src/modules/apimapper/gateway/advanced-read-tool.ts — F200b
|
|
2
|
+
//
|
|
3
|
+
// `apimapper_advanced_read` — a READ-ONLY sibling of the `apimapper_advanced`
|
|
4
|
+
// gateway. The Desktop-E2E #2 forensics (2026-06-12) showed every advanced
|
|
5
|
+
// call (even pure reads like flow_get / graph_preview) routed through the
|
|
6
|
+
// single write-capable gateway, whose `creating` annotation makes hosts gate
|
|
7
|
+
// it behind an approval prompt. Most advanced calls in a session are READS.
|
|
8
|
+
//
|
|
9
|
+
// This gateway whitelists ONLY the read-only advanced subtools — derived
|
|
10
|
+
// straight from each subtool's `readOnlyHint` annotation (zero per-provider
|
|
11
|
+
// branching) — and carries a `readOnly` annotation itself, so a host treats
|
|
12
|
+
// the whole read surface as side-effect-free and stops prompting on every
|
|
13
|
+
// discovery / inspect call. Write/mutate/create/destructive subtools stay
|
|
14
|
+
// reachable ONLY through `apimapper_advanced`.
|
|
15
|
+
//
|
|
16
|
+
// Two modes mirror the write gateway:
|
|
17
|
+
// { tool } → discovery (schema + annotations, no invocation)
|
|
18
|
+
// { tool, arguments } → execution (validate against the target's Zod schema,
|
|
19
|
+
// then invoke the captured handler with the same `extra`)
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import { readOnly, errorResult } from "@getimo/mcp-toolkit";
|
|
22
|
+
import { renderGroupedList, shapeOf, discoveryResult, isReadOnlyEntry, } from "./gateway-shared.js";
|
|
23
|
+
import { isEssential } from "./essentials.js";
|
|
24
|
+
/**
|
|
25
|
+
* Builds the read gateway's description: it lists ONLY the read-only subtools,
|
|
26
|
+
* grouped by domain, and steers write/mutate/create/destructive calls to the
|
|
27
|
+
* full `apimapper_advanced` gateway.
|
|
28
|
+
*/
|
|
29
|
+
function buildReadDescription(readNames) {
|
|
30
|
+
const toolCount = readNames.length;
|
|
31
|
+
return (`Routes to the ${toolCount} READ-ONLY advanced API Mapper tools. ` +
|
|
32
|
+
// F214: stop the model habitually routing first-class tools through the
|
|
33
|
+
// gateway (a wasted invalid_arguments cycle each time). State the scope
|
|
34
|
+
// boundary up front, before the grouped-tool list.
|
|
35
|
+
"ONLY for the read-only advanced tools listed below — every tool that " +
|
|
36
|
+
"appears directly in tools/list is FIRST-CLASS: call it directly, never via this gateway. " +
|
|
37
|
+
"All targets are side-effect-free (readOnly), so this gateway can be called " +
|
|
38
|
+
"freely for discovery and inspection without write-confirmation prompts. " +
|
|
39
|
+
"Call with { tool } for a target's schema + annotations, or " +
|
|
40
|
+
"{ tool, arguments } to run it.\n\n" +
|
|
41
|
+
"Available read-only tools by domain:\n" +
|
|
42
|
+
`${renderGroupedList(readNames)}\n\n` +
|
|
43
|
+
"For write / mutate / create / delete tools, use the full apimapper_advanced gateway.");
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Registers `apimapper_advanced_read` on the real McpServer.
|
|
47
|
+
*
|
|
48
|
+
* @param realServer the McpServer that exposes the gateway tool
|
|
49
|
+
* @param advancedRegistry the captured non-essential tools (from CapturingServer)
|
|
50
|
+
*/
|
|
51
|
+
export function registerAdvancedReadTool(realServer, advancedRegistry) {
|
|
52
|
+
// F200b — derive the read whitelist from each subtool's readOnlyHint. This
|
|
53
|
+
// is the SOLE classifier; adding a read-only advanced tool covers it
|
|
54
|
+
// automatically on the next registration, with no list to maintain here.
|
|
55
|
+
const readEntries = new Map();
|
|
56
|
+
for (const [name, entry] of advancedRegistry) {
|
|
57
|
+
if (isReadOnlyEntry(entry))
|
|
58
|
+
readEntries.set(name, entry);
|
|
59
|
+
}
|
|
60
|
+
const readNames = [...readEntries.keys()].sort();
|
|
61
|
+
realServer.registerTool("apimapper_advanced_read", {
|
|
62
|
+
title: "Advanced Read-Only Tool Gateway",
|
|
63
|
+
description: buildReadDescription(readNames),
|
|
64
|
+
inputSchema: {
|
|
65
|
+
// F205 (P2): `tool` is a free string, NOT a z.enum — same trap as the
|
|
66
|
+
// write gateway. The MCP SDK validates the inputSchema before the
|
|
67
|
+
// handler runs; an enum rejected first-class names with a raw McpError
|
|
68
|
+
// -32602 so the handler's not_read_only / first_class_tool / unknown
|
|
69
|
+
// steering never ran. A plain string lets every name reach the handler.
|
|
70
|
+
tool: z
|
|
71
|
+
.string()
|
|
72
|
+
.describe('Read-only advanced tool to route to (e.g. "apimapper_flow_get"). ' +
|
|
73
|
+
"Must be one of the read-only advanced tools listed in this " +
|
|
74
|
+
"gateway's description. First-class tools (apimapper_health, ...) " +
|
|
75
|
+
"are called DIRECTLY; write/mutate tools use apimapper_advanced. " +
|
|
76
|
+
"Omit `arguments` to discover its schema first."),
|
|
77
|
+
arguments: z
|
|
78
|
+
.record(z.string(), z.unknown())
|
|
79
|
+
.optional()
|
|
80
|
+
.describe("Arguments for the target tool. Omit for discovery mode " +
|
|
81
|
+
"(returns the tool's schema + annotations)."),
|
|
82
|
+
},
|
|
83
|
+
// The whole surface is side-effect-free — that is the entire point of
|
|
84
|
+
// this gateway. openWorld:true because the read targets may touch
|
|
85
|
+
// upstream APIs (graph_preview, connection_test, library_* reads).
|
|
86
|
+
annotations: readOnly({ openWorld: true, title: "Advanced Read-Only Tool Gateway" }),
|
|
87
|
+
}, async (args, extra) => {
|
|
88
|
+
const entry = readEntries.get(args.tool);
|
|
89
|
+
if (!entry) {
|
|
90
|
+
// A WRITE subtool name that exists in the FULL registry but not the
|
|
91
|
+
// read whitelist gets a targeted steer to apimapper_advanced; this
|
|
92
|
+
// branch MUST stay ahead of the first_class_tool check (an advanced
|
|
93
|
+
// write subtool is not a first-class tool).
|
|
94
|
+
const existsAsWrite = advancedRegistry.has(args.tool);
|
|
95
|
+
if (existsAsWrite) {
|
|
96
|
+
return errorResult({
|
|
97
|
+
message: `"${args.tool}" is not a read-only tool — it mutates state and is not ` +
|
|
98
|
+
"reachable through apimapper_advanced_read.",
|
|
99
|
+
code: "not_read_only",
|
|
100
|
+
suggestion: `Call it through the full gateway instead: ` +
|
|
101
|
+
`apimapper_advanced({ tool: "${args.tool}", arguments: {...} }).`,
|
|
102
|
+
details: { tool: args.tool },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// F205: a first-class tool name (in tools/list directly) is steered to
|
|
106
|
+
// a direct call rather than treated as a typo.
|
|
107
|
+
if (isEssential(args.tool)) {
|
|
108
|
+
return errorResult({
|
|
109
|
+
message: `"${args.tool}" is a FIRST-CLASS tool — it appears directly in tools/list.`,
|
|
110
|
+
code: "first_class_tool",
|
|
111
|
+
suggestion: `Call "${args.tool}" directly instead of routing it through ` +
|
|
112
|
+
"apimapper_advanced_read. This gateway only routes the read-only " +
|
|
113
|
+
"advanced tools listed in its description.",
|
|
114
|
+
details: { tool: args.tool },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return errorResult({
|
|
118
|
+
message: `Unknown read-only advanced tool: "${args.tool}".`,
|
|
119
|
+
code: "unknown_tool",
|
|
120
|
+
suggestion: "Pick one of the valid read-only advanced tool names below, or use " +
|
|
121
|
+
"apimapper_advanced for write tools.\n\n" +
|
|
122
|
+
`Valid read-only advanced tools by domain:\n${renderGroupedList(readNames)}`,
|
|
123
|
+
details: { valid_tools_by_domain: renderGroupedList(readNames) },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Discovery mode — no arguments supplied.
|
|
127
|
+
if (args.arguments === undefined) {
|
|
128
|
+
return discoveryResult(args.tool, entry);
|
|
129
|
+
}
|
|
130
|
+
// Execution mode — validate against the target's Zod inputSchema.
|
|
131
|
+
// strict() surfaces unknown keys as Zod issues (parity with the write
|
|
132
|
+
// gateway's F-LS-06 behaviour).
|
|
133
|
+
const parsed = z.object(shapeOf(entry)).strict().safeParse(args.arguments);
|
|
134
|
+
if (!parsed.success) {
|
|
135
|
+
let expectedSchema;
|
|
136
|
+
try {
|
|
137
|
+
expectedSchema = z.toJSONSchema(z.object(shapeOf(entry)));
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
expectedSchema = { note: "input schema could not be derived" };
|
|
141
|
+
}
|
|
142
|
+
return errorResult({
|
|
143
|
+
message: `Invalid arguments for "${args.tool}".`,
|
|
144
|
+
code: "invalid_arguments",
|
|
145
|
+
suggestion: `Call apimapper_advanced_read with { tool: "${args.tool}" } to see ` +
|
|
146
|
+
"the expected schema, then retry with corrected arguments.",
|
|
147
|
+
details: {
|
|
148
|
+
issues: parsed.error.issues,
|
|
149
|
+
expected_schema: expectedSchema,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// Invoke the captured handler with the parsed args + the SAME `extra`,
|
|
154
|
+
// so progress / elicitation / AbortSignal of the target tool keep
|
|
155
|
+
// working. A throw is wrapped into a structured errorResult (parity with
|
|
156
|
+
// the write gateway's DEF-LOW-1 guard).
|
|
157
|
+
try {
|
|
158
|
+
return await entry.handler(parsed.data, extra);
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
return errorResult({
|
|
162
|
+
message: e instanceof Error ? e.message : String(e),
|
|
163
|
+
code: "tool_threw",
|
|
164
|
+
suggestion: "The target tool threw instead of returning a structured error. " +
|
|
165
|
+
`Retry via apimapper_advanced_read({ tool: "${args.tool}" }) discovery, ` +
|
|
166
|
+
"then re-run with corrected arguments. If it persists, run apimapper_health.",
|
|
167
|
+
details: { tool: args.tool },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=advanced-read-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advanced-read-tool.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/advanced-read-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,123 +21,12 @@
|
|
|
21
21
|
import { z } from "zod";
|
|
22
22
|
import { creating, errorResult } from "@getimo/mcp-toolkit";
|
|
23
23
|
import { SKILL_TOPICS } from "../get-skill.js";
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
// added below so every advanced tool renders under its own named domain.
|
|
31
|
-
//
|
|
32
|
-
// Forward-looking stems (workflow / onboarding / render / yootheme) are kept
|
|
33
|
-
// too: the latter three are currently L1 essentials (never in the advanced
|
|
34
|
-
// registry), but listing their stems means that if any future advanced tool
|
|
35
|
-
// adopts that prefix it groups correctly instead of leaking into "misc".
|
|
36
|
-
//
|
|
37
|
-
// `misc` stays last as the explicit catch-all. `domainOf` matches a stem to a
|
|
38
|
-
// domain by exact match or `${domain}_` prefix, and `groupByDomain` drops any
|
|
39
|
-
// domain with zero tools — so unused stems (e.g. workflow, the legacy
|
|
40
|
-
// `diagnostics` placeholder) cost nothing in the rendered output.
|
|
41
|
-
const DOMAIN_ORDER = [
|
|
42
|
-
"connection",
|
|
43
|
-
"credential",
|
|
44
|
-
"flow",
|
|
45
|
-
"graph",
|
|
46
|
-
"library",
|
|
47
|
-
"license",
|
|
48
|
-
"settings",
|
|
49
|
-
"cache",
|
|
50
|
-
"local_source",
|
|
51
|
-
"schema",
|
|
52
|
-
"diagnostics",
|
|
53
|
-
"release",
|
|
54
|
-
"brandfetch",
|
|
55
|
-
"feedback",
|
|
56
|
-
"features",
|
|
57
|
-
"health",
|
|
58
|
-
"inspect",
|
|
59
|
-
"node_snapshot",
|
|
60
|
-
"platform",
|
|
61
|
-
"workflow",
|
|
62
|
-
"onboarding",
|
|
63
|
-
"render",
|
|
64
|
-
"yootheme",
|
|
65
|
-
"misc",
|
|
66
|
-
];
|
|
67
|
-
/** Maps a tool name to its display domain (the segment after `apimapper_`). */
|
|
68
|
-
function domainOf(toolName) {
|
|
69
|
-
const stem = toolName.replace(/^apimapper_/, "");
|
|
70
|
-
for (const domain of DOMAIN_ORDER) {
|
|
71
|
-
if (stem === domain || stem.startsWith(`${domain}_`))
|
|
72
|
-
return domain;
|
|
73
|
-
}
|
|
74
|
-
return "misc";
|
|
75
|
-
}
|
|
76
|
-
/** Groups tool names by domain, in DOMAIN_ORDER, for stable output. */
|
|
77
|
-
function groupByDomain(toolNames) {
|
|
78
|
-
const groups = new Map();
|
|
79
|
-
for (const domain of DOMAIN_ORDER)
|
|
80
|
-
groups.set(domain, []);
|
|
81
|
-
for (const name of [...toolNames].sort()) {
|
|
82
|
-
const domain = domainOf(name);
|
|
83
|
-
const bucket = groups.get(domain);
|
|
84
|
-
if (bucket)
|
|
85
|
-
bucket.push(name);
|
|
86
|
-
}
|
|
87
|
-
for (const [domain, names] of groups) {
|
|
88
|
-
if (names.length === 0)
|
|
89
|
-
groups.delete(domain);
|
|
90
|
-
}
|
|
91
|
-
return groups;
|
|
92
|
-
}
|
|
93
|
-
/** Renders the grouped tool list as readable text (used in description + errors). */
|
|
94
|
-
function renderGroupedList(toolNames) {
|
|
95
|
-
const groups = groupByDomain(toolNames);
|
|
96
|
-
const lines = [];
|
|
97
|
-
for (const [domain, names] of groups) {
|
|
98
|
-
lines.push(` ${domain}: ${names.join(", ")}`);
|
|
99
|
-
}
|
|
100
|
-
return lines.join("\n");
|
|
101
|
-
}
|
|
102
|
-
/** Reads the captured config's inputSchema as a Zod raw-shape (or empty). */
|
|
103
|
-
function shapeOf(entry) {
|
|
104
|
-
const schema = entry.config.inputSchema;
|
|
105
|
-
if (schema && typeof schema === "object")
|
|
106
|
-
return schema;
|
|
107
|
-
return {};
|
|
108
|
-
}
|
|
109
|
-
/** Builds the discovery-mode result for a target tool. */
|
|
110
|
-
function discoveryResult(toolName, entry) {
|
|
111
|
-
const cfg = entry.config;
|
|
112
|
-
let schema;
|
|
113
|
-
try {
|
|
114
|
-
schema = z.toJSONSchema(z.object(shapeOf(entry)));
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
// A schema that cannot be JSON-projected still yields a usable discovery
|
|
118
|
-
// payload — the description and annotations carry the rest.
|
|
119
|
-
schema = { note: "input schema could not be derived" };
|
|
120
|
-
}
|
|
121
|
-
const payload = {
|
|
122
|
-
tool: toolName,
|
|
123
|
-
description: cfg.description ?? "",
|
|
124
|
-
inputSchema: schema,
|
|
125
|
-
annotations: cfg.annotations ?? {},
|
|
126
|
-
};
|
|
127
|
-
return {
|
|
128
|
-
content: [
|
|
129
|
-
{
|
|
130
|
-
type: "text",
|
|
131
|
-
text: `Discovery for ${toolName}\n\n` +
|
|
132
|
-
`${cfg.description ?? ""}\n\n` +
|
|
133
|
-
`Annotations: ${JSON.stringify(cfg.annotations ?? {})}\n\n` +
|
|
134
|
-
`Input schema:\n${JSON.stringify(schema, null, 2)}\n\n` +
|
|
135
|
-
`Call apimapper_advanced again with { tool: "${toolName}", arguments: {...} } to run it.`,
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
structuredContent: payload,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
24
|
+
import { isEssential } from "./essentials.js";
|
|
25
|
+
// F200b — the domain grouping + discovery machinery is shared with the
|
|
26
|
+
// read-only sibling gateway (apimapper_advanced_read). It lives in
|
|
27
|
+
// gateway-shared.ts so the two surfaces render identical groupings and can
|
|
28
|
+
// never drift.
|
|
29
|
+
import { groupByDomain, renderGroupedList, shapeOf, discoveryResult, } from "./gateway-shared.js";
|
|
141
30
|
/** Builds the gateway tool's description, grouping every advanced tool by domain. */
|
|
142
31
|
function buildDescription(toolNames) {
|
|
143
32
|
const toolCount = toolNames.length;
|
|
@@ -150,6 +39,11 @@ function buildDescription(toolNames) {
|
|
|
150
39
|
// the LLM size the gateway at-a-glance before scanning the grouped list.
|
|
151
40
|
return (`Routes to ${toolCount} advanced API Mapper tools across ${domainCount} ` +
|
|
152
41
|
`domain${domainCount === 1 ? "" : "s"} (${domainList}). ` +
|
|
42
|
+
// F214: stop the model habitually routing first-class tools through the
|
|
43
|
+
// gateway (a wasted invalid_arguments cycle each time). State the scope
|
|
44
|
+
// boundary up front, before the grouped-tool list.
|
|
45
|
+
"ONLY for the advanced tools listed below — every tool that appears " +
|
|
46
|
+
"directly in tools/list is FIRST-CLASS: call it directly, never via this gateway. " +
|
|
153
47
|
"Call with { tool } for a target's schema + annotations, or " +
|
|
154
48
|
"{ tool, arguments } to run it. The target tool's own confirmation " +
|
|
155
49
|
"guards and behavior stay in effect.\n\n" +
|
|
@@ -168,25 +62,27 @@ function buildDescription(toolNames) {
|
|
|
168
62
|
*/
|
|
169
63
|
export function registerAdvancedTool(realServer, advancedRegistry) {
|
|
170
64
|
const advancedNames = [...advancedRegistry.keys()].sort();
|
|
171
|
-
// z.enum needs a non-empty tuple. In production the advanced registry
|
|
172
|
-
// always holds the captured advanced tools, so the empty-registry arm is
|
|
173
|
-
// exercised only by test wiring with a zero-tool registry; it is kept as a
|
|
174
|
-
// defensive guard so a future zero-tool wiring still yields a valid
|
|
175
|
-
// (if inert) gateway schema rather than a z.enum construction crash.
|
|
176
|
-
// F-1.3 (Pass-1 consolidation): the `__none__` placeholder is now covered
|
|
177
|
-
// by a real assertion in gateway/advanced-tool.test.ts — the previous
|
|
178
|
-
// v8-ignore directive has been removed.
|
|
179
|
-
const enumValues = advancedNames.length > 0
|
|
180
|
-
? advancedNames
|
|
181
|
-
: ["__none__"];
|
|
182
65
|
realServer.registerTool("apimapper_advanced", {
|
|
183
66
|
title: "Advanced Tool Gateway",
|
|
184
67
|
description: buildDescription(advancedNames),
|
|
185
68
|
inputSchema: {
|
|
69
|
+
// F205 (P2): `tool` is a free string, NOT a z.enum. The MCP SDK
|
|
70
|
+
// validates the gateway inputSchema BEFORE our handler runs; an enum
|
|
71
|
+
// rejected every first-class tool name (apimapper_health,
|
|
72
|
+
// apimapper_flow_full_recompile_publish, ...) with a raw McpError
|
|
73
|
+
// -32602, so the friendly first_class_tool / unknown_tool steering in
|
|
74
|
+
// the handler NEVER ran. A plain string lets every name reach the
|
|
75
|
+
// handler, which routes it: advanced → run; first-class → "call it
|
|
76
|
+
// directly"; unknown → grouped suggestion. renderGroupedList in the
|
|
77
|
+
// description stays the load-bearing discovery surface.
|
|
186
78
|
tool: z
|
|
187
|
-
.
|
|
79
|
+
.string()
|
|
188
80
|
.describe('Advanced tool to route to (e.g. "apimapper_flow_get"). ' +
|
|
189
|
-
"
|
|
81
|
+
"Must be one of the advanced tools listed in this gateway's " +
|
|
82
|
+
"description — first-class tools (apimapper_health, " +
|
|
83
|
+
"apimapper_flow_setup_with_sources, ...) are called DIRECTLY, " +
|
|
84
|
+
"not through this gateway. Omit `arguments` to discover its " +
|
|
85
|
+
"schema first."),
|
|
190
86
|
arguments: z
|
|
191
87
|
.record(z.string(), z.unknown())
|
|
192
88
|
.optional()
|
|
@@ -197,6 +93,19 @@ export function registerAdvancedTool(realServer, advancedRegistry) {
|
|
|
197
93
|
}, async (args, extra) => {
|
|
198
94
|
const entry = advancedRegistry.get(args.tool);
|
|
199
95
|
if (!entry) {
|
|
96
|
+
// F205: a name that is a first-class tool (in tools/list directly)
|
|
97
|
+
// is a different error than a typo. Steer the caller to call it
|
|
98
|
+
// directly instead of routing through the gateway.
|
|
99
|
+
if (isEssential(args.tool)) {
|
|
100
|
+
return errorResult({
|
|
101
|
+
message: `"${args.tool}" is a FIRST-CLASS tool — it appears directly in tools/list.`,
|
|
102
|
+
code: "first_class_tool",
|
|
103
|
+
suggestion: `Call "${args.tool}" directly instead of routing it through ` +
|
|
104
|
+
"apimapper_advanced. This gateway only routes the advanced " +
|
|
105
|
+
"(non-essential) tools listed in its description.",
|
|
106
|
+
details: { tool: args.tool },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
200
109
|
return errorResult({
|
|
201
110
|
message: `Unknown advanced tool: "${args.tool}".`,
|
|
202
111
|
code: "unknown_tool",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advanced-tool.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/advanced-tool.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,2EAA2E;AAC3E,6DAA6D;AAC7D,EAAE;AACF,aAAa;AACb,wEAAwE;AACxE,8EAA8E;AAC9E,4EAA4E;AAC5E,qCAAqC;AACrC,4EAA4E;AAC5E,8EAA8E;AAC9E,yEAAyE;AACzE,4EAA4E;AAC5E,sEAAsE;AACtE,EAAE;AACF,2EAA2E;AAC3E,0DAA0D;AAI1D,OAAO,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"advanced-tool.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/advanced-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { ApimapperRestModule } from "../index.js";
|
|
4
|
+
/** A tool entry as seen by tests: handler + the registered config. */
|
|
5
|
+
export interface CollectedTool {
|
|
6
|
+
handler: (args: Record<string, unknown>, extra?: unknown) => CallToolResult | Promise<CallToolResult>;
|
|
7
|
+
title?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
inputSchema?: unknown;
|
|
10
|
+
annotations?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Returns every API Mapper tool — the essentials registered on the real
|
|
14
|
+
* McpServer plus the advanced tools captured in the gateway registry —
|
|
15
|
+
* keyed by tool name. `module.register(server)` must have run first.
|
|
16
|
+
*/
|
|
17
|
+
export declare function collectModuleTools(server: McpServer, module: ApimapperRestModule): Record<string, CollectedTool>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/modules/apimapper/gateway/collect-module-tools.ts — unified tool view
|
|
2
|
+
//
|
|
3
|
+
// After the W3.4 Gateway-Hub, advanced (non-essential) tools no longer live
|
|
4
|
+
// in McpServer._registeredTools — they are captured into the advanced
|
|
5
|
+
// registry behind `apimapper_advanced`. `collectModuleTools` returns a unified
|
|
6
|
+
// view of every tool (essentials on the real server + advanced from the
|
|
7
|
+
// registry), keeping lookup semantics identical to the pre-gateway behaviour.
|
|
8
|
+
//
|
|
9
|
+
// Used by tests (via test-support.ts re-export) AND by the build/release path
|
|
10
|
+
// (catalog/build-catalog.ts, toolslist-size.ts), so it lives in its own
|
|
11
|
+
// non-test module — it is NOT a test-only helper.
|
|
12
|
+
/**
|
|
13
|
+
* Returns every API Mapper tool — the essentials registered on the real
|
|
14
|
+
* McpServer plus the advanced tools captured in the gateway registry —
|
|
15
|
+
* keyed by tool name. `module.register(server)` must have run first.
|
|
16
|
+
*/
|
|
17
|
+
export function collectModuleTools(server, module) {
|
|
18
|
+
const result = {};
|
|
19
|
+
const realTools = server._registeredTools;
|
|
20
|
+
for (const [name, tool] of Object.entries(realTools)) {
|
|
21
|
+
result[name] = {
|
|
22
|
+
handler: tool.handler,
|
|
23
|
+
title: tool.title,
|
|
24
|
+
description: tool.description,
|
|
25
|
+
inputSchema: tool.inputSchema,
|
|
26
|
+
annotations: tool.annotations,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const advanced = module.getAdvancedRegistry();
|
|
30
|
+
if (advanced) {
|
|
31
|
+
for (const [name, entry] of advanced) {
|
|
32
|
+
const cfg = entry.config;
|
|
33
|
+
result[name] = {
|
|
34
|
+
handler: entry.handler,
|
|
35
|
+
title: cfg.title,
|
|
36
|
+
description: cfg.description,
|
|
37
|
+
inputSchema: cfg.inputSchema,
|
|
38
|
+
annotations: cfg.annotations,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=collect-module-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-module-tools.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/collect-module-tools.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,+EAA+E;AAC/E,wEAAwE;AACxE,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,wEAAwE;AACxE,kDAAkD;AA0BlD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAiB,EACjB,MAA2B;IAE3B,MAAM,MAAM,GAAkC,EAAE,CAAC;IAEjD,MAAM,SAAS,GACb,MACD,CAAC,gBAAgB,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,KAAK,CAAC,MAKjB,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,GAAG;gBACb,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;aAC7B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Tools kept as first-class entries in tools/list (Cursor-cap-safe surface). */
|
|
2
|
-
export declare const ESSENTIAL_TOOLS: readonly ["apimapper_onboarding", "apimapper_diagnose", "apimapper_list_profiles", "apimapper_use_profile", "apimapper_library_featured", "apimapper_library_list", "apimapper_library_activate", "apimapper_connection_list", "apimapper_connection_create", "apimapper_connection_data", "apimapper_credential_list", "apimapper_oauth_authorize_begin", "apimapper_flow_setup_with_sources", "apimapper_flow_full_recompile_publish", "apimapper_yootheme_binding_for_flow", "apimapper_render", "apimapper_get_skill"];
|
|
2
|
+
export declare const ESSENTIAL_TOOLS: readonly ["apimapper_onboarding", "apimapper_diagnose", "apimapper_list_profiles", "apimapper_use_profile", "apimapper_library_featured", "apimapper_library_list", "apimapper_library_activate", "apimapper_health", "apimapper_connection_list", "apimapper_connection_create", "apimapper_connection_data", "apimapper_credential_list", "apimapper_oauth_authorize_begin", "apimapper_flow_setup_with_sources", "apimapper_flow_full_recompile_publish", "apimapper_yootheme_binding_for_flow", "apimapper_render", "apimapper_get_skill"];
|
|
3
3
|
export type EssentialTool = (typeof ESSENTIAL_TOOLS)[number];
|
|
4
4
|
export declare function isEssential(name: string): boolean;
|
|
@@ -2,13 +2,24 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Single source of truth for the "essentials" surface: the tools kept as
|
|
4
4
|
// first-class entries in `tools/list`. Cursor caps MCP servers at ~40 tools;
|
|
5
|
-
// the API Mapper adapter has
|
|
6
|
-
// essentials + the apimapper_advanced gateway
|
|
7
|
-
// + 3 tools registered directly in
|
|
8
|
-
// are routed through the
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// this comment cites what that
|
|
5
|
+
// the API Mapper adapter has 81 registered tools (18 module-real = 16 module
|
|
6
|
+
// essentials + the apimapper_advanced gateway + the apimapper_advanced_read
|
|
7
|
+
// gateway, + 60 advanced-registry tools, + 3 tools registered directly in
|
|
8
|
+
// src/index.ts), so all but the essentials are routed through the gateways
|
|
9
|
+
// (see advanced-tool.ts / advanced-read-tool.ts). That keeps the first-class
|
|
10
|
+
// `tools/list` surface at 21 — well under the cap. The canonical counts are
|
|
11
|
+
// asserted live in gateway/gateway.test.ts (A2); this comment cites what that
|
|
12
|
+
// test proves.
|
|
13
|
+
//
|
|
14
|
+
// F115 (2026-06-11): apimapper_health promoted from the advanced registry to
|
|
15
|
+
// a module-registered essential — the documented "run this first" verify tool
|
|
16
|
+
// was itself only reachable via the gateway (first-call deadend). This shifts
|
|
17
|
+
// module essentials 15→16, advanced 60→59 (total then 79).
|
|
18
|
+
//
|
|
19
|
+
// F200b (2026-06-12): apimapper_advanced_read added as a 2nd module-real
|
|
20
|
+
// gateway — module-real 17→18, surface 20→21, total 80→81. It whitelists the
|
|
21
|
+
// read-only advanced subtools (readOnlyHint-derived) and carries a readOnly
|
|
22
|
+
// annotation so hosts stop prompting on every advanced read.
|
|
12
23
|
/** Tools kept as first-class entries in tools/list (Cursor-cap-safe surface). */
|
|
13
24
|
export const ESSENTIAL_TOOLS = [
|
|
14
25
|
"apimapper_onboarding",
|
|
@@ -18,6 +29,7 @@ export const ESSENTIAL_TOOLS = [
|
|
|
18
29
|
"apimapper_library_featured",
|
|
19
30
|
"apimapper_library_list",
|
|
20
31
|
"apimapper_library_activate",
|
|
32
|
+
"apimapper_health",
|
|
21
33
|
"apimapper_connection_list",
|
|
22
34
|
"apimapper_connection_create",
|
|
23
35
|
"apimapper_connection_data",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"essentials.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/essentials.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"essentials.js","sourceRoot":"","sources":["../../../../src/modules/apimapper/gateway/essentials.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,eAAe;AACf,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,2DAA2D;AAC3D,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,6DAA6D;AAE7D,iFAAiF;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,sBAAsB;IACtB,oBAAoB;IACpB,yBAAyB;IACzB,uBAAuB;IACvB,4BAA4B;IAC5B,wBAAwB;IACxB,4BAA4B;IAC5B,kBAAkB;IAClB,2BAA2B;IAC3B,6BAA6B;IAC7B,2BAA2B;IAC3B,2BAA2B;IAC3B,iCAAiC;IACjC,mCAAmC;IACnC,uCAAuC;IACvC,qCAAqC;IACrC,kBAAkB;IAClB,qBAAqB;CACb,CAAC;AAUX,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAQ,eAAqC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { type ZodRawShape } from "zod";
|
|
3
|
+
import type { AdvancedToolEntry } from "./capturing-server.js";
|
|
4
|
+
export declare const DOMAIN_ORDER: readonly ["connection", "credential", "flow", "graph", "library", "license", "settings", "cache", "local_source", "schema", "diagnostics", "release", "brandfetch", "feedback", "features", "health", "inspect", "node_snapshot", "platform", "workflow", "onboarding", "render", "yootheme", "misc"];
|
|
5
|
+
/** Maps a tool name to its display domain (the segment after `apimapper_`). */
|
|
6
|
+
export declare function domainOf(toolName: string): string;
|
|
7
|
+
/** Groups tool names by domain, in DOMAIN_ORDER, for stable output. */
|
|
8
|
+
export declare function groupByDomain(toolNames: string[]): Map<string, string[]>;
|
|
9
|
+
/** Renders the grouped tool list as readable text (used in description + errors). */
|
|
10
|
+
export declare function renderGroupedList(toolNames: string[]): string;
|
|
11
|
+
/** Reads the captured config's inputSchema as a Zod raw-shape (or empty). */
|
|
12
|
+
export declare function shapeOf(entry: AdvancedToolEntry): ZodRawShape;
|
|
13
|
+
/**
|
|
14
|
+
* F200b: a registry entry is read-only when its annotation carries
|
|
15
|
+
* `readOnlyHint === true`. This is the SOLE classifier for the read gateway's
|
|
16
|
+
* whitelist — derived from the subtool's own annotation, zero per-provider
|
|
17
|
+
* branching.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isReadOnlyEntry(entry: AdvancedToolEntry): boolean;
|
|
20
|
+
/** Builds the discovery-mode result for a target tool. */
|
|
21
|
+
export declare function discoveryResult(toolName: string, entry: AdvancedToolEntry): CallToolResult;
|