@hasna/connectors 0.3.0 → 0.3.2

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/bin/mcp.js CHANGED
@@ -4569,7 +4569,6 @@ var require_limitLength = __commonJS((exports) => {
4569
4569
  var require_pattern = __commonJS((exports) => {
4570
4570
  Object.defineProperty(exports, "__esModule", { value: true });
4571
4571
  var code_1 = require_code2();
4572
- var util_1 = require_util();
4573
4572
  var codegen_1 = require_codegen();
4574
4573
  var error2 = {
4575
4574
  message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`,
@@ -4582,18 +4581,10 @@ var require_pattern = __commonJS((exports) => {
4582
4581
  $data: true,
4583
4582
  error: error2,
4584
4583
  code(cxt) {
4585
- const { gen, data, $data, schema, schemaCode, it } = cxt;
4584
+ const { data, $data, schema, schemaCode, it } = cxt;
4586
4585
  const u = it.opts.unicodeRegExp ? "u" : "";
4587
- if ($data) {
4588
- const { regExp } = it.opts.code;
4589
- const regExpCode = regExp.code === "new RegExp" ? (0, codegen_1._)`new RegExp` : (0, util_1.useFunc)(gen, regExp);
4590
- const valid = gen.let("valid");
4591
- gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u}).test(${data})`), () => gen.assign(valid, false));
4592
- cxt.fail$data((0, codegen_1._)`!${valid}`);
4593
- } else {
4594
- const regExp = (0, code_1.usePattern)(cxt, schema);
4595
- cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
4596
- }
4586
+ const regExp = $data ? (0, codegen_1._)`(new RegExp(${schemaCode}, ${u}))` : (0, code_1.usePattern)(cxt, schema);
4587
+ cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
4597
4588
  }
4598
4589
  };
4599
4590
  exports.default = def;
