mcp-scraper 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -88,7 +88,7 @@ Build the branded one-click bundle:
88
88
  npm run build:mcpb
89
89
  ```
90
90
 
91
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.11.0`, SHA-256 `ed9f00c3f5ea47cc79b5e6e0205c2f85fecb9aa0eed5dcd55fee9e4e309ecfac`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
91
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.12.0`, SHA-256 `2a0dfdc53e93d48588ef672c6daf0ec0e6194b3f938add02b106bf5e86c20ef3`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
92
92
 
93
93
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
94
94
 
@@ -27452,7 +27452,7 @@ var PACKAGE_VERSION;
27452
27452
  var init_version = __esm({
27453
27453
  "src/version.ts"() {
27454
27454
  "use strict";
27455
- PACKAGE_VERSION = "0.11.0";
27455
+ PACKAGE_VERSION = "0.12.0";
27456
27456
  }
27457
27457
  });
27458
27458
 
@@ -32869,11 +32869,12 @@ var init_memory_tool_schemas = __esm({
32869
32869
  CreateScheduledActionSchema = {
32870
32870
  id: "create-scheduled-action",
32871
32871
  upstreamName: "createScheduledActionTool",
32872
- description: "Create a scheduled action: on the given cadence, an agent reads the description, does what it asks, and writes the result into the target vault. Cadence 'once' runs a single time then completes permanently \u2014 use it for one-off tasks, not recurring ones. Requires an active scheduling subscription and write access to the target vault.",
32872
+ description: "Create a scheduled action in agent mode (default) or connection_sync mode. Agent mode asks an agent to follow the description and write a result into the target vault. connection_sync deterministically runs the approved read-only tools on bound service connections and ingests their data; it requires at least one connection to be bound before execution. Cadence 'once' runs a single time then completes permanently. Requires an active scheduling subscription and write access to the target vault.",
32873
32873
  input: {
32874
32874
  description: import_zod35.z.string().min(1).describe("Free-text description of what this action should do each time it runs."),
32875
32875
  vault: import_zod35.z.string().min(1).describe("The vault this action writes its results into. You must already have write access to it."),
32876
32876
  cadence: import_zod35.z.enum(["once", "daily", "weekly", "monthly"]).describe('How often this action runs. "once" fires a single time and then completes.'),
32877
+ executionMode: import_zod35.z.enum(["agent", "connection_sync"]).default("agent").describe(`How to execute each run. "agent" (default) lets an agent follow the description. "connection_sync" deterministically ingests data from the schedule's bound connections using only their approved read-only tools; bind at least one connection before it runs.`),
32877
32878
  timeOfDay: import_zod35.z.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/).optional().describe("24-hour HH:MM clock time to run at, in the given timezone. Optional \u2014 omit to run at any time during the period (matches prior default behavior)."),
32878
32879
  timezone: import_zod35.z.string().optional().describe('IANA timezone name, e.g. "America/Denver". Only meaningful together with timeOfDay. Defaults to UTC.'),
32879
32880
  deployDate: import_zod35.z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe('Calendar date (YYYY-MM-DD, in the given timezone) this action should first become eligible to run \u2014 its deployment/start date. For recurring cadences, the first occurrence lands on or after this date; every later occurrence still follows the normal cadence. For cadence "once", this (combined with timeOfDay if given) is exactly what day it fires. Omit to start immediately.')
