@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.
@@ -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 formatHelpForConnections(definition, connectionResolvers) {
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
- "Connections (set as environment variables; do NOT pass via CLI argument):"
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
- const heading = slotName ? ` ${slotName} (${connectionKey}):` : ` ${connectionKey}:`;
280
- lines.push(heading);
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
- lines.push(` ${resolver.name}:`);
283
- for (const envVar of envVarsFor(slotName, connectionKey, resolver)) {
284
- lines.push(` ${envVar}`);
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
- if (!hasConnections) {
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
- const config = {
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 authorRun(validated, ctx);
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
- statements: config.statements,
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>"}), or \`mcp\` to boot a local MCP server.`
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 new Response(io.stdin).text();
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
- type AnyInputDependencies$1 = Readonly<Record<string, unknown>>;
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.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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>) => Promise<z.infer<TOut>>;
183
+ run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<unknown>;
188
184
  }
189
- interface DefineToolConfigSingle<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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<z.infer<TOut>>;
188
+ run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<unknown>;
193
189
  }
194
- interface DefineToolConfigMulti<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string, TSlots extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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<z.infer<TOut>>;
193
+ run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<unknown>;
198
194
  }
199
- interface ToolDefinitionBase<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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
- /** Author's run; the wrapper passes `input` directly. */
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TSlots extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TSlots extends string = string, TKey extends string = string> = ToolDefinitionNone<TIn, TOut, TInputDependencies, TName> | ToolDefinitionSingle<TIn, TOut, TInputDependencies, TName, TKey> | ToolDefinitionMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>;
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.ZodType, z.ZodType, any, string>, "run" | "inputDependencies"> & {
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.ZodType;
334
- outputSchema?: z.ZodType;
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, any, string, string, string>;
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 _TInputDependencies, infer _TName> ? Omit<D, "run"> & {
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 _TInputDependencies, infer _TName, infer TKey> ? Omit<D, "run"> & {
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 _TInputDependencies, infer _TName, infer TSlots, infer TKey> ? Omit<D, "run"> & {
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
- type AnyInputDependencies = Readonly<Record<string, unknown>>;
462
- declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string>(config: DefineToolConfigNone<TIn, TOut, TInputDependencies, TName>): ToolDefinitionNone<TIn, TOut, TInputDependencies, TName>;
463
- declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string, const TKey extends string = string>(config: DefineToolConfigSingle<TIn, TOut, TInputDependencies, TName, TKey>): ToolDefinitionSingle<TIn, TOut, TInputDependencies, TName, TKey>;
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
- type AnyInputDependencies$1 = Readonly<Record<string, unknown>>;
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.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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>) => Promise<z.infer<TOut>>;
183
+ run: (input: z.infer<TIn>, ctx?: ContextNone) => Promise<unknown>;
188
184
  }
189
- interface DefineToolConfigSingle<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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<z.infer<TOut>>;
188
+ run: (input: z.infer<TIn>, ctx: ContextSingle) => Promise<unknown>;
193
189
  }
194
- interface DefineToolConfigMulti<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string, TSlots extends string, TKey extends string> extends DefineToolConfigBase<TIn, TOut, TInputDependencies, TName> {
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<z.infer<TOut>>;
193
+ run: (input: z.infer<TIn>, ctx: ContextMulti<TSlots>) => Promise<unknown>;
198
194
  }
199
- interface ToolDefinitionBase<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined, TName extends string> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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
- /** Author's run; the wrapper passes `input` directly. */
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TSlots extends string = string, TKey extends string = string> extends ToolDefinitionBase<TIn, TOut, TInputDependencies, TName> {
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.ZodType = z.ZodType, TOut extends z.ZodType = z.ZodType, TInputDependencies extends AnyInputDependencies$1 | undefined = undefined, TName extends string = string, TSlots extends string = string, TKey extends string = string> = ToolDefinitionNone<TIn, TOut, TInputDependencies, TName> | ToolDefinitionSingle<TIn, TOut, TInputDependencies, TName, TKey> | ToolDefinitionMulti<TIn, TOut, TInputDependencies, TName, TSlots, TKey>;
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.ZodType, z.ZodType, any, string>, "run" | "inputDependencies"> & {
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.ZodType;
334
- outputSchema?: z.ZodType;
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, any, string, string, string>;
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 _TInputDependencies, infer _TName> ? Omit<D, "run"> & {
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 _TInputDependencies, infer _TName, infer TKey> ? Omit<D, "run"> & {
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 _TInputDependencies, infer _TName, infer TSlots, infer TKey> ? Omit<D, "run"> & {
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
- type AnyInputDependencies = Readonly<Record<string, unknown>>;
462
- declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string>(config: DefineToolConfigNone<TIn, TOut, TInputDependencies, TName>): ToolDefinitionNone<TIn, TOut, TInputDependencies, TName>;
463
- declare function defineTool<TIn extends z.ZodType, TOut extends z.ZodType, TInputDependencies extends AnyInputDependencies | undefined = undefined, const TName extends string = string, const TKey extends string = string>(config: DefineToolConfigSingle<TIn, TOut, TInputDependencies, TName, TKey>): ToolDefinitionSingle<TIn, TOut, TInputDependencies, TName, TKey>;
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 formatHelpForConnections(definition, connectionResolvers) {
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
- "Connections (set as environment variables; do NOT pass via CLI argument):"
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
- const heading = slotName ? ` ${slotName} (${connectionKey}):` : ` ${connectionKey}:`;
175
- lines.push(heading);
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
- lines.push(` ${resolver.name}:`);
178
- for (const envVar of envVarsFor(slotName, connectionKey, resolver)) {
179
- lines.push(` ${envVar}`);
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
- if (!hasConnections) {
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
- const config = {
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 authorRun(validated, ctx);
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
- statements: config.statements,
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>"}), or \`mcp\` to boot a local MCP server.`
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 new Response(io.stdin).text();
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.1",
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
+ }