@@ -6286,7 +6277,7 @@ var require_formats = __commonJS((exports) => {
6286
6277
  }
6287
6278
  var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
6288
6279
  function getTime(strictTimeZone) {
6289
- return function time(str) {
6280
+ return function time3(str) {
6290
6281
  const matches = TIME.exec(str);
6291
6282
  if (!matches)
6292
6283
  return false;
@@ -18120,62 +18111,6 @@ class ExperimentalServerTasks {
18120
18111
  requestStream(request, resultSchema, options) {
18121
18112
  return this._server.requestStream(request, resultSchema, options);
18122
18113
  }
18123
- createMessageStream(params, options) {
18124
- const clientCapabilities = this._server.getClientCapabilities();
18125
- if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
18126
- throw new Error("Client does not support sampling tools capability.");
18127
- }
18128
- if (params.messages.length > 0) {
18129
- const lastMessage = params.messages[params.messages.length - 1];
18130
- const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
18131
- const hasToolResults = lastContent.some((c) => c.type === "tool_result");
18132
- const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
18133
- const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
18134
- const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
18135
- if (hasToolResults) {
18136
- if (lastContent.some((c) => c.type !== "tool_result")) {
18137
- throw new Error("The last message must contain only tool_result content if any is present");
18138
- }
18139
- if (!hasPreviousToolUse) {
18140
- throw new Error("tool_result blocks are not matching any tool_use from the previous message");
18141
- }
18142
- }
18143
- if (hasPreviousToolUse) {
18144
- const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
18145
- const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
18146
- if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
18147
- throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
18148
- }
18149
- }
18150
- }
18151
- return this.requestStream({
18152
- method: "sampling/createMessage",
18153
- params
18154
- }, CreateMessageResultSchema, options);
18155
- }
18156
- elicitInputStream(params, options) {
18157
- const clientCapabilities = this._server.getClientCapabilities();
18158
- const mode = params.mode ?? "form";
18159
- switch (mode) {
18160
- case "url": {
18161
- if (!clientCapabilities?.elicitation?.url) {
18162
- throw new Error("Client does not support url elicitation.");
18163
- }
18164
- break;
18165
- }
18166
- case "form": {
18167
- if (!clientCapabilities?.elicitation?.form) {
18168
- throw new Error("Client does not support form elicitation.");
18169
- }
18170
- break;
18171
- }
18172
- }
18173
- const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
18174
- return this.requestStream({
18175
- method: "elicitation/create",
18176
- params: normalizedParams
18177
- }, ElicitResultSchema, options);
18178
- }
18179
18114
  async getTask(taskId, options) {
18180
18115
  return this._server.getTask({ taskId }, options);
18181
18116
  }
@@ -20271,11 +20206,110 @@ function guessKeyField(name) {
20271
20206
  return "apiKey";
20272
20207
  }
20273
20208
 
20209
+ // src/lib/runner.ts
20210
+ import { existsSync as existsSync4 } from "fs";
20211
+ import { join as join4, dirname as dirname3 } from "path";
20212
+ import { fileURLToPath as fileURLToPath3 } from "url";
20213
+ import { spawn } from "child_process";
20214
+ var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
20215
+ function resolveConnectorsDir2() {
20216
+ const fromBin = join4(__dirname3, "..", "connectors");
20217
+ if (existsSync4(fromBin))
20218
+ return fromBin;
20219
+ const fromSrc = join4(__dirname3, "..", "..", "connectors");
20220
+ if (existsSync4(fromSrc))
20221
+ return fromSrc;
20222
+ return fromBin;
20223
+ }
20224
+ var CONNECTORS_DIR2 = resolveConnectorsDir2();
20225
+ function getConnectorCliPath(name) {
20226
+ const safeName = name.replace(/[^a-z0-9-]/g, "");
20227
+ const connectorDir = join4(CONNECTORS_DIR2, `connect-${safeName}`);
20228
+ const cliPath = join4(connectorDir, "src", "cli", "index.ts");
20229
+ if (existsSync4(cliPath))
20230
+ return cliPath;
20231
+ return null;
20232
+ }
20233
+ function runConnectorCommand(name, args, timeoutMs = 30000) {
20234
+ const cliPath = getConnectorCliPath(name);
20235
+ if (!cliPath) {
20236
+ return Promise.resolve({
20237
+ stdout: "",
20238
+ stderr: `Connector '${name}' not found or has no CLI.`,
20239
+ exitCode: 1,
20240
+ success: false
20241
+ });
20242
+ }
20243
+ return new Promise((resolve) => {
20244
+ const proc = spawn("bun", ["run", cliPath, ...args], {
20245
+ timeout: timeoutMs,
20246
+ env: { ...process.env },
20247
+ stdio: ["pipe", "pipe", "pipe"]
20248
+ });
20249
+ let stdout = "";
20250
+ let stderr = "";
20251
+ proc.stdout.on("data", (data) => {
20252
+ stdout += data.toString();
20253
+ });
20254
+ proc.stderr.on("data", (data) => {
20255
+ stderr += data.toString();
20256
+ });
20257
+ proc.on("close", (code) => {
20258
+ resolve({
20259
+ stdout: stdout.trim(),
20260
+ stderr: stderr.trim(),
20261
+ exitCode: code ?? 1,
20262
+ success: code === 0
20263
+ });
20264
+ });
20265
+ proc.on("error", (err) => {
20266
+ resolve({
20267
+ stdout: "",
20268
+ stderr: err.message,
20269
+ exitCode: 1,
20270
+ success: false
20271
+ });
20272
+ });
20273
+ });
20274
+ }
20275
+ async function getConnectorOperations(name) {
20276
+ const cliPath = getConnectorCliPath(name);
20277
+ if (!cliPath) {
20278
+ return { commands: [], helpText: "", hasCli: false };
20279
+ }
20280
+ const result = await runConnectorCommand(name, ["--help"]);
20281
+ const helpText = result.stdout || result.stderr;
20282
+ const commands = [];
20283
+ const lines = helpText.split(`
20284
+ `);
20285
+ let inCommands = false;
20286
+ for (const line of lines) {
20287
+ if (line.trim().startsWith("Commands:")) {
20288
+ inCommands = true;
20289
+ continue;
20290
+ }
20291
+ if (inCommands) {
20292
+ const match = line.match(/^\s{2,}(\S+)/);
20293
+ if (match && match[1] !== "help") {
20294
+ commands.push(match[1]);
20295
+ }
20296
+ if (line.trim() === "" && commands.length > 0) {
20297
+ inCommands = false;
20298
+ }
20299
+ }
20300
+ }
20301
+ return { commands, helpText, hasCli: true };
20302
+ }
20303
+ async function getConnectorCommandHelp(name, command) {
20304
+ const result = await runConnectorCommand(name, [command, "--help"]);
20305
+ return result.stdout || result.stderr;
20306
+ }
20307
+
20274
20308
  // src/mcp/index.ts
20275
20309
  loadConnectorVersions();
20276
20310
  var server = new McpServer({
20277
20311
  name: "connectors",
20278
- version: "0.3.0"
20312
+ version: "0.3.2"
20279
20313
  });
20280
20314
  server.registerTool("search_connectors", {
20281
20315
  title: "Search Connectors",
@@ -20523,6 +20557,111 @@ server.registerTool("list_categories", {
20523
20557
  ]
20524
20558
  };
20525
20559
  });
20560
+ server.registerTool("list_connector_operations", {
20561
+ title: "List Connector Operations",
20562
+ description: "Discover available API operations for a connector. Returns CLI commands the connector supports (e.g. messages, products, customers). Use this before run_connector_operation to know what's available.",
20563
+ inputSchema: {
20564
+ name: exports_external.string().describe("Connector name (e.g. stripe, gmail, anthropic)"),
20565
+ command: exports_external.string().optional().describe("Get detailed help for a specific subcommand (e.g. products, messages)")
20566
+ }
20567
+ }, async ({ name, command }) => {
20568
+ const meta = getConnector(name);
20569
+ if (!meta) {
20570
+ return {
20571
+ content: [{ type: "text", text: `Connector '${name}' not found.` }],
20572
+ isError: true
20573
+ };
20574
+ }
20575
+ if (!getConnectorCliPath(name)) {
20576
+ return {
20577
+ content: [
20578
+ {
20579
+ type: "text",
20580
+ text: `Connector '${name}' does not have a CLI. It may be API-only.`
20581
+ }
20582
+ ],
20583
+ isError: true
20584
+ };
20585
+ }
20586
+ if (command) {
20587
+ const help = await getConnectorCommandHelp(name, command);
20588
+ return {
20589
+ content: [
20590
+ {
20591
+ type: "text",
20592
+ text: JSON.stringify({ connector: name, command, help }, null, 2)
20593
+ }
20594
+ ]
20595
+ };
20596
+ }
20597
+ const ops = await getConnectorOperations(name);
20598
+ return {
20599
+ content: [
20600
+ {
20601
+ type: "text",
20602
+ text: JSON.stringify({
20603
+ connector: name,
20604
+ displayName: meta.displayName,
20605
+ commands: ops.commands,
20606
+ helpText: ops.helpText
20607
+ }, null, 2)
20608
+ }
20609
+ ]
20610
+ };
20611
+ });
20612
+ server.registerTool("run_connector_operation", {
20613
+ title: "Run Connector Operation",
20614
+ description: "Execute an API operation on a connector. Pass the connector name and CLI arguments. Use list_connector_operations first to discover available commands. Example: name='stripe', args=['products', 'list', '--limit', '5']",
20615
+ inputSchema: {
20616
+ name: exports_external.string().describe("Connector name (e.g. stripe, gmail, anthropic)"),
20617
+ args: exports_external.array(exports_external.string()).describe("CLI arguments for the connector command (e.g. ['products', 'list', '--limit', '5'])"),
20618
+ format: exports_external.enum(["json", "pretty"]).optional().describe("Output format (default: json for structured parsing)"),
20619
+ timeout: exports_external.number().optional().describe("Timeout in milliseconds (default: 30000)")
20620
+ }
20621
+ }, async ({ name, args, format, timeout }) => {
20622
+ const meta = getConnector(name);
20623
+ if (!meta) {
20624
+ return {
20625
+ content: [{ type: "text", text: `Connector '${name}' not found.` }],
20626
+ isError: true
20627
+ };
20628
+ }
20629
+ const finalArgs = [...args];
20630
+ if (format) {
20631
+ finalArgs.push("--format", format);
20632
+ } else if (!args.includes("--format") && !args.includes("-f")) {
20633
+ finalArgs.push("--format", "json");
20634
+ }
20635
+ const result = await runConnectorCommand(name, finalArgs, timeout ?? 30000);
20636
+ if (!result.success) {
20637
+ return {
20638
+ content: [
20639
+ {
20640
+ type: "text",
20641
+ text: JSON.stringify({
20642
+ connector: name,
20643
+ success: false,
20644
+ error: result.stderr || result.stdout,
20645
+ exitCode: result.exitCode
20646
+ }, null, 2)
20647
+ }
20648
+ ],
20649
+ isError: true
20650
+ };
20651
+ }
20652
+ return {
20653
+ content: [
20654
+ {
20655
+ type: "text",
20656
+ text: JSON.stringify({
20657
+ connector: name,
20658
+ success: true,
20659
+ output: result.stdout
20660
+ }, null, 2)
20661
+ }
20662
+ ]
20663
+ };
20664
+ });
20526
20665
  server.registerTool("search_tools", {
20527
20666
  title: "Search Tools",
20528
20667
  description: "List tool names, optionally filtered by keyword.",
@@ -20539,6 +20678,8 @@ server.registerTool("search_tools", {
20539
20678
  "connector_auth_status",
20540
20679
  "configure_auth",
20541
20680
  "list_categories",
20681
+ "list_connector_operations",
20682
+ "run_connector_operation",
20542
20683
  "search_tools",
20543
20684
  "describe_tools"
20544
20685
  ];
@@ -20560,7 +20701,9 @@ server.registerTool("describe_tools", {
20560
20701
  connector_info: "Get metadata and install status. Params: name",
20561
20702
  connector_auth_status: "Check auth status and env vars. Params: name",
20562
20703
  configure_auth: "Save API key or token. Params: name, key, field?",
20563
- list_categories: "List connector categories with counts."
20704
+ list_categories: "List connector categories with counts.",
20705
+ list_connector_operations: "Discover available API operations for a connector. Params: name, command?",
20706
+ run_connector_operation: "Execute an API operation on a connector. Params: name, args[], format?, timeout?"
20564
20707
  };
20565
20708
  const result = names.map((n) => `${n}: ${descriptions[n] || "See tool schema"}`).join(`
20566
20709
  `);
package/bin/serve.js CHANGED
@@ -1,21 +1,5 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
- var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __toESM = (mod, isNodeMode, target) => {
9
- target = mod != null ? __create(__getProtoOf(mod)) : {};
10
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
- for (let key of __getOwnPropNames(mod))
12
- if (!__hasOwnProp.call(to, key))
13
- __defProp(to, key, {
14
- get: () => mod[key],
15
- enumerable: true
16
- });
17
- return to;
18
- };
19
3
  var __require = import.meta.require;
20
4
 
21
5
  // src/server/serve.ts
@@ -1136,7 +1120,24 @@ Dashboard not found at: ${dashboardDir}`);
1136
1120
  const path = url2.pathname;
1137
1121
  const method = req.method;
1138
1122
  if (path === "/api/connectors" && method === "GET") {
1139
- return json(getAllConnectorsWithAuth(), 200, port);
1123
+ const compact = url2.searchParams.get("compact") === "true";
1124
+ const fieldsParam = url2.searchParams.get("fields");
1125
+ const fields = fieldsParam ? new Set(fieldsParam.split(",").map((f) => f.trim())) : null;
1126
+ const data = getAllConnectorsWithAuth();
1127
+ if (compact) {
1128
+ return json(data.map((c) => ({ name: c.name, category: c.category, installed: c.installed })), 200, port);
1129
+ }
1130
+ if (fields) {
1131
+ return json(data.map((c) => {
1132
+ const out = {};
1133
+ for (const f of fields) {
1134
+ if (f in c)
1135
+ out[f] = c[f];
1136
+ }
1137
+ return out;
1138
+ }), 200, port);
1139
+ }
1140
+ return json(data, 200, port);
1140
1141
  }
1141
1142
  const singleMatch = path.match(/^\/api\/connectors\/([^/]+)$/);
1142
1143
  if (singleMatch && method === "GET") {
@@ -25,6 +25,8 @@
25
25
  "s3",
26
26
  "lambda",
27
27
  "dynamodb",
28
+ "ses",
29
+ "email",
28
30
  "connector",
29
31
  "cli",
30
32
  "typescript",
@@ -39,7 +41,8 @@
39
41
  },
40
42
  "dependencies": {
41
43
  "commander": "^12.1.0",
42
- "chalk": "^5.3.0"
44
+ "chalk": "^5.3.0",
45
+ "@aws-sdk/client-sesv2": "^3.0.0"
43
46
  },
44
47
  "engines": {
45
48
  "bun": ">=1.0.0"