@@ -32882,6 +32883,7 @@ var init_memory_tool_schemas = __esm({
32882
32883
  ok: import_zod35.z.boolean().describe("True when the scheduled action was created."),
32883
32884
  id: import_zod35.z.string().optional().describe("The new scheduled action id."),
32884
32885
  nextRunAt: import_zod35.z.string().optional().describe("When it will first run."),
32886
+ executionMode: import_zod35.z.enum(["agent", "connection_sync"]).optional().describe("The stored execution mode. Defaults to agent when omitted from the request."),
32885
32887
  error: import_zod35.z.string().optional().describe("Human-readable failure reason when ok is false."),
32886
32888
  code: import_zod35.z.string().optional().describe("Machine-readable denial code: not_enabled when no scheduling subscription is active.")
32887
32889
  },
@@ -32956,7 +32958,7 @@ var init_memory_tool_schemas = __esm({
32956
32958
  ListScheduledActionsSchema = {
32957
32959
  id: "list-scheduled-actions",
32958
32960
  upstreamName: "listScheduledActionsTool",
32959
- description: "List every scheduled action you own \u2014 active, paused, and completed one-time actions \u2014 with cadence, next run time, and last run status.",
32961
+ description: "List every scheduled action you own \u2014 active, paused, and completed one-time actions \u2014 with execution mode, cadence, next run time, and last run status. connection_sync means deterministic read-only ingestion from bound service connections.",
32960
32962
  input: {},
32961
32963
  output: {
32962
32964
  ok: import_zod35.z.boolean(),
@@ -32965,6 +32967,7 @@ var init_memory_tool_schemas = __esm({
32965
32967
  description: import_zod35.z.string(),
32966
32968
  vault: import_zod35.z.string(),
32967
32969
  cadence: import_zod35.z.enum(["once", "daily", "weekly", "monthly"]),
32970
+ executionMode: import_zod35.z.enum(["agent", "connection_sync"]),
32968
32971
  timeOfDay: import_zod35.z.string().nullable(),
32969
32972
  timezone: import_zod35.z.string(),
32970
32973
  status: import_zod35.z.enum(["active", "paused", "completed"]),
@@ -38884,6 +38887,43 @@ var init_memory_db = __esm({
38884
38887
  });
38885
38888
 
38886
38889
  // src/api/nango-control.ts
38890
+ function connectionSyncPolicyIssues(selections) {
38891
+ const issues = [];
38892
+ for (const selection of selections) {
38893
+ const required = CONNECTION_SYNC_REQUIRED_TOOLS[selection.providerConfigKey];
38894
+ if (!required) {
38895
+ issues.push({ providerConfigKey: selection.providerConfigKey, code: "unsupported_provider" });
38896
+ continue;
38897
+ }
38898
+ const allowed = new Set(selection.allowedTools);
38899
+ const missingTools = required.filter((tool) => !allowed.has(tool));
38900
+ if (missingTools.length > 0) {
38901
+ issues.push({ providerConfigKey: selection.providerConfigKey, code: "missing_required_tools", missingTools });
38902
+ }
38903
+ const requiredSet = new Set(required);
38904
+ const unexpectedTools = [...allowed].filter((tool) => !requiredSet.has(tool));
38905
+ if (unexpectedTools.length > 0) {
38906
+ issues.push({ providerConfigKey: selection.providerConfigKey, code: "unexpected_tools", unexpectedTools });
38907
+ }
38908
+ }
38909
+ return issues;
38910
+ }
38911
+ function connectionSyncSelectionError(connections) {
38912
+ if (connections.length === 0) {
38913
+ return "Data sync requires at least one bound service connection with approved read-only tools.";
38914
+ }
38915
+ const issues = connectionSyncPolicyIssues(connections);
38916
+ const unsupported = [...new Set(issues.filter((issue) => issue.code === "unsupported_provider").map((issue) => issue.providerConfigKey))];
38917
+ if (unsupported.length > 0) {
38918
+ return `Data sync currently supports only ${Object.keys(CONNECTION_SYNC_REQUIRED_TOOLS).join(", ")}. Unsupported providerConfigKey: ${unsupported.join(", ")}.`;
38919
+ }
38920
+ const missing = issues.filter((issue) => issue.code === "missing_required_tools").map((issue) => `${issue.providerConfigKey}: ${(issue.missingTools ?? []).join(", ")}`);
38921
+ if (missing.length > 0) {
38922
+ return `Data sync is missing required approved read tools (${missing.join("; ")}).`;
38923
+ }
38924
+ const unexpected = issues.filter((issue) => issue.code === "unexpected_tools").map((issue) => `${issue.providerConfigKey}: ${(issue.unexpectedTools ?? []).join(", ")}`);
38925
+ return unexpected.length > 0 ? `Data sync permits only its exact read-only tool set; remove unexpected tools (${unexpected.join("; ")}).` : null;
38926
+ }
38887
38927
  function controlBaseUrl() {
38888
38928
  return (process.env.NANGO_CONTROL_URL?.trim() || DEFAULT_NANGO_CONTROL_URL).replace(/\/$/, "");
38889
38929
  }
@@ -39013,6 +39053,7 @@ async function getNangoCatalog() {
39013
39053
  ], 100);
39014
39054
  const appReviewStatus = row.appReviewLimited === true || row.app_review_limited === true ? "limited" : firstString(row, ["appReviewStatus", "app_review_status", "reviewStatus", "review_status"], 100);
39015
39055
  const appReviewNote = firstString(row, ["appReviewNote", "app_review_note", "reviewNote", "review_note"], 500);
39056
+ const connectionSyncRequiredTools = [...CONNECTION_SYNC_REQUIRED_TOOLS[providerConfigKey] ?? []];
39016
39057
  result.push({
39017
39058
  providerConfigKey,
39018
39059
  provider,
@@ -39023,6 +39064,8 @@ async function getNangoCatalog() {
39023
39064
  authMode,
39024
39065
  categories,
39025
39066
  safeDefaultAllowedTools,
39067
+ connectionSyncSupported: connectionSyncRequiredTools.length > 0,
39068
+ connectionSyncRequiredTools,
39026
39069
  platformSetupStatus,
39027
39070
  appReviewStatus,
39028
39071
  appReviewNote
@@ -39186,7 +39229,7 @@ async function callScheduleConnectionRead(identity, connectionId, tool, args) {
39186
39229
  const data = unwrapData(body);
39187
39230
  return isRecord(data) ? data.result ?? data : data;
39188
39231
  }
39189
- var DEFAULT_NANGO_CONTROL_URL, DISABLED_NANGO_TOOLS, NangoControlError, ScheduleConnectionValidationError;
39232
+ var DEFAULT_NANGO_CONTROL_URL, DISABLED_NANGO_TOOLS, CONNECTION_SYNC_REQUIRED_TOOLS, NangoControlError, ScheduleConnectionValidationError;
39190
39233
  var init_nango_control = __esm({
39191
39234
  "src/api/nango-control.ts"() {
39192
39235
  "use strict";
@@ -39195,6 +39238,17 @@ var init_nango_control = __esm({
39195
39238
  "google-mail": /* @__PURE__ */ new Set(["list-filters"]),
39196
39239
  slack: /* @__PURE__ */ new Set(["search-files", "search-messages"])
39197
39240
  };
39241
+ CONNECTION_SYNC_REQUIRED_TOOLS = {
39242
+ "google-mail": ["list-messages", "get-message"],
39243
+ "google-calendar": ["list-events", "get-event"],
39244
+ zoom: [
39245
+ "list-meetings",
39246
+ "get-meeting",
39247
+ "list-recordings",
39248
+ "get-recording",
39249
+ "get-meeting-transcript"
39250
+ ]
39251
+ };
39198
39252
  NangoControlError = class extends Error {
39199
39253
  status;
39200
39254
  constructor(message, status = 502) {
@@ -40266,9 +40320,10 @@ var init_server = __esm({
40266
40320
  try {
40267
40321
  const actions = await Promise.all(r.actions.map(async (action) => {
40268
40322
  const id = typeof action.id === "string" ? action.id : "";
40269
- if (!id) return { ...action, connections: [] };
40323
+ const executionMode = action.executionMode === "connection_sync" ? "connection_sync" : "agent";
40324
+ if (!id) return { ...action, executionMode, connections: [] };
40270
40325
  const bindings = await getScheduleConnectionBindings(user.email, id);
40271
- return { ...action, connections: bindingsForSchedule(bindings, id) };
40326
+ return { ...action, executionMode, connections: bindingsForSchedule(bindings, id) };
40272
40327
  }));
40273
40328
  return c.json({
40274
40329
  ...r,
@@ -40278,7 +40333,7 @@ var init_server = __esm({
40278
40333
  console.warn("[schedule-actions] connection bindings unavailable:", err instanceof Error ? err.message : String(err));
40279
40334
  return c.json({
40280
40335
  ...r,
40281
- actions: r.actions.map((action) => ({ ...action, connections: [] })),
40336
+ actions: r.actions.map((action) => ({ ...action, executionMode: action.executionMode === "connection_sync" ? "connection_sync" : "agent", connections: [] })),
40282
40337
  connectionBindingsUnavailable: true
40283
40338
  });
40284
40339
  }
@@ -40288,6 +40343,10 @@ var init_server = __esm({
40288
40343
  const { key, error } = await getOrCreateUserMemoryKey(user);
40289
40344
  if (!key) return c.json({ ok: false, error: error ?? "memory unavailable" }, 503);
40290
40345
  const body = await c.req.json().catch(() => ({}));
40346
+ const executionMode = body.executionMode ?? "agent";
40347
+ if (executionMode !== "agent" && executionMode !== "connection_sync") {
40348
+ return c.json({ ok: false, error: 'executionMode must be "agent" or "connection_sync".' }, 400);
40349
+ }
40291
40350
  const hasConnections = Object.prototype.hasOwnProperty.call(body, "connections");
40292
40351
  let connections;
40293
40352
  try {
@@ -40295,18 +40354,23 @@ var init_server = __esm({
40295
40354
  } catch (err) {
40296
40355
  return scheduleConnectionError(c, err, "Invalid service connections.");
40297
40356
  }
40298
- const actionBody = { ...body };
40357
+ if (executionMode === "connection_sync") {
40358
+ const policyError = connectionSyncSelectionError(connections);
40359
+ if (policyError) return c.json({ ok: false, error: policyError }, 400);
40360
+ }
40361
+ const actionBody = { ...body, executionMode };
40299
40362
  delete actionBody.connections;
40300
40363
  const r = await memoryCall("createScheduledActionTool", actionBody, key);
40301
- if (!r.ok || !hasConnections) return c.json(r);
40302
- if (connections.length === 0) return c.json({ ...r, connections: [] });
40364
+ const createResponse = { ...r, executionMode };
40365
+ if (!r.ok || !hasConnections) return c.json(createResponse);
40366
+ if (connections.length === 0) return c.json({ ...createResponse, connections: [] });
40303
40367
  if (!r.id) {
40304
40368
  console.error("[schedule-actions] create returned no id while service connections were requested");
40305
40369
  return c.json({ ok: false, error: "The scheduled action was created without a usable id; service connections were not attached." }, 502);
40306
40370
  }
40307
40371
  try {
40308
40372
  const bound = await putScheduleConnectionBindings(user.email, r.id, connections);
40309
- return c.json({ ...r, connections: bound });
40373
+ return c.json({ ...createResponse, connections: bound });
40310
40374
  } catch (err) {
40311
40375
  const rollback = await memoryCall("deleteScheduledActionTool", { id: r.id }, key).catch(() => ({ ok: false }));
40312
40376
  if (!rollback.ok) console.error("[schedule-actions] failed to compensate action after connection binding failure", r.id);
@@ -40344,6 +40408,16 @@ var init_server = __esm({
40344
40408
  }
40345
40409
  try {
40346
40410
  const scheduleActionId = c.req.param("id");
40411
+ const { key, error } = await getOrCreateUserMemoryKey(user);
40412
+ if (!key) return c.json({ ok: false, error: error ?? "memory unavailable" }, 503);
40413
+ const schedules = await memoryCall("listScheduledActionsTool", {}, key);
40414
+ if (!schedules.ok || !Array.isArray(schedules.actions)) return c.json(schedules, 502);
40415
+ const schedule = schedules.actions.find((action) => action.id === scheduleActionId);
40416
+ if (!schedule) return c.json({ ok: false, error: "scheduled action not found" }, 404);
40417
+ if (schedule.executionMode === "connection_sync") {
40418
+ const policyError = connectionSyncSelectionError(connections);
40419
+ if (policyError) return c.json({ ok: false, error: policyError }, 400);
40420
+ }
40347
40421
  const bindings = await putScheduleConnectionBindings(user.email, scheduleActionId, connections);
40348
40422
  return c.json({ ok: true, connections: bindings });
40349
40423
  } catch (err) {