@zapier/connectors-sdk 0.1.0-experimental.1 → 0.1.0-experimental.10
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.internal.md +0 -26
- package/dist/index.cjs +174 -48
- package/dist/index.d.cts +49 -52
- package/dist/index.d.ts +49 -52
- package/dist/index.js +173 -48
- package/package.json +5 -5
package/README.internal.md
CHANGED
|
@@ -346,32 +346,6 @@ A multi-credential resolver `{ name: "hmac", keySuffixes: ["KEY", "SECRET"] }` w
|
|
|
346
346
|
|
|
347
347
|
The author never sees `process.env`, never threads a `Fetch` through their script body, never re-implements auth logic.
|
|
348
348
|
|
|
349
|
-
## `inputDependencies` — out-of-band dependent-field metadata
|
|
350
|
-
|
|
351
|
-
Some scripts have input fields whose accepted shape depends on another input field — e.g. Notion's `create_database_item` takes a `databaseId` and a `properties` map whose schema is determined by which database was chosen. JSON Schema can't express that conditional shape, but adapters that drive option-loading or schema-resolution chains need to know about it.
|
|
352
|
-
|
|
353
|
-
`defineTool` publishes the metadata in two places:
|
|
354
|
-
|
|
355
|
-
1. `definition.inputDependencies` — programmatic readers reach for it directly on the script's default export.
|
|
356
|
-
2. MCP registration shape — `_meta["zapier:inputDependencies"]` via either `toMcpTool` (wire-format) or `toMcpServerTool` (`McpServer.registerTool` config).
|
|
357
|
-
|
|
358
|
-
Shape constraints:
|
|
359
|
-
|
|
360
|
-
- Dependencies are keyed by the dependent input field's name (`databaseId`, `properties`).
|
|
361
|
-
- Each entry names another tool by **string** (`fromTool: "list-databases"`), not by function reference — so the chain stays serializable.
|
|
362
|
-
- Args passed to the resolver tool use `$<fieldName>` syntax to reference other input fields (`fromArgs: { databaseId: "$databaseId" }`). The adapter reads and evaluates these references; the script body does not.
|
|
363
|
-
|
|
364
|
-
```ts
|
|
365
|
-
inputDependencies: {
|
|
366
|
-
databaseId: { kind: "options", fromTool: "list-databases", fromArgs: {} },
|
|
367
|
-
properties: {
|
|
368
|
-
kind: "schema",
|
|
369
|
-
fromTool: "get-database-schema",
|
|
370
|
-
fromArgs: { databaseId: "$databaseId" },
|
|
371
|
-
},
|
|
372
|
-
} as const,
|
|
373
|
-
```
|
|
374
|
-
|
|
375
349
|
## `<bin> mcp` — local-MCP-server execution surface
|
|
376
350
|
|
|
377
351
|
Reached through the bundled CLI as `npx @zapier/<x>-connector mcp` — no per-app glue. The dispatcher reserves the primary command `mcp` and delegates to the internal `serveMcpStdio` helper:
|
package/dist/index.cjs
CHANGED
|
@@ -109,6 +109,7 @@ function defineConnectionResolver(resolver) {
|
|
|
109
109
|
}
|
|
110
110
|
var zapierConnectionResolver = defineConnectionResolver({
|
|
111
111
|
name: "zapier-connection-id",
|
|
112
|
+
optionalPackages: ["@zapier/zapier-sdk"],
|
|
112
113
|
resolve: async (connectionId) => {
|
|
113
114
|
const { buildZapierFetch: buildZapierFetch2 } = await Promise.resolve().then(() => (init_build_zapier_fetch(), build_zapier_fetch_exports));
|
|
114
115
|
return buildZapierFetch2(connectionId);
|
|
@@ -128,12 +129,16 @@ function defineBearerTokenResolver(opts = {}) {
|
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
|
|
132
|
+
// src/normalize-connections.ts
|
|
133
|
+
var import_node_module = require("module");
|
|
134
|
+
|
|
131
135
|
// src/connection-key.ts
|
|
132
136
|
function envFromKey(name) {
|
|
133
137
|
return name.toUpperCase().replace(/-/g, "_");
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
// src/normalize-connections.ts
|
|
141
|
+
var import_meta = {};
|
|
137
142
|
function* walkConnections(definition) {
|
|
138
143
|
if (typeof definition.connection === "string") {
|
|
139
144
|
yield { slotName: void 0, connectionKey: definition.connection };
|
|
@@ -267,23 +272,70 @@ function buildRunOptionsFromEnv(definition, env, connectionResolvers) {
|
|
|
267
272
|
}
|
|
268
273
|
return { connections: wrapped };
|
|
269
274
|
}
|
|
270
|
-
function
|
|
275
|
+
function isPackageInstalled(name) {
|
|
276
|
+
try {
|
|
277
|
+
(0, import_node_module.createRequire)(import_meta.url).resolve(name);
|
|
278
|
+
return true;
|
|
279
|
+
} catch {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function formatHelpForConnections(definition, connectionResolvers, env) {
|
|
271
284
|
const slots = [...walkConnections(definition)];
|
|
272
285
|
if (slots.length === 0) return [];
|
|
273
286
|
const lines = [];
|
|
274
287
|
lines.push(
|
|
275
|
-
"
|
|
288
|
+
"Auth (set as environment variables; do NOT pass via CLI argument):"
|
|
276
289
|
);
|
|
290
|
+
const notReadySlots = [];
|
|
277
291
|
for (const { slotName, connectionKey } of slots) {
|
|
278
292
|
const resolvers = resolversForKey(connectionResolvers, connectionKey);
|
|
279
|
-
|
|
280
|
-
|
|
293
|
+
if (slotName !== void 0) {
|
|
294
|
+
lines.push(` ${slotName} (${connectionKey}):`);
|
|
295
|
+
}
|
|
296
|
+
const resolverIndent = slotName !== void 0 ? " " : " ";
|
|
297
|
+
const varIndent = slotName !== void 0 ? " " : " ";
|
|
298
|
+
let slotHasReady = false;
|
|
281
299
|
for (const resolver of resolvers) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
300
|
+
const vars = envVarsFor(slotName, connectionKey, resolver);
|
|
301
|
+
let isReady = false;
|
|
302
|
+
let missingPkgs = [];
|
|
303
|
+
if (env !== void 0) {
|
|
304
|
+
const envVarsOk = vars.every(
|
|
305
|
+
(k) => typeof env[k] === "string" && env[k] !== ""
|
|
306
|
+
);
|
|
307
|
+
if (envVarsOk) isReady = true;
|
|
308
|
+
missingPkgs = (resolver.optionalPackages ?? []).filter(
|
|
309
|
+
(pkg) => !isPackageInstalled(pkg)
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const markReady = isReady && !slotHasReady;
|
|
313
|
+
if (markReady) slotHasReady = true;
|
|
314
|
+
const resolverSuffix = env !== void 0 && markReady ? " [READY \u2014 use this]" : "";
|
|
315
|
+
lines.push(`${resolverIndent}${resolver.name}:${resolverSuffix}`);
|
|
316
|
+
for (const envVar of vars) {
|
|
317
|
+
const varSuffix = env !== void 0 ? env[envVar] !== void 0 && env[envVar] !== "" ? " [set]" : " [not set]" : "";
|
|
318
|
+
lines.push(`${varIndent}${envVar}${varSuffix}`);
|
|
319
|
+
}
|
|
320
|
+
if (env !== void 0) {
|
|
321
|
+
for (const pkg of resolver.optionalPackages ?? []) {
|
|
322
|
+
if (missingPkgs.includes(pkg)) {
|
|
323
|
+
lines.push(
|
|
324
|
+
`${varIndent}${pkg} [not installed \u2014 run \`npm install ${pkg}\` first]`
|
|
325
|
+
);
|
|
326
|
+
} else {
|
|
327
|
+
lines.push(`${varIndent}${pkg} [installed]`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
285
330
|
}
|
|
286
331
|
}
|
|
332
|
+
if (env !== void 0 && !slotHasReady) {
|
|
333
|
+
notReadySlots.push(slotName ?? connectionKey);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (env !== void 0 && notReadySlots.length > 0) {
|
|
337
|
+
const label = notReadySlots.length === slots.length ? "No option is ready" : `No option is ready for slot${notReadySlots.length > 1 ? "s" : ""} ${notReadySlots.join(", ")}`;
|
|
338
|
+
lines.push(`${label} \u2014 set one of the env vars above.`);
|
|
287
339
|
}
|
|
288
340
|
return lines;
|
|
289
341
|
}
|
|
@@ -368,8 +420,8 @@ function ensureConnectionValue(scriptName, slotName, connectionKey, value) {
|
|
|
368
420
|
return value;
|
|
369
421
|
}
|
|
370
422
|
async function buildContext(definition, opts, connectionResolvers) {
|
|
371
|
-
const hasConnection = "connection" in opts && opts.connection !== void 0;
|
|
372
|
-
const hasConnections = "connections" in opts && opts.connections !== void 0;
|
|
423
|
+
const hasConnection = opts !== void 0 && "connection" in opts && opts.connection !== void 0;
|
|
424
|
+
const hasConnections = opts !== void 0 && "connections" in opts && opts.connections !== void 0;
|
|
373
425
|
if (definition.connection === void 0 && definition.connections === void 0) {
|
|
374
426
|
if (hasConnection || hasConnections) {
|
|
375
427
|
throw new Error(
|
|
@@ -378,6 +430,11 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
378
430
|
}
|
|
379
431
|
return {};
|
|
380
432
|
}
|
|
433
|
+
if (opts === void 0) {
|
|
434
|
+
throw new Error(
|
|
435
|
+
`ToolDefinition "${definition.name}": \`RunOptions\` is required \u2014 pass \`{ connection: ... }\` or \`{ connections: ... }\`.`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
381
438
|
if (hasConnection && hasConnections) {
|
|
382
439
|
throw new Error(
|
|
383
440
|
`ToolDefinition "${definition.name}": \`RunOptions\` sets both \`connection\` and \`connections\`. Use one or the other.`
|
|
@@ -395,7 +452,7 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
395
452
|
definition.name,
|
|
396
453
|
void 0,
|
|
397
454
|
connectionKey,
|
|
398
|
-
opts.connection
|
|
455
|
+
"connection" in opts ? opts.connection : void 0
|
|
399
456
|
);
|
|
400
457
|
const fetch = await resolveSlotFetch(
|
|
401
458
|
definition.name,
|
|
@@ -412,12 +469,12 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
412
469
|
`ToolDefinition "${definition.name}" is multi-connection (slots: ${declaredSlots.join(", ")}) \u2014 call with \`{ connections: { ... } }\`, not \`{ connection: ... }\`.`
|
|
413
470
|
);
|
|
414
471
|
}
|
|
415
|
-
|
|
472
|
+
const provided = opts.connections;
|
|
473
|
+
if (provided === void 0) {
|
|
416
474
|
throw new Error(
|
|
417
475
|
`ToolDefinition "${definition.name}" is multi-connection \u2014 \`RunOptions.connections\` is required.`
|
|
418
476
|
);
|
|
419
477
|
}
|
|
420
|
-
const provided = opts.connections;
|
|
421
478
|
const unknown = Object.keys(provided).filter(
|
|
422
479
|
(s) => !declaredSlots.includes(s)
|
|
423
480
|
);
|
|
@@ -471,28 +528,18 @@ function toChatCompletionTool(definition) {
|
|
|
471
528
|
|
|
472
529
|
// src/surfaces/to-mcp-server-tool.ts
|
|
473
530
|
function toMcpServerTool(definition) {
|
|
474
|
-
|
|
531
|
+
return {
|
|
475
532
|
title: definition.title,
|
|
476
533
|
description: definition.description,
|
|
477
534
|
inputSchema: definition.inputSchema,
|
|
478
535
|
outputSchema: definition.outputSchema,
|
|
479
536
|
annotations: definition.annotations
|
|
480
537
|
};
|
|
481
|
-
if (definition.inputDependencies) {
|
|
482
|
-
config._meta = {
|
|
483
|
-
"zapier:inputDependencies": definition.inputDependencies
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
return config;
|
|
487
538
|
}
|
|
488
539
|
|
|
489
540
|
// src/surfaces/to-mcp-tool.ts
|
|
490
541
|
var import_zod2 = require("zod");
|
|
491
542
|
function toMcpTool(definition) {
|
|
492
|
-
const meta = {};
|
|
493
|
-
if (definition.inputDependencies) {
|
|
494
|
-
meta["zapier:inputDependencies"] = definition.inputDependencies;
|
|
495
|
-
}
|
|
496
543
|
return {
|
|
497
544
|
name: definition.name,
|
|
498
545
|
title: definition.title,
|
|
@@ -501,8 +548,7 @@ function toMcpTool(definition) {
|
|
|
501
548
|
outputSchema: import_zod2.z.toJSONSchema(
|
|
502
549
|
definition.outputSchema
|
|
503
550
|
),
|
|
504
|
-
annotations: definition.annotations
|
|
505
|
-
...Object.keys(meta).length > 0 ? { _meta: meta } : {}
|
|
551
|
+
annotations: definition.annotations
|
|
506
552
|
};
|
|
507
553
|
}
|
|
508
554
|
|
|
@@ -516,24 +562,9 @@ function toResponsesTool(definition) {
|
|
|
516
562
|
|
|
517
563
|
// src/define-connector.ts
|
|
518
564
|
function wrapScriptWithResolvers(definition, connectionResolvers) {
|
|
519
|
-
const authorRun = definition.run;
|
|
520
565
|
const wrappedRun = async (input, opts) => {
|
|
521
|
-
const validated = definition.inputSchema.parse(input);
|
|
522
|
-
if (definition.connection === void 0 && definition.connections === void 0) {
|
|
523
|
-
if (opts !== void 0 && (opts.connection !== void 0 || opts.connections !== void 0)) {
|
|
524
|
-
throw new Error(
|
|
525
|
-
`ToolDefinition "${definition.name}" is credential-free \u2014 \`RunOptions\` must not include \`connection\` or \`connections\`.`
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
return authorRun(validated);
|
|
529
|
-
}
|
|
530
|
-
if (opts === void 0) {
|
|
531
|
-
throw new Error(
|
|
532
|
-
`ToolDefinition "${definition.name}": \`RunOptions\` is required \u2014 pass \`{ connection: ... }\` or \`{ connections: ... }\`.`
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
566
|
const ctx = await buildContext(definition, opts, connectionResolvers);
|
|
536
|
-
return
|
|
567
|
+
return definition.run(input, ctx);
|
|
537
568
|
};
|
|
538
569
|
return { ...definition, run: wrappedRun };
|
|
539
570
|
}
|
|
@@ -543,6 +574,11 @@ function defineConnector(config) {
|
|
|
543
574
|
validateConnectionResolvers(scriptsAsAny, connectionResolvers);
|
|
544
575
|
const wrapped = {};
|
|
545
576
|
for (const [key, definition] of Object.entries(scriptsAsAny)) {
|
|
577
|
+
if (key !== definition.name) {
|
|
578
|
+
throw new Error(
|
|
579
|
+
`defineConnector: script key "${key}" must match its tool name \u2014 got name "${definition.name}". Rename the key to "${definition.name}" or update the tool's name field.`
|
|
580
|
+
);
|
|
581
|
+
}
|
|
546
582
|
wrapped[key] = wrapScriptWithResolvers(definition, connectionResolvers);
|
|
547
583
|
}
|
|
548
584
|
return {
|
|
@@ -612,6 +648,12 @@ function defineTool(config) {
|
|
|
612
648
|
validateConnectionKey(config.name, value);
|
|
613
649
|
}
|
|
614
650
|
}
|
|
651
|
+
const authorRun = config.run;
|
|
652
|
+
const wrappedRun = async (input, ctx) => {
|
|
653
|
+
const validated = config.inputSchema.parse(input);
|
|
654
|
+
const result = await authorRun(validated, ctx);
|
|
655
|
+
return config.outputSchema.parse(result);
|
|
656
|
+
};
|
|
615
657
|
const base = {
|
|
616
658
|
kind: "tool",
|
|
617
659
|
name: config.name,
|
|
@@ -620,9 +662,7 @@ function defineTool(config) {
|
|
|
620
662
|
inputSchema: config.inputSchema,
|
|
621
663
|
outputSchema: config.outputSchema,
|
|
622
664
|
annotations: config.annotations,
|
|
623
|
-
|
|
624
|
-
inputDependencies: config.inputDependencies,
|
|
625
|
-
run: config.run
|
|
665
|
+
run: wrappedRun
|
|
626
666
|
};
|
|
627
667
|
if (hasSingular) base.connection = config.connection;
|
|
628
668
|
if (hasPlural) base.connections = config.connections;
|
|
@@ -766,10 +806,73 @@ async function runDispatchCliBody(connector, opts) {
|
|
|
766
806
|
});
|
|
767
807
|
return;
|
|
768
808
|
}
|
|
809
|
+
if (first === "skill") {
|
|
810
|
+
if (!opts.meta) {
|
|
811
|
+
throw new Error(
|
|
812
|
+
"runDispatchCliBody: `skill` requires `meta` in options (the connector's `import.meta` from `cli.ts`)."
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
const cliPath = (0, import_node_url2.fileURLToPath)(opts.meta.url);
|
|
816
|
+
const connectorDir = path2.dirname(cliPath);
|
|
817
|
+
const skillPath = path2.join(connectorDir, "SKILL.md");
|
|
818
|
+
let content;
|
|
819
|
+
try {
|
|
820
|
+
content = await fs2.readFile(skillPath, "utf8");
|
|
821
|
+
} catch {
|
|
822
|
+
throw new Error(
|
|
823
|
+
`SKILL.md not found at ${skillPath}. Ensure the connector ships a SKILL.md.`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
opts.stdout.write(resolveRelativeLinks(content, connectorDir));
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
if (first === "reference") {
|
|
830
|
+
if (!opts.meta) {
|
|
831
|
+
throw new Error(
|
|
832
|
+
"runDispatchCliBody: `reference` requires `meta` in options (the connector's `import.meta` from `cli.ts`)."
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
const cliPath = (0, import_node_url2.fileURLToPath)(opts.meta.url);
|
|
836
|
+
const connectorDir = path2.dirname(cliPath);
|
|
837
|
+
const refsDir = path2.join(connectorDir, "references");
|
|
838
|
+
const name = args[1];
|
|
839
|
+
if (!name) {
|
|
840
|
+
let entries;
|
|
841
|
+
try {
|
|
842
|
+
const files = await fs2.readdir(refsDir);
|
|
843
|
+
entries = files.filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -".md".length));
|
|
844
|
+
} catch {
|
|
845
|
+
entries = [];
|
|
846
|
+
}
|
|
847
|
+
if (entries.length === 0) {
|
|
848
|
+
opts.stdout.write(`Available references: <none>
|
|
849
|
+
`);
|
|
850
|
+
} else {
|
|
851
|
+
opts.stdout.write(`Available references:
|
|
852
|
+
`);
|
|
853
|
+
for (const entry of entries) {
|
|
854
|
+
opts.stdout.write(` ${entry}
|
|
855
|
+
`);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const refPath = path2.join(refsDir, `${name}.md`);
|
|
861
|
+
let content;
|
|
862
|
+
try {
|
|
863
|
+
content = await fs2.readFile(refPath, "utf8");
|
|
864
|
+
} catch {
|
|
865
|
+
throw new Error(
|
|
866
|
+
`Reference file not found at ${refPath}. Ensure the connector ships \`references/${name}.md\`.`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
opts.stdout.write(resolveRelativeLinks(content, refsDir));
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
769
872
|
if (first !== "run") {
|
|
770
873
|
printUsage(scripts, errOut, packageName);
|
|
771
874
|
throw new Error(
|
|
772
|
-
`Unknown command "${first}". Use \`run <script>\` to dispatch a script (available: ${Object.keys(scripts).join(", ") || "<none>"}),
|
|
875
|
+
`Unknown command "${first}". Use \`run <script>\` to dispatch a script (available: ${Object.keys(scripts).join(", ") || "<none>"}), \`mcp\` to boot a local MCP server, \`skill\` to print SKILL.md, or \`reference [<name>]\` to print or list reference docs.`
|
|
773
876
|
);
|
|
774
877
|
}
|
|
775
878
|
const scriptName = args[1];
|
|
@@ -796,6 +899,17 @@ async function runDispatchCliBody(connector, opts) {
|
|
|
796
899
|
invocation
|
|
797
900
|
});
|
|
798
901
|
}
|
|
902
|
+
function resolveRelativeLinks(content, baseDir) {
|
|
903
|
+
return content.replace(
|
|
904
|
+
/(!?\[([^\]]*)\])\(([^)]+)\)/g,
|
|
905
|
+
(match, prefix, _alt, url) => {
|
|
906
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file:") || url.startsWith("#") || url.startsWith("/")) {
|
|
907
|
+
return match;
|
|
908
|
+
}
|
|
909
|
+
return `${prefix}(${path2.resolve(baseDir, url)})`;
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
}
|
|
799
913
|
async function resolvePackageName(meta) {
|
|
800
914
|
if (!meta?.url) return void 0;
|
|
801
915
|
try {
|
|
@@ -814,6 +928,8 @@ function printUsage(scripts, out, packageName) {
|
|
|
814
928
|
`Usage: <bin> run <script> [<json-input>]
|
|
815
929
|
<bin> run <script> --help (per-script input + required env vars)
|
|
816
930
|
<bin> mcp (run as a local MCP server over stdio)
|
|
931
|
+
<bin> skill (print SKILL.md to stdout)
|
|
932
|
+
<bin> reference [<name>] (print references/<name>.md, or list all)
|
|
817
933
|
|
|
818
934
|
`
|
|
819
935
|
);
|
|
@@ -926,12 +1042,13 @@ async function handleIfScriptMainBody(wrappedScript, connectionResolvers, io) {
|
|
|
926
1042
|
if (helpRequested) {
|
|
927
1043
|
io.stdout.write(
|
|
928
1044
|
buildHelpText(wrappedScript, connectionResolvers, {
|
|
929
|
-
invocation: io.invocation
|
|
1045
|
+
invocation: io.invocation,
|
|
1046
|
+
env: io.env
|
|
930
1047
|
})
|
|
931
1048
|
);
|
|
932
1049
|
return;
|
|
933
1050
|
}
|
|
934
|
-
const raw = positional ?? await
|
|
1051
|
+
const raw = positional ?? await readStdinInput(io.stdin, wrappedScript.name);
|
|
935
1052
|
if (raw.trim().length === 0) {
|
|
936
1053
|
throw new Error(
|
|
937
1054
|
`Missing JSON input for "${wrappedScript.name}". Pass it as a positional argument or via stdin.`
|
|
@@ -943,6 +1060,14 @@ async function handleIfScriptMainBody(wrappedScript, connectionResolvers, io) {
|
|
|
943
1060
|
const result = await wrappedScript.run(input, runOpts);
|
|
944
1061
|
io.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
945
1062
|
}
|
|
1063
|
+
async function readStdinInput(stdin, scriptName) {
|
|
1064
|
+
if (stdin.isTTY) {
|
|
1065
|
+
throw new Error(
|
|
1066
|
+
`Missing JSON input for "${scriptName}". Pass it as a positional argument or pipe it via stdin.`
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
return new Response(stdin).text();
|
|
1070
|
+
}
|
|
946
1071
|
function buildHelpText(definition, connectionResolvers, opts = {}) {
|
|
947
1072
|
const lines = [];
|
|
948
1073
|
const description = definition.description.split("\n")[0]?.trim() ?? "";
|
|
@@ -966,7 +1091,8 @@ function buildHelpText(definition, connectionResolvers, opts = {}) {
|
|
|
966
1091
|
}
|
|
967
1092
|
const connectionsBlock = formatHelpForConnections(
|
|
968
1093
|
definition,
|
|
969
|
-
connectionResolvers
|
|
1094
|
+
connectionResolvers,
|
|
1095
|
+
opts.env
|
|
970
1096
|
);
|
|
971
1097
|
if (connectionsBlock.length > 0) {
|
|
972
1098
|
lines.push(...connectionsBlock);
|
package/dist/index.d.cts
CHANGED
|
@@ -30,24 +30,6 @@ type Replace<S extends string, From extends string, To extends string> = S exten
|
|
|
30
30
|
*/
|
|
31
31
|
type EnvFromKey<K extends string> = Uppercase<Replace<K, "-", "_">>;
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* A Zapier policy statement. Carried on the `ToolDefinition` for in-process
|
|
35
|
-
* governance consumers (policy engines that wrap `script.run` before HTTP).
|
|
36
|
-
* Not propagated to MCP `_meta` — only `inputDependencies` is published over
|
|
37
|
-
* the wire (`_meta["zapier:inputDependencies"]`) by `toMcpTool` /
|
|
38
|
-
* `toMcpServerTool`.
|
|
39
|
-
*/
|
|
40
|
-
interface Statement {
|
|
41
|
-
effect: "allow" | "ask" | "deny";
|
|
42
|
-
permissions: ReadonlyArray<string>;
|
|
43
|
-
resources: ReadonlyArray<string>;
|
|
44
|
-
conditions?: ReadonlyArray<{
|
|
45
|
-
path: ReadonlyArray<string>;
|
|
46
|
-
operator: string;
|
|
47
|
-
value: unknown;
|
|
48
|
-
}>;
|
|
49
|
-
label?: string;
|
|
50
|
-
}
|
|
51
33
|
/**
|
|
52
34
|
* Single-credential resolver: the resolver's `name` IS the credential
|
|
53
35
|
* descriptor. `resolve` receives the credential as a plain `string` —
|
|
@@ -68,6 +50,12 @@ interface Statement {
|
|
|
68
50
|
interface SingleConnectionResolver<TName extends string = string> {
|
|
69
51
|
readonly name: TName;
|
|
70
52
|
readonly keySuffixes?: undefined;
|
|
53
|
+
/**
|
|
54
|
+
* npm package names that must be installed for this resolver to function
|
|
55
|
+
* at runtime. Declared here so `--help` can check availability and tell
|
|
56
|
+
* the agent which packages to install before using this resolver.
|
|
57
|
+
*/
|
|
58
|
+
readonly optionalPackages?: readonly string[];
|
|
71
59
|
resolve: (credential: string) => typeof globalThis.fetch | Promise<typeof globalThis.fetch>;
|
|
72
60
|
}
|
|
73
61
|
/**
|
|
@@ -86,6 +74,12 @@ interface SingleConnectionResolver<TName extends string = string> {
|
|
|
86
74
|
interface MultiConnectionResolver<TName extends string = string, TSuffixes extends readonly string[] = readonly string[]> {
|
|
87
75
|
readonly name: TName;
|
|
88
76
|
readonly keySuffixes: TSuffixes;
|
|
77
|
+
/**
|
|
78
|
+
* npm package names that must be installed for this resolver to function
|
|
79
|
+
* at runtime. Declared here so `--help` can check availability and tell
|
|
80
|
+
* the agent which packages to install before using this resolver.
|
|
81
|
+
*/
|
|
82
|
+
readonly optionalPackages?: readonly string[];
|
|
89
83
|
resolve: (credentials: Record<TSuffixes[number], string>) => typeof globalThis.fetch | Promise<typeof globalThis.fetch>;
|
|
90
84
|
}
|
|
91
85
|
/** Either resolver shape. */
|
|
@@ -160,43 +154,45 @@ interface RunOptionsMulti<TSlots extends string = string, TPerSlot extends Recor
|
|
|
160
154
|
connections: TPerSlot;
|
|
161
155
|
}
|
|
162
156
|
type RunOptions<TSlots extends string = string, TValue = ConnectionValue, TPerSlot extends Record<TSlots, ConnectionValue> = Record<TSlots, ConnectionValue>> = RunOptionsNone | RunOptionsSingle<TValue> | RunOptionsMulti<TSlots, TPerSlot>;
|
|
157
|
+
/** Author-facing context for a credential-free script. */
|
|
158
|
+
interface ContextNone {
|
|
159
|
+
fetch?: undefined;
|
|
160
|
+
connections?: undefined;
|
|
161
|
+
}
|
|
163
162
|
/** Author-facing context for a single-connection script. */
|
|
164
163
|
interface ContextSingle {
|
|
165
164
|
fetch: typeof globalThis.fetch;
|
|
165
|
+
connections?: never;
|
|
166
166
|
}
|
|
167
167
|
/** Author-facing context for a multi-connection script. */
|
|
168
168
|
interface ContextMulti<TSlots extends string = string> {
|
|
169
|
+
fetch?: never;
|
|
169
170
|
connections: Record<TSlots, typeof globalThis.fetch>;
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
/** When authoring omits `inputDependencies`, the definition value is `undefined`. */
|
|
173
|
-
type InputDependenciesValue<T> = [T] extends [undefined] ? undefined : T;
|
|
174
|
-
interface DefineToolConfigBase<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> {
|
|
172
|
+
interface DefineToolConfigBase<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> {
|
|
175
173
|
name: TName;
|
|
176
174
|
title: string;
|
|
177
175
|
description: string;
|
|
178
176
|
inputSchema: TIn;
|
|
179
177
|
outputSchema: TOut;
|
|
180
178
|
annotations: _modelcontextprotocol_sdk_types_js.Tool["annotations"];
|
|
181
|
-
statements?: ReadonlyArray<Statement>;
|
|
182
|
-
inputDependencies?: TInputDependencies;
|
|
183
179
|
}
|
|
184
|
-
interface DefineToolConfigNone<TIn extends z.
|
|
180
|
+
interface DefineToolConfigNone<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
185
181
|
connection?: never;
|
|
186
182
|
connections?: never;
|
|
187
|
-
run: (input: z.infer<TIn
|
|
183
|
+
run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<unknown>;
|
|
188
184
|
}
|
|
189
|
-
interface DefineToolConfigSingle<TIn extends z.
|
|
185
|
+
interface DefineToolConfigSingle<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
190
186
|
connection: TKey;
|
|
191
187
|
connections?: never;
|
|
192
|
-
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<
|
|
188
|
+
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<unknown>;
|
|
193
189
|
}
|
|
194
|
-
interface DefineToolConfigMulti<TIn extends z.
|
|
190
|
+
interface DefineToolConfigMulti<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string, TSlots extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
195
191
|
connection?: never;
|
|
196
192
|
connections: Record<TSlots, TKey>;
|
|
197
|
-
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<
|
|
193
|
+
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<unknown>;
|
|
198
194
|
}
|
|
199
|
-
interface ToolDefinitionBase<TIn extends z.
|
|
195
|
+
interface ToolDefinitionBase<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> {
|
|
200
196
|
readonly kind: "tool";
|
|
201
197
|
readonly name: TName;
|
|
202
198
|
readonly title: string;
|
|
@@ -204,30 +200,26 @@ interface ToolDefinitionBase<TIn extends z.ZodType, TOut extends z.ZodType, TInp
|
|
|
204
200
|
inputSchema: TIn;
|
|
205
201
|
outputSchema: TOut;
|
|
206
202
|
readonly annotations: _modelcontextprotocol_sdk_types_js.Tool["annotations"];
|
|
207
|
-
readonly statements: ReadonlyArray<Statement> | undefined;
|
|
208
|
-
inputDependencies: InputDependenciesValue<TInputDependencies>;
|
|
209
203
|
}
|
|
210
|
-
interface ToolDefinitionNone<TIn extends z.
|
|
204
|
+
interface ToolDefinitionNone<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
211
205
|
readonly connection?: undefined;
|
|
212
206
|
readonly connections?: undefined;
|
|
213
|
-
|
|
214
|
-
run: (input: z.infer<TIn>) => Promise<z.infer<TOut>>;
|
|
207
|
+
run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<z.infer<TOut>>;
|
|
215
208
|
}
|
|
216
|
-
interface ToolDefinitionSingle<TIn extends z.
|
|
209
|
+
interface ToolDefinitionSingle<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
217
210
|
readonly connection: TKey;
|
|
218
211
|
readonly connections?: undefined;
|
|
219
212
|
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<z.infer<TOut>>;
|
|
220
213
|
}
|
|
221
|
-
interface ToolDefinitionMulti<TIn extends z.
|
|
214
|
+
interface ToolDefinitionMulti<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TSlots extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
222
215
|
readonly connection?: undefined;
|
|
223
216
|
readonly connections: Record<TSlots, TKey>;
|
|
224
217
|
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<z.infer<TOut>>;
|
|
225
218
|
}
|
|
226
|
-
type ToolDefinition<TIn extends z.
|
|
219
|
+
type ToolDefinition<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TSlots extends string = string, TKey extends string = string> = ToolDefinitionNone<TIn, TOut, TName> | ToolDefinitionSingle<TIn, TOut, TName, TKey> | ToolDefinitionMulti<TIn, TOut, TName, TSlots, TKey>;
|
|
227
220
|
/** Wide author-side `run` signature for polymorphic walks. */
|
|
228
221
|
type AnyToolDefinitionRun = (input: any, ctx?: any) => Promise<any>;
|
|
229
|
-
type AnyToolDefinition = Omit<ToolDefinitionBase<z.
|
|
230
|
-
inputDependencies: AnyInputDependencies$1 | undefined;
|
|
222
|
+
type AnyToolDefinition = Omit<ToolDefinitionBase<z.ZodObject<z.ZodRawShape>, z.ZodObject<z.ZodRawShape>, string>, "run"> & {
|
|
231
223
|
run: AnyToolDefinitionRun;
|
|
232
224
|
readonly connection?: string | undefined;
|
|
233
225
|
readonly connections?: Record<string, string> | undefined;
|
|
@@ -330,10 +322,9 @@ declare function toChatCompletionTool(definition: AnyToolDefinition): ChatComple
|
|
|
330
322
|
interface McpRegisterToolConfig {
|
|
331
323
|
title?: string;
|
|
332
324
|
description?: string;
|
|
333
|
-
inputSchema?: z.
|
|
334
|
-
outputSchema?: z.
|
|
325
|
+
inputSchema?: z.ZodObject<z.ZodRawShape>;
|
|
326
|
+
outputSchema?: z.ZodObject<z.ZodRawShape>;
|
|
335
327
|
annotations?: ToolAnnotations;
|
|
336
|
-
_meta?: Record<string, unknown>;
|
|
337
328
|
}
|
|
338
329
|
/**
|
|
339
330
|
* Build the `McpServer.registerTool` config for a `ToolDefinition`.
|
|
@@ -389,7 +380,7 @@ declare function toResponsesTool(definition: AnyToolDefinition): ResponsesFuncti
|
|
|
389
380
|
* consume the wrapped scripts unchanged.
|
|
390
381
|
*/
|
|
391
382
|
|
|
392
|
-
type AnyDef = ToolDefinition<any, any,
|
|
383
|
+
type AnyDef = ToolDefinition<any, any, string, string, string>;
|
|
393
384
|
/**
|
|
394
385
|
* Map a script's `ToolDefinition` to its consumer-facing wrapped form,
|
|
395
386
|
* narrowed against the connector's `connectionResolvers` map. The wrapped
|
|
@@ -397,11 +388,11 @@ type AnyDef = ToolDefinition<any, any, any, string, string, string>;
|
|
|
397
388
|
* `RunOptions.connections.<slot>` is narrowed per the slot's resolver
|
|
398
389
|
* array via `ConnectionValueFor`.
|
|
399
390
|
*/
|
|
400
|
-
type WrappedScript<D extends AnyDef, TResolvers extends ConnectionResolversMap> = D extends ToolDefinitionNone<infer TIn, infer TOut, infer
|
|
391
|
+
type WrappedScript<D extends AnyDef, TResolvers extends ConnectionResolversMap> = D extends ToolDefinitionNone<infer TIn, infer TOut, infer _TName> ? Omit<D, "run"> & {
|
|
401
392
|
run: (input: z.infer<TIn>, opts?: RunOptionsNone) => Promise<z.infer<TOut>>;
|
|
402
|
-
} : D extends ToolDefinitionSingle<infer TIn, infer TOut, infer
|
|
393
|
+
} : D extends ToolDefinitionSingle<infer TIn, infer TOut, infer _TName, infer TKey> ? Omit<D, "run"> & {
|
|
403
394
|
run: (input: z.infer<TIn>, opts: RunOptionsSingle<ConnectionValueForKey<TResolvers, TKey>>) => Promise<z.infer<TOut>>;
|
|
404
|
-
} : D extends ToolDefinitionMulti<infer TIn, infer TOut, infer
|
|
395
|
+
} : D extends ToolDefinitionMulti<infer TIn, infer TOut, infer _TName, infer TSlots, infer TKey> ? Omit<D, "run"> & {
|
|
405
396
|
run: (input: z.infer<TIn>, opts: {
|
|
406
397
|
connection?: never;
|
|
407
398
|
connections: {
|
|
@@ -458,10 +449,9 @@ declare function defineConnector<TScripts extends Record<string, AnyDef>, const
|
|
|
458
449
|
* to `run`. The returned definition mirrors the input one-to-one.
|
|
459
450
|
*/
|
|
460
451
|
|
|
461
|
-
|
|
462
|
-
declare function defineTool<TIn extends z.
|
|
463
|
-
declare function defineTool<TIn extends z.
|
|
464
|
-
declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string, const TSlots extends string = string, const TKey extends string = string>(config: DefineToolConfigMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>): ToolDefinitionMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>;
|
|
452
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string>(config: DefineToolConfigNone<TIn, TOut, TName>): ToolDefinitionNone<TIn, TOut, TName>;
|
|
453
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string, const TKey extends string = string>(config: DefineToolConfigSingle<TIn, TOut, TName, TKey>): ToolDefinitionSingle<TIn, TOut, TName, TKey>;
|
|
454
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string, const TSlots extends string = string, const TKey extends string = string>(config: DefineToolConfigMulti<TIn, TOut, TName, TSlots, TKey>): ToolDefinitionMulti<TIn, TOut, TName, TSlots, TKey>;
|
|
465
455
|
|
|
466
456
|
/**
|
|
467
457
|
* `handleIfScriptMain(meta, definition, opts?)` — per-script CLI execution
|
|
@@ -515,6 +505,13 @@ declare function handleIfScriptMain<D extends AnyToolDefinition>(meta: ImportMet
|
|
|
515
505
|
* - `<bin> mcp` — boot a local MCP stdio
|
|
516
506
|
* server exposing every
|
|
517
507
|
* script.
|
|
508
|
+
* - `<bin> skill` — print the connector's
|
|
509
|
+
* `SKILL.md` to stdout.
|
|
510
|
+
* - `<bin> reference [<name>]` — print
|
|
511
|
+
* `references/<name>.md` to
|
|
512
|
+
* stdout, or list all
|
|
513
|
+
* available references when
|
|
514
|
+
* called with no name.
|
|
518
515
|
* - `<bin>`, `<bin> --help`, `<bin> -h` — usage to stdout.
|
|
519
516
|
* - `<bin> run <script> --help` — per-script help (input
|
|
520
517
|
* schema + required env
|
package/dist/index.d.ts
CHANGED
|
@@ -30,24 +30,6 @@ type Replace<S extends string, From extends string, To extends string> = S exten
|
|
|
30
30
|
*/
|
|
31
31
|
type EnvFromKey<K extends string> = Uppercase<Replace<K, "-", "_">>;
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* A Zapier policy statement. Carried on the `ToolDefinition` for in-process
|
|
35
|
-
* governance consumers (policy engines that wrap `script.run` before HTTP).
|
|
36
|
-
* Not propagated to MCP `_meta` — only `inputDependencies` is published over
|
|
37
|
-
* the wire (`_meta["zapier:inputDependencies"]`) by `toMcpTool` /
|
|
38
|
-
* `toMcpServerTool`.
|
|
39
|
-
*/
|
|
40
|
-
interface Statement {
|
|
41
|
-
effect: "allow" | "ask" | "deny";
|
|
42
|
-
permissions: ReadonlyArray<string>;
|
|
43
|
-
resources: ReadonlyArray<string>;
|
|
44
|
-
conditions?: ReadonlyArray<{
|
|
45
|
-
path: ReadonlyArray<string>;
|
|
46
|
-
operator: string;
|
|
47
|
-
value: unknown;
|
|
48
|
-
}>;
|
|
49
|
-
label?: string;
|
|
50
|
-
}
|
|
51
33
|
/**
|
|
52
34
|
* Single-credential resolver: the resolver's `name` IS the credential
|
|
53
35
|
* descriptor. `resolve` receives the credential as a plain `string` —
|
|
@@ -68,6 +50,12 @@ interface Statement {
|
|
|
68
50
|
interface SingleConnectionResolver<TName extends string = string> {
|
|
69
51
|
readonly name: TName;
|
|
70
52
|
readonly keySuffixes?: undefined;
|
|
53
|
+
/**
|
|
54
|
+
* npm package names that must be installed for this resolver to function
|
|
55
|
+
* at runtime. Declared here so `--help` can check availability and tell
|
|
56
|
+
* the agent which packages to install before using this resolver.
|
|
57
|
+
*/
|
|
58
|
+
readonly optionalPackages?: readonly string[];
|
|
71
59
|
resolve: (credential: string) => typeof globalThis.fetch | Promise<typeof globalThis.fetch>;
|
|
72
60
|
}
|
|
73
61
|
/**
|
|
@@ -86,6 +74,12 @@ interface SingleConnectionResolver<TName extends string = string> {
|
|
|
86
74
|
interface MultiConnectionResolver<TName extends string = string, TSuffixes extends readonly string[] = readonly string[]> {
|
|
87
75
|
readonly name: TName;
|
|
88
76
|
readonly keySuffixes: TSuffixes;
|
|
77
|
+
/**
|
|
78
|
+
* npm package names that must be installed for this resolver to function
|
|
79
|
+
* at runtime. Declared here so `--help` can check availability and tell
|
|
80
|
+
* the agent which packages to install before using this resolver.
|
|
81
|
+
*/
|
|
82
|
+
readonly optionalPackages?: readonly string[];
|
|
89
83
|
resolve: (credentials: Record<TSuffixes[number], string>) => typeof globalThis.fetch | Promise<typeof globalThis.fetch>;
|
|
90
84
|
}
|
|
91
85
|
/** Either resolver shape. */
|
|
@@ -160,43 +154,45 @@ interface RunOptionsMulti<TSlots extends string = string, TPerSlot extends Recor
|
|
|
160
154
|
connections: TPerSlot;
|
|
161
155
|
}
|
|
162
156
|
type RunOptions<TSlots extends string = string, TValue = ConnectionValue, TPerSlot extends Record<TSlots, ConnectionValue> = Record<TSlots, ConnectionValue>> = RunOptionsNone | RunOptionsSingle<TValue> | RunOptionsMulti<TSlots, TPerSlot>;
|
|
157
|
+
/** Author-facing context for a credential-free script. */
|
|
158
|
+
interface ContextNone {
|
|
159
|
+
fetch?: undefined;
|
|
160
|
+
connections?: undefined;
|
|
161
|
+
}
|
|
163
162
|
/** Author-facing context for a single-connection script. */
|
|
164
163
|
interface ContextSingle {
|
|
165
164
|
fetch: typeof globalThis.fetch;
|
|
165
|
+
connections?: never;
|
|
166
166
|
}
|
|
167
167
|
/** Author-facing context for a multi-connection script. */
|
|
168
168
|
interface ContextMulti<TSlots extends string = string> {
|
|
169
|
+
fetch?: never;
|
|
169
170
|
connections: Record<TSlots, typeof globalThis.fetch>;
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
/** When authoring omits `inputDependencies`, the definition value is `undefined`. */
|
|
173
|
-
type InputDependenciesValue<T> = [T] extends [undefined] ? undefined : T;
|
|
174
|
-
interface DefineToolConfigBase<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> {
|
|
172
|
+
interface DefineToolConfigBase<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> {
|
|
175
173
|
name: TName;
|
|
176
174
|
title: string;
|
|
177
175
|
description: string;
|
|
178
176
|
inputSchema: TIn;
|
|
179
177
|
outputSchema: TOut;
|
|
180
178
|
annotations: _modelcontextprotocol_sdk_types_js.Tool["annotations"];
|
|
181
|
-
statements?: ReadonlyArray<Statement>;
|
|
182
|
-
inputDependencies?: TInputDependencies;
|
|
183
179
|
}
|
|
184
|
-
interface DefineToolConfigNone<TIn extends z.
|
|
180
|
+
interface DefineToolConfigNone<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
185
181
|
connection?: never;
|
|
186
182
|
connections?: never;
|
|
187
|
-
run: (input: z.infer<TIn
|
|
183
|
+
run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<unknown>;
|
|
188
184
|
}
|
|
189
|
-
interface DefineToolConfigSingle<TIn extends z.
|
|
185
|
+
interface DefineToolConfigSingle<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
190
186
|
connection: TKey;
|
|
191
187
|
connections?: never;
|
|
192
|
-
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<
|
|
188
|
+
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<unknown>;
|
|
193
189
|
}
|
|
194
|
-
interface DefineToolConfigMulti<TIn extends z.
|
|
190
|
+
interface DefineToolConfigMulti<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string, TSlots extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TName> {
|
|
195
191
|
connection?: never;
|
|
196
192
|
connections: Record<TSlots, TKey>;
|
|
197
|
-
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<
|
|
193
|
+
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<unknown>;
|
|
198
194
|
}
|
|
199
|
-
interface ToolDefinitionBase<TIn extends z.
|
|
195
|
+
interface ToolDefinitionBase<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, TName extends string> {
|
|
200
196
|
readonly kind: "tool";
|
|
201
197
|
readonly name: TName;
|
|
202
198
|
readonly title: string;
|
|
@@ -204,30 +200,26 @@ interface ToolDefinitionBase<TIn extends z.ZodType, TOut extends z.ZodType, TInp
|
|
|
204
200
|
inputSchema: TIn;
|
|
205
201
|
outputSchema: TOut;
|
|
206
202
|
readonly annotations: _modelcontextprotocol_sdk_types_js.Tool["annotations"];
|
|
207
|
-
readonly statements: ReadonlyArray<Statement> | undefined;
|
|
208
|
-
inputDependencies: InputDependenciesValue<TInputDependencies>;
|
|
209
203
|
}
|
|
210
|
-
interface ToolDefinitionNone<TIn extends z.
|
|
204
|
+
interface ToolDefinitionNone<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
211
205
|
readonly connection?: undefined;
|
|
212
206
|
readonly connections?: undefined;
|
|
213
|
-
|
|
214
|
-
run: (input: z.infer<TIn>) => Promise<z.infer<TOut>>;
|
|
207
|
+
run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<z.infer<TOut>>;
|
|
215
208
|
}
|
|
216
|
-
interface ToolDefinitionSingle<TIn extends z.
|
|
209
|
+
interface ToolDefinitionSingle<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
217
210
|
readonly connection: TKey;
|
|
218
211
|
readonly connections?: undefined;
|
|
219
212
|
run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<z.infer<TOut>>;
|
|
220
213
|
}
|
|
221
|
-
interface ToolDefinitionMulti<TIn extends z.
|
|
214
|
+
interface ToolDefinitionMulti<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TSlots extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TName> {
|
|
222
215
|
readonly connection?: undefined;
|
|
223
216
|
readonly connections: Record<TSlots, TKey>;
|
|
224
217
|
run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<z.infer<TOut>>;
|
|
225
218
|
}
|
|
226
|
-
type ToolDefinition<TIn extends z.
|
|
219
|
+
type ToolDefinition<TIn extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TName extends string = string, TSlots extends string = string, TKey extends string = string> = ToolDefinitionNone<TIn, TOut, TName> | ToolDefinitionSingle<TIn, TOut, TName, TKey> | ToolDefinitionMulti<TIn, TOut, TName, TSlots, TKey>;
|
|
227
220
|
/** Wide author-side `run` signature for polymorphic walks. */
|
|
228
221
|
type AnyToolDefinitionRun = (input: any, ctx?: any) => Promise<any>;
|
|
229
|
-
type AnyToolDefinition = Omit<ToolDefinitionBase<z.
|
|
230
|
-
inputDependencies: AnyInputDependencies$1 | undefined;
|
|
222
|
+
type AnyToolDefinition = Omit<ToolDefinitionBase<z.ZodObject<z.ZodRawShape>, z.ZodObject<z.ZodRawShape>, string>, "run"> & {
|
|
231
223
|
run: AnyToolDefinitionRun;
|
|
232
224
|
readonly connection?: string | undefined;
|
|
233
225
|
readonly connections?: Record<string, string> | undefined;
|
|
@@ -330,10 +322,9 @@ declare function toChatCompletionTool(definition: AnyToolDefinition): ChatComple
|
|
|
330
322
|
interface McpRegisterToolConfig {
|
|
331
323
|
title?: string;
|
|
332
324
|
description?: string;
|
|
333
|
-
inputSchema?: z.
|
|
334
|
-
outputSchema?: z.
|
|
325
|
+
inputSchema?: z.ZodObject<z.ZodRawShape>;
|
|
326
|
+
outputSchema?: z.ZodObject<z.ZodRawShape>;
|
|
335
327
|
annotations?: ToolAnnotations;
|
|
336
|
-
_meta?: Record<string, unknown>;
|
|
337
328
|
}
|
|
338
329
|
/**
|
|
339
330
|
* Build the `McpServer.registerTool` config for a `ToolDefinition`.
|
|
@@ -389,7 +380,7 @@ declare function toResponsesTool(definition: AnyToolDefinition): ResponsesFuncti
|
|
|
389
380
|
* consume the wrapped scripts unchanged.
|
|
390
381
|
*/
|
|
391
382
|
|
|
392
|
-
type AnyDef = ToolDefinition<any, any,
|
|
383
|
+
type AnyDef = ToolDefinition<any, any, string, string, string>;
|
|
393
384
|
/**
|
|
394
385
|
* Map a script's `ToolDefinition` to its consumer-facing wrapped form,
|
|
395
386
|
* narrowed against the connector's `connectionResolvers` map. The wrapped
|
|
@@ -397,11 +388,11 @@ type AnyDef = ToolDefinition<any, any, any, string, string, string>;
|
|
|
397
388
|
* `RunOptions.connections.<slot>` is narrowed per the slot's resolver
|
|
398
389
|
* array via `ConnectionValueFor`.
|
|
399
390
|
*/
|
|
400
|
-
type WrappedScript<D extends AnyDef, TResolvers extends ConnectionResolversMap> = D extends ToolDefinitionNone<infer TIn, infer TOut, infer
|
|
391
|
+
type WrappedScript<D extends AnyDef, TResolvers extends ConnectionResolversMap> = D extends ToolDefinitionNone<infer TIn, infer TOut, infer _TName> ? Omit<D, "run"> & {
|
|
401
392
|
run: (input: z.infer<TIn>, opts?: RunOptionsNone) => Promise<z.infer<TOut>>;
|
|
402
|
-
} : D extends ToolDefinitionSingle<infer TIn, infer TOut, infer
|
|
393
|
+
} : D extends ToolDefinitionSingle<infer TIn, infer TOut, infer _TName, infer TKey> ? Omit<D, "run"> & {
|
|
403
394
|
run: (input: z.infer<TIn>, opts: RunOptionsSingle<ConnectionValueForKey<TResolvers, TKey>>) => Promise<z.infer<TOut>>;
|
|
404
|
-
} : D extends ToolDefinitionMulti<infer TIn, infer TOut, infer
|
|
395
|
+
} : D extends ToolDefinitionMulti<infer TIn, infer TOut, infer _TName, infer TSlots, infer TKey> ? Omit<D, "run"> & {
|
|
405
396
|
run: (input: z.infer<TIn>, opts: {
|
|
406
397
|
connection?: never;
|
|
407
398
|
connections: {
|
|
@@ -458,10 +449,9 @@ declare function defineConnector<TScripts extends Record<string, AnyDef>, const
|
|
|
458
449
|
* to `run`. The returned definition mirrors the input one-to-one.
|
|
459
450
|
*/
|
|
460
451
|
|
|
461
|
-
|
|
462
|
-
declare function defineTool<TIn extends z.
|
|
463
|
-
declare function defineTool<TIn extends z.
|
|
464
|
-
declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string, const TSlots extends string = string, const TKey extends string = string>(config: DefineToolConfigMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>): ToolDefinitionMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>;
|
|
452
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string>(config: DefineToolConfigNone<TIn, TOut, TName>): ToolDefinitionNone<TIn, TOut, TName>;
|
|
453
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string, const TKey extends string = string>(config: DefineToolConfigSingle<TIn, TOut, TName, TKey>): ToolDefinitionSingle<TIn, TOut, TName, TKey>;
|
|
454
|
+
declare function defineTool<TIn extends z.ZodObject<z.ZodRawShape>, TOut extends z.ZodObject<z.ZodRawShape>, const TName extends string = string, const TSlots extends string = string, const TKey extends string = string>(config: DefineToolConfigMulti<TIn, TOut, TName, TSlots, TKey>): ToolDefinitionMulti<TIn, TOut, TName, TSlots, TKey>;
|
|
465
455
|
|
|
466
456
|
/**
|
|
467
457
|
* `handleIfScriptMain(meta, definition, opts?)` — per-script CLI execution
|
|
@@ -515,6 +505,13 @@ declare function handleIfScriptMain<D extends AnyToolDefinition>(meta: ImportMet
|
|
|
515
505
|
* - `<bin> mcp` — boot a local MCP stdio
|
|
516
506
|
* server exposing every
|
|
517
507
|
* script.
|
|
508
|
+
* - `<bin> skill` — print the connector's
|
|
509
|
+
* `SKILL.md` to stdout.
|
|
510
|
+
* - `<bin> reference [<name>]` — print
|
|
511
|
+
* `references/<name>.md` to
|
|
512
|
+
* stdout, or list all
|
|
513
|
+
* available references when
|
|
514
|
+
* called with no name.
|
|
518
515
|
* - `<bin>`, `<bin> --help`, `<bin> -h` — usage to stdout.
|
|
519
516
|
* - `<bin> run <script> --help` — per-script help (input
|
|
520
517
|
* schema + required env
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ function defineConnectionResolver(resolver) {
|
|
|
4
4
|
}
|
|
5
5
|
var zapierConnectionResolver = defineConnectionResolver({
|
|
6
6
|
name: "zapier-connection-id",
|
|
7
|
+
optionalPackages: ["@zapier/zapier-sdk"],
|
|
7
8
|
resolve: async (connectionId) => {
|
|
8
9
|
const { buildZapierFetch } = await import("./build-zapier-fetch-DWCYBAF4.js");
|
|
9
10
|
return buildZapierFetch(connectionId);
|
|
@@ -23,6 +24,9 @@ function defineBearerTokenResolver(opts = {}) {
|
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
// src/normalize-connections.ts
|
|
28
|
+
import { createRequire } from "module";
|
|
29
|
+
|
|
26
30
|
// src/connection-key.ts
|
|
27
31
|
function envFromKey(name) {
|
|
28
32
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -162,23 +166,70 @@ function buildRunOptionsFromEnv(definition, env, connectionResolvers) {
|
|
|
162
166
|
}
|
|
163
167
|
return { connections: wrapped };
|
|
164
168
|
}
|
|
165
|
-
function
|
|
169
|
+
function isPackageInstalled(name) {
|
|
170
|
+
try {
|
|
171
|
+
createRequire(import.meta.url).resolve(name);
|
|
172
|
+
return true;
|
|
173
|
+
} catch {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function formatHelpForConnections(definition, connectionResolvers, env) {
|
|
166
178
|
const slots = [...walkConnections(definition)];
|
|
167
179
|
if (slots.length === 0) return [];
|
|
168
180
|
const lines = [];
|
|
169
181
|
lines.push(
|
|
170
|
-
"
|
|
182
|
+
"Auth (set as environment variables; do NOT pass via CLI argument):"
|
|
171
183
|
);
|
|
184
|
+
const notReadySlots = [];
|
|
172
185
|
for (const { slotName, connectionKey } of slots) {
|
|
173
186
|
const resolvers = resolversForKey(connectionResolvers, connectionKey);
|
|
174
|
-
|
|
175
|
-
|
|
187
|
+
if (slotName !== void 0) {
|
|
188
|
+
lines.push(` ${slotName} (${connectionKey}):`);
|
|
189
|
+
}
|
|
190
|
+
const resolverIndent = slotName !== void 0 ? " " : " ";
|
|
191
|
+
const varIndent = slotName !== void 0 ? " " : " ";
|
|
192
|
+
let slotHasReady = false;
|
|
176
193
|
for (const resolver of resolvers) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
194
|
+
const vars = envVarsFor(slotName, connectionKey, resolver);
|
|
195
|
+
let isReady = false;
|
|
196
|
+
let missingPkgs = [];
|
|
197
|
+
if (env !== void 0) {
|
|
198
|
+
const envVarsOk = vars.every(
|
|
199
|
+
(k) => typeof env[k] === "string" && env[k] !== ""
|
|
200
|
+
);
|
|
201
|
+
if (envVarsOk) isReady = true;
|
|
202
|
+
missingPkgs = (resolver.optionalPackages ?? []).filter(
|
|
203
|
+
(pkg) => !isPackageInstalled(pkg)
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const markReady = isReady && !slotHasReady;
|
|
207
|
+
if (markReady) slotHasReady = true;
|
|
208
|
+
const resolverSuffix = env !== void 0 && markReady ? " [READY \u2014 use this]" : "";
|
|
209
|
+
lines.push(`${resolverIndent}${resolver.name}:${resolverSuffix}`);
|
|
210
|
+
for (const envVar of vars) {
|
|
211
|
+
const varSuffix = env !== void 0 ? env[envVar] !== void 0 && env[envVar] !== "" ? " [set]" : " [not set]" : "";
|
|
212
|
+
lines.push(`${varIndent}${envVar}${varSuffix}`);
|
|
213
|
+
}
|
|
214
|
+
if (env !== void 0) {
|
|
215
|
+
for (const pkg of resolver.optionalPackages ?? []) {
|
|
216
|
+
if (missingPkgs.includes(pkg)) {
|
|
217
|
+
lines.push(
|
|
218
|
+
`${varIndent}${pkg} [not installed \u2014 run \`npm install ${pkg}\` first]`
|
|
219
|
+
);
|
|
220
|
+
} else {
|
|
221
|
+
lines.push(`${varIndent}${pkg} [installed]`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
180
224
|
}
|
|
181
225
|
}
|
|
226
|
+
if (env !== void 0 && !slotHasReady) {
|
|
227
|
+
notReadySlots.push(slotName ?? connectionKey);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (env !== void 0 && notReadySlots.length > 0) {
|
|
231
|
+
const label = notReadySlots.length === slots.length ? "No option is ready" : `No option is ready for slot${notReadySlots.length > 1 ? "s" : ""} ${notReadySlots.join(", ")}`;
|
|
232
|
+
lines.push(`${label} \u2014 set one of the env vars above.`);
|
|
182
233
|
}
|
|
183
234
|
return lines;
|
|
184
235
|
}
|
|
@@ -263,8 +314,8 @@ function ensureConnectionValue(scriptName, slotName, connectionKey, value) {
|
|
|
263
314
|
return value;
|
|
264
315
|
}
|
|
265
316
|
async function buildContext(definition, opts, connectionResolvers) {
|
|
266
|
-
const hasConnection = "connection" in opts && opts.connection !== void 0;
|
|
267
|
-
const hasConnections = "connections" in opts && opts.connections !== void 0;
|
|
317
|
+
const hasConnection = opts !== void 0 && "connection" in opts && opts.connection !== void 0;
|
|
318
|
+
const hasConnections = opts !== void 0 && "connections" in opts && opts.connections !== void 0;
|
|
268
319
|
if (definition.connection === void 0 && definition.connections === void 0) {
|
|
269
320
|
if (hasConnection || hasConnections) {
|
|
270
321
|
throw new Error(
|
|
@@ -273,6 +324,11 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
273
324
|
}
|
|
274
325
|
return {};
|
|
275
326
|
}
|
|
327
|
+
if (opts === void 0) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`ToolDefinition "${definition.name}": \`RunOptions\` is required \u2014 pass \`{ connection: ... }\` or \`{ connections: ... }\`.`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
276
332
|
if (hasConnection && hasConnections) {
|
|
277
333
|
throw new Error(
|
|
278
334
|
`ToolDefinition "${definition.name}": \`RunOptions\` sets both \`connection\` and \`connections\`. Use one or the other.`
|
|
@@ -290,7 +346,7 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
290
346
|
definition.name,
|
|
291
347
|
void 0,
|
|
292
348
|
connectionKey,
|
|
293
|
-
opts.connection
|
|
349
|
+
"connection" in opts ? opts.connection : void 0
|
|
294
350
|
);
|
|
295
351
|
const fetch = await resolveSlotFetch(
|
|
296
352
|
definition.name,
|
|
@@ -307,12 +363,12 @@ async function buildContext(definition, opts, connectionResolvers) {
|
|
|
307
363
|
`ToolDefinition "${definition.name}" is multi-connection (slots: ${declaredSlots.join(", ")}) \u2014 call with \`{ connections: { ... } }\`, not \`{ connection: ... }\`.`
|
|
308
364
|
);
|
|
309
365
|
}
|
|
310
|
-
|
|
366
|
+
const provided = opts.connections;
|
|
367
|
+
if (provided === void 0) {
|
|
311
368
|
throw new Error(
|
|
312
369
|
`ToolDefinition "${definition.name}" is multi-connection \u2014 \`RunOptions.connections\` is required.`
|
|
313
370
|
);
|
|
314
371
|
}
|
|
315
|
-
const provided = opts.connections;
|
|
316
372
|
const unknown = Object.keys(provided).filter(
|
|
317
373
|
(s) => !declaredSlots.includes(s)
|
|
318
374
|
);
|
|
@@ -366,28 +422,18 @@ function toChatCompletionTool(definition) {
|
|
|
366
422
|
|
|
367
423
|
// src/surfaces/to-mcp-server-tool.ts
|
|
368
424
|
function toMcpServerTool(definition) {
|
|
369
|
-
|
|
425
|
+
return {
|
|
370
426
|
title: definition.title,
|
|
371
427
|
description: definition.description,
|
|
372
428
|
inputSchema: definition.inputSchema,
|
|
373
429
|
outputSchema: definition.outputSchema,
|
|
374
430
|
annotations: definition.annotations
|
|
375
431
|
};
|
|
376
|
-
if (definition.inputDependencies) {
|
|
377
|
-
config._meta = {
|
|
378
|
-
"zapier:inputDependencies": definition.inputDependencies
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
return config;
|
|
382
432
|
}
|
|
383
433
|
|
|
384
434
|
// src/surfaces/to-mcp-tool.ts
|
|
385
435
|
import { z as z2 } from "zod";
|
|
386
436
|
function toMcpTool(definition) {
|
|
387
|
-
const meta = {};
|
|
388
|
-
if (definition.inputDependencies) {
|
|
389
|
-
meta["zapier:inputDependencies"] = definition.inputDependencies;
|
|
390
|
-
}
|
|
391
437
|
return {
|
|
392
438
|
name: definition.name,
|
|
393
439
|
title: definition.title,
|
|
@@ -396,8 +442,7 @@ function toMcpTool(definition) {
|
|
|
396
442
|
outputSchema: z2.toJSONSchema(
|
|
397
443
|
definition.outputSchema
|
|
398
444
|
),
|
|
399
|
-
annotations: definition.annotations
|
|
400
|
-
...Object.keys(meta).length > 0 ? { _meta: meta } : {}
|
|
445
|
+
annotations: definition.annotations
|
|
401
446
|
};
|
|
402
447
|
}
|
|
403
448
|
|
|
@@ -411,24 +456,9 @@ function toResponsesTool(definition) {
|
|
|
411
456
|
|
|
412
457
|
// src/define-connector.ts
|
|
413
458
|
function wrapScriptWithResolvers(definition, connectionResolvers) {
|
|
414
|
-
const authorRun = definition.run;
|
|
415
459
|
const wrappedRun = async (input, opts) => {
|
|
416
|
-
const validated = definition.inputSchema.parse(input);
|
|
417
|
-
if (definition.connection === void 0 && definition.connections === void 0) {
|
|
418
|
-
if (opts !== void 0 && (opts.connection !== void 0 || opts.connections !== void 0)) {
|
|
419
|
-
throw new Error(
|
|
420
|
-
`ToolDefinition "${definition.name}" is credential-free \u2014 \`RunOptions\` must not include \`connection\` or \`connections\`.`
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
return authorRun(validated);
|
|
424
|
-
}
|
|
425
|
-
if (opts === void 0) {
|
|
426
|
-
throw new Error(
|
|
427
|
-
`ToolDefinition "${definition.name}": \`RunOptions\` is required \u2014 pass \`{ connection: ... }\` or \`{ connections: ... }\`.`
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
460
|
const ctx = await buildContext(definition, opts, connectionResolvers);
|
|
431
|
-
return
|
|
461
|
+
return definition.run(input, ctx);
|
|
432
462
|
};
|
|
433
463
|
return { ...definition, run: wrappedRun };
|
|
434
464
|
}
|
|
@@ -438,6 +468,11 @@ function defineConnector(config) {
|
|
|
438
468
|
validateConnectionResolvers(scriptsAsAny, connectionResolvers);
|
|
439
469
|
const wrapped = {};
|
|
440
470
|
for (const [key, definition] of Object.entries(scriptsAsAny)) {
|
|
471
|
+
if (key !== definition.name) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
`defineConnector: script key "${key}" must match its tool name \u2014 got name "${definition.name}". Rename the key to "${definition.name}" or update the tool's name field.`
|
|
474
|
+
);
|
|
475
|
+
}
|
|
441
476
|
wrapped[key] = wrapScriptWithResolvers(definition, connectionResolvers);
|
|
442
477
|
}
|
|
443
478
|
return {
|
|
@@ -507,6 +542,12 @@ function defineTool(config) {
|
|
|
507
542
|
validateConnectionKey(config.name, value);
|
|
508
543
|
}
|
|
509
544
|
}
|
|
545
|
+
const authorRun = config.run;
|
|
546
|
+
const wrappedRun = async (input, ctx) => {
|
|
547
|
+
const validated = config.inputSchema.parse(input);
|
|
548
|
+
const result = await authorRun(validated, ctx);
|
|
549
|
+
return config.outputSchema.parse(result);
|
|
550
|
+
};
|
|
510
551
|
const base = {
|
|
511
552
|
kind: "tool",
|
|
512
553
|
name: config.name,
|
|
@@ -515,9 +556,7 @@ function defineTool(config) {
|
|
|
515
556
|
inputSchema: config.inputSchema,
|
|
516
557
|
outputSchema: config.outputSchema,
|
|
517
558
|
annotations: config.annotations,
|
|
518
|
-
|
|
519
|
-
inputDependencies: config.inputDependencies,
|
|
520
|
-
run: config.run
|
|
559
|
+
run: wrappedRun
|
|
521
560
|
};
|
|
522
561
|
if (hasSingular) base.connection = config.connection;
|
|
523
562
|
if (hasPlural) base.connections = config.connections;
|
|
@@ -661,10 +700,73 @@ async function runDispatchCliBody(connector, opts) {
|
|
|
661
700
|
});
|
|
662
701
|
return;
|
|
663
702
|
}
|
|
703
|
+
if (first === "skill") {
|
|
704
|
+
if (!opts.meta) {
|
|
705
|
+
throw new Error(
|
|
706
|
+
"runDispatchCliBody: `skill` requires `meta` in options (the connector's `import.meta` from `cli.ts`)."
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
const cliPath = fileURLToPath2(opts.meta.url);
|
|
710
|
+
const connectorDir = path2.dirname(cliPath);
|
|
711
|
+
const skillPath = path2.join(connectorDir, "SKILL.md");
|
|
712
|
+
let content;
|
|
713
|
+
try {
|
|
714
|
+
content = await fs2.readFile(skillPath, "utf8");
|
|
715
|
+
} catch {
|
|
716
|
+
throw new Error(
|
|
717
|
+
`SKILL.md not found at ${skillPath}. Ensure the connector ships a SKILL.md.`
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
opts.stdout.write(resolveRelativeLinks(content, connectorDir));
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (first === "reference") {
|
|
724
|
+
if (!opts.meta) {
|
|
725
|
+
throw new Error(
|
|
726
|
+
"runDispatchCliBody: `reference` requires `meta` in options (the connector's `import.meta` from `cli.ts`)."
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
const cliPath = fileURLToPath2(opts.meta.url);
|
|
730
|
+
const connectorDir = path2.dirname(cliPath);
|
|
731
|
+
const refsDir = path2.join(connectorDir, "references");
|
|
732
|
+
const name = args[1];
|
|
733
|
+
if (!name) {
|
|
734
|
+
let entries;
|
|
735
|
+
try {
|
|
736
|
+
const files = await fs2.readdir(refsDir);
|
|
737
|
+
entries = files.filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -".md".length));
|
|
738
|
+
} catch {
|
|
739
|
+
entries = [];
|
|
740
|
+
}
|
|
741
|
+
if (entries.length === 0) {
|
|
742
|
+
opts.stdout.write(`Available references: <none>
|
|
743
|
+
`);
|
|
744
|
+
} else {
|
|
745
|
+
opts.stdout.write(`Available references:
|
|
746
|
+
`);
|
|
747
|
+
for (const entry of entries) {
|
|
748
|
+
opts.stdout.write(` ${entry}
|
|
749
|
+
`);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
const refPath = path2.join(refsDir, `${name}.md`);
|
|
755
|
+
let content;
|
|
756
|
+
try {
|
|
757
|
+
content = await fs2.readFile(refPath, "utf8");
|
|
758
|
+
} catch {
|
|
759
|
+
throw new Error(
|
|
760
|
+
`Reference file not found at ${refPath}. Ensure the connector ships \`references/${name}.md\`.`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
opts.stdout.write(resolveRelativeLinks(content, refsDir));
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
664
766
|
if (first !== "run") {
|
|
665
767
|
printUsage(scripts, errOut, packageName);
|
|
666
768
|
throw new Error(
|
|
667
|
-
`Unknown command "${first}". Use \`run <script>\` to dispatch a script (available: ${Object.keys(scripts).join(", ") || "<none>"}),
|
|
769
|
+
`Unknown command "${first}". Use \`run <script>\` to dispatch a script (available: ${Object.keys(scripts).join(", ") || "<none>"}), \`mcp\` to boot a local MCP server, \`skill\` to print SKILL.md, or \`reference [<name>]\` to print or list reference docs.`
|
|
668
770
|
);
|
|
669
771
|
}
|
|
670
772
|
const scriptName = args[1];
|
|
@@ -691,6 +793,17 @@ async function runDispatchCliBody(connector, opts) {
|
|
|
691
793
|
invocation
|
|
692
794
|
});
|
|
693
795
|
}
|
|
796
|
+
function resolveRelativeLinks(content, baseDir) {
|
|
797
|
+
return content.replace(
|
|
798
|
+
/(!?\[([^\]]*)\])\(([^)]+)\)/g,
|
|
799
|
+
(match, prefix, _alt, url) => {
|
|
800
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file:") || url.startsWith("#") || url.startsWith("/")) {
|
|
801
|
+
return match;
|
|
802
|
+
}
|
|
803
|
+
return `${prefix}(${path2.resolve(baseDir, url)})`;
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
}
|
|
694
807
|
async function resolvePackageName(meta) {
|
|
695
808
|
if (!meta?.url) return void 0;
|
|
696
809
|
try {
|
|
@@ -709,6 +822,8 @@ function printUsage(scripts, out, packageName) {
|
|
|
709
822
|
`Usage: <bin> run <script> [<json-input>]
|
|
710
823
|
<bin> run <script> --help (per-script input + required env vars)
|
|
711
824
|
<bin> mcp (run as a local MCP server over stdio)
|
|
825
|
+
<bin> skill (print SKILL.md to stdout)
|
|
826
|
+
<bin> reference [<name>] (print references/<name>.md, or list all)
|
|
712
827
|
|
|
713
828
|
`
|
|
714
829
|
);
|
|
@@ -821,12 +936,13 @@ async function handleIfScriptMainBody(wrappedScript, connectionResolvers, io) {
|
|
|
821
936
|
if (helpRequested) {
|
|
822
937
|
io.stdout.write(
|
|
823
938
|
buildHelpText(wrappedScript, connectionResolvers, {
|
|
824
|
-
invocation: io.invocation
|
|
939
|
+
invocation: io.invocation,
|
|
940
|
+
env: io.env
|
|
825
941
|
})
|
|
826
942
|
);
|
|
827
943
|
return;
|
|
828
944
|
}
|
|
829
|
-
const raw = positional ?? await
|
|
945
|
+
const raw = positional ?? await readStdinInput(io.stdin, wrappedScript.name);
|
|
830
946
|
if (raw.trim().length === 0) {
|
|
831
947
|
throw new Error(
|
|
832
948
|
`Missing JSON input for "${wrappedScript.name}". Pass it as a positional argument or via stdin.`
|
|
@@ -838,6 +954,14 @@ async function handleIfScriptMainBody(wrappedScript, connectionResolvers, io) {
|
|
|
838
954
|
const result = await wrappedScript.run(input, runOpts);
|
|
839
955
|
io.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
840
956
|
}
|
|
957
|
+
async function readStdinInput(stdin, scriptName) {
|
|
958
|
+
if (stdin.isTTY) {
|
|
959
|
+
throw new Error(
|
|
960
|
+
`Missing JSON input for "${scriptName}". Pass it as a positional argument or pipe it via stdin.`
|
|
961
|
+
);
|
|
962
|
+
}
|
|
963
|
+
return new Response(stdin).text();
|
|
964
|
+
}
|
|
841
965
|
function buildHelpText(definition, connectionResolvers, opts = {}) {
|
|
842
966
|
const lines = [];
|
|
843
967
|
const description = definition.description.split("\n")[0]?.trim() ?? "";
|
|
@@ -861,7 +985,8 @@ function buildHelpText(definition, connectionResolvers, opts = {}) {
|
|
|
861
985
|
}
|
|
862
986
|
const connectionsBlock = formatHelpForConnections(
|
|
863
987
|
definition,
|
|
864
|
-
connectionResolvers
|
|
988
|
+
connectionResolvers,
|
|
989
|
+
opts.env
|
|
865
990
|
);
|
|
866
991
|
if (connectionsBlock.length > 0) {
|
|
867
992
|
lines.push(...connectionsBlock);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/connectors-sdk",
|
|
3
|
-
"version": "0.1.0-experimental.
|
|
3
|
+
"version": "0.1.0-experimental.10",
|
|
4
4
|
"description": "SDK for building Zapier connectors. Provides the authoring primitives and execution surfaces for connector scripts.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
"README.md",
|
|
25
25
|
"LICENSE"
|
|
26
26
|
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsup"
|
|
29
|
-
},
|
|
30
27
|
"peerDependencies": {
|
|
31
28
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
32
29
|
"@zapier/zapier-sdk": "^0.59.0",
|
|
@@ -44,5 +41,8 @@
|
|
|
44
41
|
"type": "git",
|
|
45
42
|
"url": "https://gitlab.com/zapier/team-agents-platform/connectors.git",
|
|
46
43
|
"directory": "packages/connectors-sdk"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|