@kadoa/mcp 0.7.0-rc.2 → 0.7.1

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.
Files changed (2) hide show
  1. package/dist/index.js +218 -102
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ var package_default;
17
17
  var init_package = __esm(() => {
18
18
  package_default = {
19
19
  name: "@kadoa/mcp",
20
- version: "0.7.0-rc.2",
20
+ version: "0.7.1",
21
21
  description: "Kadoa MCP Server — manage workflows from Claude Desktop, Cursor, and other MCP clients",
22
22
  type: "module",
23
23
  main: "dist/index.js",
@@ -44,7 +44,7 @@ var init_package = __esm(() => {
44
44
  prepublishOnly: "bun run check-types && bun run test:unit && bun run build"
45
45
  },
46
46
  dependencies: {
47
- "@kadoa/node-sdk": "^0.45.0",
47
+ "@kadoa/node-sdk": "^0.48.0",
48
48
  "@modelcontextprotocol/client": "2.1.0",
49
49
  "@modelcontextprotocol/express": "2.0.1",
50
50
  "@modelcontextprotocol/node": "2.1.0",
@@ -104,6 +104,11 @@ function createKadoaClient(auth) {
104
104
  var MCP_SCRAPE_REQUEST_TIMEOUT_MS = 310000;
105
105
  var init_client = () => {};
106
106
 
107
+ // src/default-product.ts
108
+ function parseDefaultProductType(value) {
109
+ return value === "realtime" || value === "workflow" ? value : undefined;
110
+ }
111
+
107
112
  // src/error-summary.ts
108
113
  function redactCredentialText(value) {
109
114
  return value.replace(/Bearer\s+[^\s,;]+/gi, "Bearer [redacted]").replace(/\b(?:kcs_|tk-)[A-Za-z0-9._~-]+\b/g, "[redacted]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[redacted]");
@@ -209,7 +214,7 @@ function withVariableDashboardUrl(variable) {
209
214
 
210
215
  // src/tools/shared/output-schemas.ts
211
216
  import { z } from "zod";
212
- var apiField, nullableString, PaginationOutput, WorkflowRowOutput, ListWorkflowsOutput, GetWorkflowOutput, FetchDataOutput, ASSISTANT_ACTIVITIES, WorkflowAssistantOutput, AssistantTimelineOutput, AssistantAnswerOutput, AssistantControlOutput, WorkflowStrategyOutput;
217
+ var apiField, nullableString, PaginationOutput, workflowStatusFields, WorkflowRowOutput, ListWorkflowsOutput, GetWorkflowOutput, FetchDataOutput, ASSISTANT_ACTIVITIES, WorkflowAssistantOutput, AssistantTimelineOutput, AssistantAnswerOutput, AssistantControlOutput, WorkflowStrategyOutput;
213
218
  var init_output_schemas = __esm(() => {
214
219
  apiField = z.unknown().optional();
215
220
  nullableString = z.string().nullable();
@@ -224,11 +229,20 @@ var init_output_schemas = __esm(() => {
224
229
  nextCursor: nullableString.optional(),
225
230
  next: z.record(z.string(), z.unknown()).optional()
226
231
  }).loose();
232
+ workflowStatusFields = {
233
+ status: z.string(),
234
+ badges: z.array(z.object({ kind: z.string(), status: z.string(), label: z.string() }).loose()),
235
+ group: nullableString,
236
+ reviewReason: z.object({ code: z.string(), explanation: z.string() }).loose().nullable(),
237
+ execution: apiField,
238
+ assistantState: apiField,
239
+ workspaceActivity: apiField
240
+ };
227
241
  WorkflowRowOutput = z.object({
228
242
  id: apiField,
229
243
  name: apiField,
230
244
  dashboardUrl: z.string(),
231
- status: z.string(),
245
+ ...workflowStatusFields,
232
246
  state: nullableString,
233
247
  displayState: nullableString,
234
248
  runState: nullableString,
@@ -239,7 +253,6 @@ var init_output_schemas = __esm(() => {
239
253
  createdAt: apiField,
240
254
  assistant: z.object({
241
255
  eligible: z.boolean(),
242
- dataStale: z.boolean(),
243
256
  session: z.object({ id: z.string(), threadId: apiField, status: apiField }).loose().nullable()
244
257
  }).loose(),
245
258
  template: z.object({ id: z.string(), pinnedVersion: apiField, latestVersion: apiField, isOutdated: z.boolean() }).loose().nullable(),
@@ -252,7 +265,7 @@ var init_output_schemas = __esm(() => {
252
265
  name: apiField,
253
266
  dashboardUrl: z.string(),
254
267
  description: apiField,
255
- status: z.string(),
268
+ ...workflowStatusFields,
256
269
  state: nullableString,
257
270
  displayState: nullableString,
258
271
  runState: nullableString,
@@ -263,7 +276,6 @@ var init_output_schemas = __esm(() => {
263
276
  entity: apiField,
264
277
  schema: apiField,
265
278
  navigationMode: apiField,
266
- dataStale: apiField,
267
279
  assistantEligible: z.boolean(),
268
280
  assistantSessionId: apiField,
269
281
  assistantThreadId: apiField,
@@ -292,8 +304,6 @@ var init_output_schemas = __esm(() => {
292
304
  createdAt: apiField,
293
305
  notificationConfig: apiField,
294
306
  channelCounts: apiField,
295
- dataValidation: apiField,
296
- validationStatistics: apiField,
297
307
  realtime: z.object({ lastDataChangedAt: apiField, observerHealth: apiField }).loose().nullable()
298
308
  }).loose();
299
309
  FetchDataOutput = z.object({
@@ -1888,11 +1898,11 @@ function scrapeResult(response, format) {
1888
1898
  };
1889
1899
  return withExtraContent(textOnlyResult(meta), { type: "text", text });
1890
1900
  }
1891
- function registerScrapeTools(server, ctx, helpers) {
1901
+ function registerScrapeTools(server, ctx, helpers, defaultProductType) {
1892
1902
  const { withErrorHandling } = helpers;
1893
1903
  server.registerTool("scrape", {
1894
1904
  title: "Scrape URL",
1895
- description: "Immediately fetch one URL as LLM-friendly markdown or raw HTML without creating a workflow. " + "Markdown is the default. Routing is fully automatic: it starts cheap and escalates through stealth tiers on its own when a site blocks bots, and remembers the working method per host. " + "Use create_workflow instead for structured extraction, recurring runs, monitoring, or navigation-heavy jobs. " + "The result is a JSON metadata block followed by the page text as its own block, capped at 70 KB.",
1905
+ description: "Immediately fetch one URL as LLM-friendly markdown or raw HTML without creating a workflow. " + "Markdown is the default. Routing is fully automatic: it starts cheap and escalates through stealth tiers on its own when a site blocks bots, and remembers the working method per host. " + (defaultProductType === "realtime" ? "Use create_realtime_monitor for monitoring, and create_workflow for one-time or scheduled structured extraction or navigation-heavy jobs. " : "Use create_workflow instead for structured extraction, recurring runs, monitoring, or navigation-heavy jobs. ") + "The result is a JSON metadata block followed by the page text as its own block, capped at 70 KB.",
1896
1906
  inputSchema: strictSchema({
1897
1907
  url: z7.url().refine((value) => {
1898
1908
  const protocol = new URL(value).protocol;
@@ -2161,24 +2171,31 @@ function registerWhoamiTool(server, ctx, helpers) {
2161
2171
  const { withErrorHandling } = helpers;
2162
2172
  server.registerTool("whoami", {
2163
2173
  title: "Show Current User",
2164
- description: "Show current user details: email, authentication method, and team memberships",
2174
+ description: "Show current user details: email, authentication method, team memberships, and the team's default product",
2165
2175
  inputSchema: strictSchema({}),
2166
2176
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
2167
2177
  }, withErrorHandling("whoami", async () => {
2178
+ const defaultProductTypePromise = ctx.client.user.getFeatures().then((features) => parseDefaultProductType(features.defaultProductType), () => {
2179
+ return;
2180
+ });
2168
2181
  if (ctx.principal.connector) {
2169
- const teams = await ctx.client.listTeams();
2182
+ const [teams, defaultProductType] = await Promise.all([
2183
+ ctx.client.listTeams(),
2184
+ defaultProductTypePromise
2185
+ ]);
2170
2186
  const activeTeam = teams.find((team) => team.id === ctx.principal.teamId);
2171
2187
  if (!activeTeam) {
2172
2188
  throw new Error("The active team is unavailable for this credential. Reconnect and choose a team.");
2173
2189
  }
2174
2190
  return jsonResult({
2175
2191
  authMethod: "Shared organization service account",
2176
- team: { name: activeTeam.name }
2192
+ team: { name: activeTeam.name, ...defaultProductType ? { defaultProductType } : {} }
2177
2193
  });
2178
2194
  }
2179
- const [user, teams] = await Promise.all([
2195
+ const [user, teams, defaultProductType] = await Promise.all([
2180
2196
  ctx.client.user.getCurrentUser(),
2181
- ctx.client.listTeams()
2197
+ ctx.client.listTeams(),
2198
+ defaultProductTypePromise
2182
2199
  ]);
2183
2200
  const activeTeam = teams.find((team) => team.id === ctx.principal.teamId);
2184
2201
  if (!activeTeam) {
@@ -2189,7 +2206,8 @@ function registerWhoamiTool(server, ctx, helpers) {
2189
2206
  authMethod: ctx.principal.actor ? `Kadoa Assistant (delegated via ${ctx.principal.actor.sub})` : "Kadoa access token",
2190
2207
  team: {
2191
2208
  name: activeTeam.name,
2192
- ...activeTeam.memberRole ? { memberRole: activeTeam.memberRole } : {}
2209
+ ...activeTeam.memberRole ? { memberRole: activeTeam.memberRole } : {},
2210
+ ...defaultProductType ? { defaultProductType } : {}
2193
2211
  },
2194
2212
  scopes: ctx.principal.scopes
2195
2213
  });
@@ -2649,49 +2667,109 @@ var init_variables = __esm(() => {
2649
2667
  init_schemas();
2650
2668
  });
2651
2669
 
2652
- // src/tools/workflows.ts
2653
- import { WorkflowStatusFilter } from "@kadoa/node-sdk";
2654
- import { z as z12 } from "zod";
2670
+ // src/tools/shared/workflow-status.ts
2671
+ function reviewReasonExplanation(reason) {
2672
+ return reason && REVIEW_REASON_EXPLANATIONS[reason] || UNKNOWN_REVIEW_REASON;
2673
+ }
2655
2674
  function isRealTimeInterval(interval) {
2656
2675
  return interval?.toUpperCase().replace("-", "_") === "REAL_TIME";
2657
2676
  }
2658
- function deriveStatusLabel(workflow) {
2659
- const ds = workflow.displayState ?? workflow.state;
2660
- switch (ds) {
2661
- case "ACTIVE":
2662
- if (isRealTimeInterval(workflow.updateInterval))
2663
- return "Running";
2664
- if (!workflow.updateInterval || workflow.updateInterval === "only once")
2665
- return "Complete";
2666
- return "Scheduled";
2667
- case "RUNNING":
2668
- return "Running";
2669
- case "VALIDATING":
2670
- return "Validating";
2671
- case "FAILED":
2672
- return "Failed";
2673
- case "PAUSED":
2674
- return "Paused";
2675
- case "SETUP":
2676
- return "Sample Processing";
2677
- case "QUEUED":
2678
- return "Queued";
2679
- case "PENDING_START":
2680
- return "Not Started";
2681
- case "PREVIEW":
2682
- return "Pending Review";
2683
- case "DEGRADED":
2684
- return "Degraded";
2685
- case "DELETED":
2686
- return "Deleted";
2687
- case "COMPLIANCE_REVIEW":
2688
- return "Compliance Review";
2689
- case "COMPLIANCE_REJECTED":
2690
- return "Rejected";
2691
- default:
2692
- return ds ?? "Unknown";
2677
+ function fallbackStatusCode(w) {
2678
+ const ds = w.displayState ?? w.state ?? null;
2679
+ if (ds === "ACTIVE") {
2680
+ if (w.isRealTime === true || isRealTimeInterval(w.updateInterval))
2681
+ return "RUNNING";
2682
+ return w.updateInterval && !["ONLY_ONCE", "only once"].includes(w.updateInterval) ? "SCHEDULED" : "COMPLETE";
2693
2683
  }
2684
+ if (ds === "VALIDATING")
2685
+ return "AWAITING_REVIEW";
2686
+ return ds;
2687
+ }
2688
+ function labelFor(code, previewReady) {
2689
+ const label = WORKFLOW_STATUS_LABELS[code === "PREVIEW" && previewReady ? "PREVIEW_READY" : code];
2690
+ if (label)
2691
+ return label;
2692
+ console.error(`[workflow-status] unmapped workflow status, passing through verbatim: ${code}`);
2693
+ return code;
2694
+ }
2695
+ function workflowStatusLabel(w) {
2696
+ const code = w.presentation?.status ?? fallbackStatusCode(w);
2697
+ if (!code)
2698
+ return "Unknown";
2699
+ return labelFor(code, w.availableActions?.approve?.allowed === true);
2700
+ }
2701
+ function workflowStatusView(w) {
2702
+ const previewReady = w.availableActions?.approve?.allowed === true;
2703
+ return {
2704
+ status: workflowStatusLabel(w),
2705
+ badges: (w.presentation?.badges ?? []).map((b) => ({
2706
+ kind: b.kind,
2707
+ status: b.status,
2708
+ label: labelFor(b.status, previewReady)
2709
+ })),
2710
+ group: w.presentation?.group ?? null,
2711
+ reviewReason: w.reviewReason ? { code: w.reviewReason, explanation: reviewReasonExplanation(w.reviewReason) } : null
2712
+ };
2694
2713
  }
2714
+ function runStatusLabel(state) {
2715
+ if (!state)
2716
+ return "Unknown";
2717
+ return RUN_STATE_LABELS[state] ?? state;
2718
+ }
2719
+ var REVIEW_STATUS_LABEL = "Verifying data", WORKFLOW_STATUS_LABELS, REVIEW_REASON_EXPLANATIONS, UNKNOWN_REVIEW_REASON = "Kadoa's quality or compliance checks selected this run for review.", RUN_STATE_LABELS;
2720
+ var init_workflow_status = __esm(() => {
2721
+ WORKFLOW_STATUS_LABELS = {
2722
+ ASSISTANT_WORKING: "Agent working",
2723
+ AWAITING_REVIEW: REVIEW_STATUS_LABEL,
2724
+ COMPLETE: "Complete",
2725
+ COMPLIANCE_REJECTED: "Rejected",
2726
+ COMPLIANCE_REVIEW: "Compliance review",
2727
+ DEGRADED: "Degraded",
2728
+ DELETED: "Deleted",
2729
+ DRAFT: "Draft",
2730
+ ERROR: "Failed",
2731
+ FAILED: "Failed",
2732
+ IN_SUPPORT: "In support",
2733
+ NOT_SUPPORTED: "Not supported",
2734
+ PAUSED: "Paused",
2735
+ PENDING_START: "Not started",
2736
+ PREVIEW: "Preview",
2737
+ PREVIEW_READY: "Preview ready",
2738
+ QUEUED: "Queued",
2739
+ REPLY_NEEDED: "Reply needed",
2740
+ RUNNING: "Running",
2741
+ SCHEDULED: "Scheduled",
2742
+ SETUP: "Setup",
2743
+ STOPPED: "Stopped",
2744
+ UPDATE_FAILED: "Update failed",
2745
+ UPDATING: "Updating"
2746
+ };
2747
+ REVIEW_REASON_EXPLANATIONS = {
2748
+ COMPLIANCE_REVIEW: "This run triggered a compliance check before delivery.",
2749
+ HARD_FAIL: "An error stopped this run from completing normally.",
2750
+ TRANSFORMATION_REPAIR_REQUIRED: "A data transformation could not be fixed automatically.",
2751
+ MINIMUM_HUMAN_APPROVALS: "Kadoa's quality checks selected this run for review before delivery.",
2752
+ DATA_QUALITY_SCHEMA_ADHERENCE: "The extracted data did not match this workflow's fields and data types.",
2753
+ DATA_QUALITY_SCHEMA_VALIDATION: "Extracted values did not match this workflow's validation rules.",
2754
+ DATA_QUALITY_COMPLETENESS: "The extracted record count did not match the expected source count.",
2755
+ DATA_QUALITY_SEMANTIC_PLAUSIBILITY: "Some extracted values look unusual for their fields.",
2756
+ ROW_COUNT_CHANGED: "This run's row count changed significantly.",
2757
+ WORKFLOW_REVISION_DRIFT: "This run no longer matches the workflow's current setup.",
2758
+ ZERO_RESULTS: "The source returned no data."
2759
+ };
2760
+ RUN_STATE_LABELS = {
2761
+ FINISHED: "Success",
2762
+ IN_PROGRESS: "Running",
2763
+ VALIDATING: REVIEW_STATUS_LABEL,
2764
+ FAILED: "Failed",
2765
+ FAILED_INSUFFICIENT_FUNDS: "Failed",
2766
+ NOT_SUPPORTED: "Failed"
2767
+ };
2768
+ });
2769
+
2770
+ // src/tools/workflows.ts
2771
+ import { WorkflowStatusFilter } from "@kadoa/node-sdk";
2772
+ import { z as z12 } from "zod";
2695
2773
  function mapRunStatus(state) {
2696
2774
  switch (state) {
2697
2775
  case "FINISHED":
@@ -2789,7 +2867,7 @@ function summarizeWorkflowAuditEntry(entry) {
2789
2867
  function historyEmptyHint(includeSnapshots) {
2790
2868
  return includeSnapshots ? "A single entry is too large to return inline. Retry without includeSnapshots for the diff summary." : "A single entry is too large to return inline even without snapshots. Retry with a narrower page (e.g. limit=1) or fewer fields.";
2791
2869
  }
2792
- function registerWorkflowCoreTools(server, ctx, helpers) {
2870
+ function registerWorkflowCoreTools(server, ctx, helpers, defaultProductType) {
2793
2871
  const { withErrorHandling } = helpers;
2794
2872
  function resolveUrls(args) {
2795
2873
  const urls = args.urls ?? (args.url ? [args.url] : []);
@@ -2897,7 +2975,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
2897
2975
 
2898
2976
  ` + "Create a data extraction workflow using agentic navigation. Supports one-time or scheduled runs. " + "If entity and schema are provided, they guide the extraction; otherwise the AI agent auto-detects the schema from the page. " + "The workflow runs asynchronously and may take several minutes. Do NOT poll or sleep-wait for completion. " + `Return the workflow ID to the user and let them check back later with get_workflow or fetch_data.
2899
2977
 
2900
- ` + "PREFER TEMPLATES: If the user's request matches an existing template, instantiate it via `templateId` instead of writing a fresh prompt/schema. " + "Use `list_templates` to discover available templates and `get_template` to inspect schemas before deciding. " + "When creating from a template, call this tool with the template's `templateId`, the source `urls`, optional `templateVersion`, and optional `prompt` containing only workflow-specific additional instructions. Never copy the template prompt, entity, or schema into the call, and never silently match or rewrite inline configuration.\n\n" + "NOTE: This tool is for one-time or scheduled extraction ONLY. " + "For continuous realtime monitoring that watches a page for data changes and sends alerts, use the create_realtime_monitor tool instead.",
2978
+ ` + "PREFER TEMPLATES: If the user's request matches an existing template, instantiate it via `templateId` instead of writing a fresh prompt/schema. " + "Use `list_templates` to discover available templates and `get_template` to inspect schemas before deciding. " + "When creating from a template, call this tool with the template's `templateId`, the source `urls`, optional `templateVersion`, and optional `prompt` containing only workflow-specific additional instructions. Never copy the template prompt, entity, or schema into the call, and never silently match or rewrite inline configuration.\n\n" + "NOTE: This tool is for one-time or scheduled extraction ONLY. " + (defaultProductType === "realtime" ? `This team's default product is realtime monitoring. Do not call this tool unless the user explicitly asked for a one-time run (e.g. "once", "just the current list") or a schedule (e.g. "daily"). A request to get, extract, or scrape data that names no frequency is not explicit: call create_realtime_monitor instead.` : "For continuous realtime monitoring that watches a page for data changes and sends alerts, use the create_realtime_monitor tool instead."),
2901
2979
  inputSchema: strictSchema({
2902
2980
  prompt: extractionPromptInput.describe('Natural language description of what to extract (e.g., "Extract product prices and names"). Required unless templateId is provided. With templateId, use it only for workflow-specific instructions to add to the template prompt.'),
2903
2981
  ...extractionInputShape,
@@ -3050,7 +3128,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3050
3128
  }
3051
3129
  server.registerTool("create_realtime_monitor", {
3052
3130
  title: "Create Realtime Monitor",
3053
- description: "Create a realtime monitoring workflow that continuously watches a page for data changes and sends alerts. " + "Use this when the user wants to monitor, track, or watch a page in realtime. " + "At least one notification channel (email, webhook, slack, or websocket) is required; notification settings are persisted before Assistant creation is dispatched. " + `Realtime monitors CANNOT be converted to/from one-time or scheduled extraction workflows after creation.
3131
+ description: "Create a realtime monitoring workflow that continuously watches a page for data changes and sends alerts. " + (defaultProductType === "realtime" ? "This team's default product is realtime monitoring: use this tool whenever the user asks to monitor, track, or watch a page, or to get or extract data from it, unless they explicitly ask for a one-time run or a schedule. A request that names no frequency counts as realtime. " : "Use this when the user wants to monitor, track, or watch a page in realtime. ") + "At least one notification channel (email, webhook, slack, or websocket) is required; notification settings are persisted before Assistant creation is dispatched. " + `Realtime monitors CANNOT be converted to/from one-time or scheduled extraction workflows after creation.
3054
3132
 
3055
3133
  ` + "If entity and schema are provided, they guide what the Assistant should monitor; otherwise the Assistant determines what to watch. " + "Creation is asynchronous and the response includes workflow, session, thread, and job IDs plus a dashboard URL. " + "Use generic workflow Assistant tools (get_workflow_assistant, answer_workflow_assistant_question, interrupt_workflow_assistant, resume_workflow_assistant, stop_workflow_assistant) for follow-up status, questions, and controls. " + "Do NOT poll or sleep-wait for completion.",
3056
3134
  inputSchema: strictSchema({
@@ -3107,7 +3185,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3107
3185
  }));
3108
3186
  server.registerTool("list_workflows", {
3109
3187
  title: "List Workflows",
3110
- description: `List workflows with customer-visible status, raw workflow and run states, Assistant session availability, template version drift, realtime freshness or health, and awaitingUserInput when the requesting user must act. Uses one paginated list request; use get_workflow only when you need full details for a selected workflow. To answer "what needs my attention", pass statusFilters: ["group:attention"]; this returns exactly the dashboard's "Needs your attention" group. In group:attention, a row with awaitingUserInput.prompt is an Assistant question: use get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with displayState PREVIEW and no awaitingUserInput is preview data: use approve_workflow. Workflows with an open support ticket are excluded from group:attention and appear under group:support.`,
3188
+ description: `List workflows with customer-visible status, raw workflow and run states, Assistant session availability, template version drift, realtime freshness or health, and awaitingUserInput when the requesting user must act. Uses one paginated list request; use get_workflow only when you need full details for a selected workflow. To answer "what needs my attention", pass statusFilters: ["group:attention"]; this returns exactly the dashboard's "Needs your attention" group. In group:attention, a row with awaitingUserInput.prompt is an Assistant question: use get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with status "Preview ready" is preview data ready to approve with approve_workflow; "Preview" means preview data exists but approval isn't available yet. Workflows with an open support ticket are excluded from group:attention and appear under group:support. badges[].label is exactly what the Kadoa dashboard displays (lifecycle, activity, and support badges, e.g. "Setup" + "Agent working"): use these labels when describing the workflow to the user. status is the one-line summary in dashboard wording (e.g. "Verifying data" = the latest run is held for quality review before delivery; see reviewReason for why).`,
3111
3189
  inputSchema: strictSchema({
3112
3190
  limit: limitInput({
3113
3191
  noun: "Workflows",
@@ -3145,10 +3223,13 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3145
3223
  id: w.id,
3146
3224
  name: w.name,
3147
3225
  dashboardUrl: workflowDashboardUrl(w.id),
3148
- status: deriveStatusLabel(w),
3226
+ ...workflowStatusView(w),
3149
3227
  state: w.state ?? null,
3150
3228
  displayState: w.displayState ?? null,
3151
3229
  runState: w.runState ?? null,
3230
+ execution: w.execution ?? null,
3231
+ assistantState: w.assistantState ?? null,
3232
+ workspaceActivity: w.workspaceActivity ?? null,
3152
3233
  urls: w.urls,
3153
3234
  totalRecords: w.totalRecords,
3154
3235
  startedAt: w.startedAt,
@@ -3156,7 +3237,6 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3156
3237
  createdAt: w.createdAt,
3157
3238
  assistant: {
3158
3239
  eligible: w.assistantEligible === true,
3159
- dataStale: w.dataStale === true,
3160
3240
  session: w.assistantSessionId ? {
3161
3241
  id: w.assistantSessionId,
3162
3242
  threadId: w.assistantThreadId ?? null,
@@ -3188,7 +3268,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3188
3268
  }));
3189
3269
  server.registerTool("get_workflow", {
3190
3270
  title: "Get Workflow",
3191
- description: "Get canonical workflow details, including Assistant/session linkage, extraction intent, template-controlled parts, stale-data state, job/run state, schedule timezone, location, monitoring, validation, and realtime health. For Assistant-built workflows, extractionSpec - not the legacy prompt - is authoritative.",
3271
+ description: 'Get canonical workflow details, including Assistant/session linkage, extraction intent, template-controlled parts, job/run state, schedule timezone, location, monitoring, and realtime health. For Assistant-built workflows, extractionSpec - not the legacy prompt - is authoritative. badges[].label is exactly what the Kadoa dashboard displays (lifecycle, activity, and support badges, e.g. "Setup" + "Agent working"): use these labels when describing the workflow to the user. status is the one-line summary in dashboard wording (e.g. "Verifying data" = the latest run is held for quality review before delivery; see reviewReason for why).',
3192
3272
  inputSchema: strictSchema({
3193
3273
  workflowId: z12.string().min(1).describe("The workflow ID")
3194
3274
  }),
@@ -3213,10 +3293,13 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3213
3293
  name: workflow.name,
3214
3294
  dashboardUrl: workflowDashboardUrl(workflow.id ?? args.workflowId),
3215
3295
  description: workflow.description,
3216
- status: deriveStatusLabel(workflow),
3296
+ ...workflowStatusView(workflow),
3217
3297
  state: workflow.state ?? null,
3218
3298
  displayState: workflow.displayState ?? null,
3219
3299
  runState: workflow.runState ?? null,
3300
+ execution: workflow.execution ?? null,
3301
+ assistantState: workflow.assistantState ?? null,
3302
+ workspaceActivity: workflow.workspaceActivity ?? null,
3220
3303
  urls: workflow.urls,
3221
3304
  prompt: extractionSpec ? null : legacyPrompt,
3222
3305
  intentSource: extractionSpec ? "extraction_spec" : legacyPrompt ? "legacy_prompt" : null,
@@ -3224,7 +3307,6 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3224
3307
  entity: workflow.entity,
3225
3308
  schema: workflow.schema,
3226
3309
  navigationMode: workflow.navigationMode,
3227
- dataStale: workflow.dataStale ?? false,
3228
3310
  assistantEligible: workflow.assistantEligible === true,
3229
3311
  assistantSessionId: workflow.assistantSessionId ?? null,
3230
3312
  assistantThreadId: workflow.assistantThreadId ?? null,
@@ -3267,8 +3349,6 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3267
3349
  createdAt: workflow.createdAt,
3268
3350
  notificationConfig: workflow.notificationConfig,
3269
3351
  channelCounts: workflow.channelCounts ?? {},
3270
- dataValidation: workflow.dataValidation ?? null,
3271
- validationStatistics: workflow.validationStatistics ?? null,
3272
3352
  realtime: isRealtime ? {
3273
3353
  lastDataChangedAt: workflow.lastDataChangedAt ?? null,
3274
3354
  observerHealth: workflow.observerHealth ?? null
@@ -3368,7 +3448,7 @@ function registerWorkflowHistoryTools(server, ctx, helpers) {
3368
3448
  }));
3369
3449
  server.registerTool("list_workflow_runs", {
3370
3450
  title: "List Workflow Runs",
3371
- description: "List a workflow's execution run history - each run's status, start/finish time, " + "record count, and errors. Use to answer 'when did this last succeed?' " + "(status='success', limit=1) or 'recent success/failure pattern?'. Distinct from " + "get_workflow_history, which is the config audit log. `status` is normally " + "success | failed | in_progress; a run whose backend state this server does not " + "recognize reports that raw state verbatim, so treat any other value as unknown " + "rather than as a failure.",
3451
+ description: "List a workflow's execution run history - each run's status, start/finish time, " + "record count, and errors. Use to answer 'when did this last succeed?' " + "(status='success', limit=1) or 'recent success/failure pattern?'. Distinct from " + "get_workflow_history, which is the config audit log. `status` is normally " + "success | failed | in_progress; a run whose backend state this server does not " + "recognize reports that raw state verbatim, so treat any other value as unknown " + "rather than as a failure. `label` is the dashboard's wording for the run " + "(Success, Failed, Running, or 'Verifying data' = held for quality review before delivery); " + "prefer it when describing a run to the user.",
3372
3452
  inputSchema: strictSchema({
3373
3453
  workflowId: z12.string().min(1).describe("The workflow ID"),
3374
3454
  status: z12.enum(["success", "failed", "in_progress"]).optional().describe("Filter runs by outcome"),
@@ -3387,6 +3467,7 @@ function registerWorkflowHistoryTools(server, ctx, helpers) {
3387
3467
  const runs = (response.workflowRuns ?? []).map((r) => ({
3388
3468
  id: r.id,
3389
3469
  status: mapRunStatus(r.state),
3470
+ label: runStatusLabel(r.state),
3390
3471
  startedAt: r.startedAt,
3391
3472
  finishedAt: r.finishedAt,
3392
3473
  records: r.records,
@@ -3436,7 +3517,7 @@ function registerWorkflowRunTools(server, ctx, helpers) {
3436
3517
  const FETCH_DATA_MAX_LIMIT = 500;
3437
3518
  server.registerTool("fetch_data", {
3438
3519
  title: "Fetch Workflow Data",
3439
- description: "Get a PAGE of extracted data from a workflow. Use ONLY for previews, sorted/filtered slices, or explicit 'first N rows' / 'top N' queries (capped at 500 rows per call). Do NOT use this to retrieve a full dataset, 'all rows', or anything the user wants to analyze in Excel / pandas / duckdb - use export_data for those. Data is only available after the workflow run has completed (status is no longer 'Running' or 'Validating'). Do NOT poll or sleep-wait for completion.",
3520
+ description: "Get a PAGE of extracted data from a workflow. Use ONLY for previews, sorted/filtered slices, or explicit 'first N rows' / 'top N' queries (capped at 500 rows per call). Do NOT use this to retrieve a full dataset, 'all rows', or anything the user wants to analyze in Excel / pandas / duckdb - use export_data for those. Data is only available after the workflow run has completed (status is no longer 'Running' or 'Verifying data'). Do NOT poll or sleep-wait for completion.",
3440
3521
  inputSchema: strictSchema({
3441
3522
  workflowId: z12.string().min(1).describe("The workflow ID"),
3442
3523
  limit: limitInput({
@@ -3598,7 +3679,7 @@ function registerWorkflowRunTools(server, ctx, helpers) {
3598
3679
  try {
3599
3680
  const workflow = await ctx.client.workflow.get(args.workflowId);
3600
3681
  workflowName = workflow.name || args.workflowId;
3601
- workflowStatus = deriveStatusLabel(workflow);
3682
+ workflowStatus = workflowStatusLabel(workflow);
3602
3683
  } catch {}
3603
3684
  if (!args.confirmed) {
3604
3685
  return jsonResult({
@@ -3710,6 +3791,7 @@ var init_workflows = __esm(() => {
3710
3791
  init_output_schemas();
3711
3792
  init_pagination();
3712
3793
  init_schemas();
3794
+ init_workflow_status();
3713
3795
  WORKFLOW_AUDIT_WATCHED_KEYS = [
3714
3796
  "name",
3715
3797
  "tags",
@@ -3727,9 +3809,9 @@ var init_workflows = __esm(() => {
3727
3809
  function registerTools(server, ctx, capabilities) {
3728
3810
  const helpers = { withErrorHandling: createWithErrorHandling(ctx) };
3729
3811
  if (capabilities.scrape)
3730
- registerScrapeTools(server, ctx, helpers);
3812
+ registerScrapeTools(server, ctx, helpers, capabilities.defaultProductType);
3731
3813
  registerWhoamiTool(server, ctx, helpers);
3732
- registerWorkflowCoreTools(server, ctx, helpers);
3814
+ registerWorkflowCoreTools(server, ctx, helpers, capabilities.defaultProductType);
3733
3815
  registerAssistantTools(server, ctx, helpers);
3734
3816
  registerWorkflowHistoryTools(server, ctx, helpers);
3735
3817
  registerObservabilityTools(server, ctx, helpers);
@@ -4413,12 +4495,41 @@ var init_request_log = __esm(() => {
4413
4495
 
4414
4496
  // src/server.ts
4415
4497
  import { McpServer as McpServer2 } from "@modelcontextprotocol/server";
4498
+ function lifecycleInstruction2(defaultProductType) {
4499
+ return defaultProductType === "realtime" ? "For one-time or scheduled workflows, the lifecycle is create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait." : "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.";
4500
+ }
4501
+ function routingInstructions2(defaultProductType) {
4502
+ if (defaultProductType === "realtime") {
4503
+ return [
4504
+ `This team's default product is realtime monitoring. Use create_realtime_monitor whenever the user asks to monitor, track, or watch a page, or to get or extract data from it, unless they explicitly ask for a one-time run (e.g. "once") or a schedule (e.g. "daily"). A request that names no frequency is not explicit: default to realtime without asking the user to choose. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.`,
4505
+ "Use create_workflow only when the user explicitly asks for a one-time run or a schedule. Use scrape for an immediate raw HTML or markdown fetch from one URL."
4506
+ ];
4507
+ }
4508
+ return [
4509
+ "Use create_realtime_monitor only when the user wants continuous realtime change detection with alerts. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.",
4510
+ "For one-time or scheduled extraction, use create_workflow. Use scrape for an immediate raw HTML or markdown fetch from one URL. Use create_workflow for structured extraction, recurring runs, monitoring, or navigation-heavy jobs."
4511
+ ];
4512
+ }
4416
4513
  async function createServer3(auth, options) {
4417
4514
  const ctx = {
4418
4515
  client: createKadoaClient(auth),
4419
4516
  principal: auth.principal,
4420
4517
  teamId: auth.principal.teamId
4421
4518
  };
4519
+ let capabilities = options?.capabilities;
4520
+ if (!capabilities) {
4521
+ try {
4522
+ const response = await ctx.client.user.getFeatures();
4523
+ capabilities = {
4524
+ scrape: response.features.scrape,
4525
+ defaultProductType: parseDefaultProductType(response.defaultProductType)
4526
+ };
4527
+ } catch (error) {
4528
+ const message = error instanceof Error ? error.message : "unknown error";
4529
+ console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
4530
+ capabilities = { scrape: false };
4531
+ }
4532
+ }
4422
4533
  const server = new McpServer2({ name: "kadoa", version: package_default.version }, {
4423
4534
  instructions: [
4424
4535
  "IMPORTANT: One workflow = one source. A single workflow can extract many different fields, tables, and sections from the same URL(s) using a rich schema.",
@@ -4427,15 +4538,14 @@ async function createServer3(auth, options) {
4427
4538
  "Kadoa workflows use agentic navigation: the AI agent can browse pages, click buttons, fill forms, select dropdowns, paginate, open detail pages, and handle multi-step interactions.",
4428
4539
  "Describe the full navigation steps in the prompt (e.g., 'select year 2022 from the dropdown, click Search, extract the table, then repeat for 2023').",
4429
4540
  "",
4430
- "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.",
4541
+ lifecycleInstruction2(capabilities.defaultProductType),
4431
4542
  "",
4432
- "Use create_realtime_monitor only when the user wants continuous realtime change detection with alerts. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.",
4433
- "For one-time or scheduled extraction, use create_workflow. Use scrape for an immediate raw HTML or markdown fetch from one URL. Use create_workflow for structured extraction, recurring runs, monitoring, or navigation-heavy jobs.",
4543
+ ...routingInstructions2(capabilities.defaultProductType),
4434
4544
  "If a one-time or scheduled workflow fails, retry it with run_workflow using the existing workflow ID. Do NOT delete and recreate the workflow just to retry it - preserve its workflow ID and configuration. Realtime workflows cannot be manually run.",
4435
4545
  "Use list_changes and get_change to retrieve detected diffs from realtime monitoring workflows.",
4436
4546
  "List tools, plus fetch_data, get_workflow_history, and get_workflow_assistant_timeline, all return pagination {totalCount?, hasMore, next?}. When hasMore is true, call the same tool again with pagination.next as its arguments to get the next page. totalCount is present only when the total is known; never treat the page size as the total.",
4437
4547
  "Large results (fetch_data, get_workflow_history, get_change) are cut to whole rows or entries under about 80 KB and marked truncated: true with a hint; follow pagination.next, narrow the filters, or use export_data, and never conclude the data ends there.",
4438
- "When the user asks what needs their attention, call list_workflows with statusFilters group:attention. A row with awaitingUserInput.prompt is the Assistant's pending question: answer it with get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with displayState PREVIEW and no awaitingUserInput is preview data to review or approve with approve_workflow. Workflows with an open support ticket are excluded from group:attention and appear under group:support.",
4548
+ `When the user asks what needs their attention, call list_workflows with statusFilters group:attention. A row with awaitingUserInput.prompt is the Assistant's pending question: answer it with get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with status "Preview ready" is preview data ready to approve with approve_workflow; "Preview" means preview data exists but approval isn't available yet. Workflows with an open support ticket are excluded from group:attention and appear under group:support.`,
4439
4549
  "",
4440
4550
  "Schema tips: Use descriptive field names and examples. Group related data under one entity.",
4441
4551
  "The AI agent uses the schema + prompt to understand what to extract - a detailed prompt with a comprehensive schema produces better results than multiple simple workflows.",
@@ -4444,17 +4554,6 @@ async function createServer3(auth, options) {
4444
4554
  ].join(`
4445
4555
  `)
4446
4556
  });
4447
- let capabilities = options?.capabilities;
4448
- if (!capabilities) {
4449
- try {
4450
- const response = await ctx.client.user.getFeatures();
4451
- capabilities = { scrape: response.features.scrape };
4452
- } catch (error) {
4453
- const message = error instanceof Error ? error.message : "unknown error";
4454
- console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
4455
- capabilities = { scrape: false };
4456
- }
4457
- }
4458
4557
  registerTools(server, ctx, capabilities);
4459
4558
  server.server.onerror = (error) => console.error("[MCP Error]", safeErrorSummary(error));
4460
4559
  return server;
@@ -4534,7 +4633,7 @@ async function requestNeedsCapabilityLookup(request) {
4534
4633
  return false;
4535
4634
  }
4536
4635
  }
4537
- return method === "tools/list" || method === "tools/call" && name === "scrape";
4636
+ return method === "initialize" || method === "server/discover" || method === "tools/list" || method === "tools/call" && name === "scrape";
4538
4637
  }
4539
4638
  function isClientCausedHandlerError(error) {
4540
4639
  if (error instanceof ProtocolError)
@@ -4874,12 +4973,41 @@ init_package();
4874
4973
  init_client();
4875
4974
  init_tools();
4876
4975
  import { McpServer } from "@modelcontextprotocol/server";
4976
+ function lifecycleInstruction(defaultProductType) {
4977
+ return defaultProductType === "realtime" ? "For one-time or scheduled workflows, the lifecycle is create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait." : "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.";
4978
+ }
4979
+ function routingInstructions(defaultProductType) {
4980
+ if (defaultProductType === "realtime") {
4981
+ return [
4982
+ `This team's default product is realtime monitoring. Use create_realtime_monitor whenever the user asks to monitor, track, or watch a page, or to get or extract data from it, unless they explicitly ask for a one-time run (e.g. "once") or a schedule (e.g. "daily"). A request that names no frequency is not explicit: default to realtime without asking the user to choose. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.`,
4983
+ "Use create_workflow only when the user explicitly asks for a one-time run or a schedule. Use scrape for an immediate raw HTML or markdown fetch from one URL."
4984
+ ];
4985
+ }
4986
+ return [
4987
+ "Use create_realtime_monitor only when the user wants continuous realtime change detection with alerts. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.",
4988
+ "For one-time or scheduled extraction, use create_workflow. Use scrape for an immediate raw HTML or markdown fetch from one URL. Use create_workflow for structured extraction, recurring runs, monitoring, or navigation-heavy jobs."
4989
+ ];
4990
+ }
4877
4991
  async function createServer(auth, options) {
4878
4992
  const ctx = {
4879
4993
  client: createKadoaClient(auth),
4880
4994
  principal: auth.principal,
4881
4995
  teamId: auth.principal.teamId
4882
4996
  };
4997
+ let capabilities = options?.capabilities;
4998
+ if (!capabilities) {
4999
+ try {
5000
+ const response = await ctx.client.user.getFeatures();
5001
+ capabilities = {
5002
+ scrape: response.features.scrape,
5003
+ defaultProductType: parseDefaultProductType(response.defaultProductType)
5004
+ };
5005
+ } catch (error) {
5006
+ const message = error instanceof Error ? error.message : "unknown error";
5007
+ console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
5008
+ capabilities = { scrape: false };
5009
+ }
5010
+ }
4883
5011
  const server = new McpServer({ name: "kadoa", version: package_default.version }, {
4884
5012
  instructions: [
4885
5013
  "IMPORTANT: One workflow = one source. A single workflow can extract many different fields, tables, and sections from the same URL(s) using a rich schema.",
@@ -4888,15 +5016,14 @@ async function createServer(auth, options) {
4888
5016
  "Kadoa workflows use agentic navigation: the AI agent can browse pages, click buttons, fill forms, select dropdowns, paginate, open detail pages, and handle multi-step interactions.",
4889
5017
  "Describe the full navigation steps in the prompt (e.g., 'select year 2022 from the dropdown, click Search, extract the table, then repeat for 2023').",
4890
5018
  "",
4891
- "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.",
5019
+ lifecycleInstruction(capabilities.defaultProductType),
4892
5020
  "",
4893
- "Use create_realtime_monitor only when the user wants continuous realtime change detection with alerts. It first persists notification channels, then asynchronously returns workflow/session/thread/job IDs; use the workflow Assistant tools for follow-up status, questions, and controls.",
4894
- "For one-time or scheduled extraction, use create_workflow. Use scrape for an immediate raw HTML or markdown fetch from one URL. Use create_workflow for structured extraction, recurring runs, monitoring, or navigation-heavy jobs.",
5021
+ ...routingInstructions(capabilities.defaultProductType),
4895
5022
  "If a one-time or scheduled workflow fails, retry it with run_workflow using the existing workflow ID. Do NOT delete and recreate the workflow just to retry it - preserve its workflow ID and configuration. Realtime workflows cannot be manually run.",
4896
5023
  "Use list_changes and get_change to retrieve detected diffs from realtime monitoring workflows.",
4897
5024
  "List tools, plus fetch_data, get_workflow_history, and get_workflow_assistant_timeline, all return pagination {totalCount?, hasMore, next?}. When hasMore is true, call the same tool again with pagination.next as its arguments to get the next page. totalCount is present only when the total is known; never treat the page size as the total.",
4898
5025
  "Large results (fetch_data, get_workflow_history, get_change) are cut to whole rows or entries under about 80 KB and marked truncated: true with a hint; follow pagination.next, narrow the filters, or use export_data, and never conclude the data ends there.",
4899
- "When the user asks what needs their attention, call list_workflows with statusFilters group:attention. A row with awaitingUserInput.prompt is the Assistant's pending question: answer it with get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with displayState PREVIEW and no awaitingUserInput is preview data to review or approve with approve_workflow. Workflows with an open support ticket are excluded from group:attention and appear under group:support.",
5026
+ `When the user asks what needs their attention, call list_workflows with statusFilters group:attention. A row with awaitingUserInput.prompt is the Assistant's pending question: answer it with get_workflow_assistant then answer_workflow_assistant_question. A row with awaitingUserInput but no prompt is a setup the user left unfinished: use get_workflow_assistant to see where it stopped, then resume_workflow_assistant or request_workflow_update. A row with status "Preview ready" is preview data ready to approve with approve_workflow; "Preview" means preview data exists but approval isn't available yet. Workflows with an open support ticket are excluded from group:attention and appear under group:support.`,
4900
5027
  "",
4901
5028
  "Schema tips: Use descriptive field names and examples. Group related data under one entity.",
4902
5029
  "The AI agent uses the schema + prompt to understand what to extract - a detailed prompt with a comprehensive schema produces better results than multiple simple workflows.",
@@ -4905,17 +5032,6 @@ async function createServer(auth, options) {
4905
5032
  ].join(`
4906
5033
  `)
4907
5034
  });
4908
- let capabilities = options?.capabilities;
4909
- if (!capabilities) {
4910
- try {
4911
- const response = await ctx.client.user.getFeatures();
4912
- capabilities = { scrape: response.features.scrape };
4913
- } catch (error) {
4914
- const message = error instanceof Error ? error.message : "unknown error";
4915
- console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
4916
- capabilities = { scrape: false };
4917
- }
4918
- }
4919
5035
  registerTools(server, ctx, capabilities);
4920
5036
  server.server.onerror = (error) => console.error("[MCP Error]", safeErrorSummary(error));
4921
5037
  return server;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kadoa/mcp",
3
- "version": "0.7.0-rc.2",
3
+ "version": "0.7.1",
4
4
  "description": "Kadoa MCP Server — manage workflows from Claude Desktop, Cursor, and other MCP clients",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,7 +27,7 @@
27
27
  "prepublishOnly": "bun run check-types && bun run test:unit && bun run build"
28
28
  },
29
29
  "dependencies": {
30
- "@kadoa/node-sdk": "^0.45.0",
30
+ "@kadoa/node-sdk": "^0.48.0",
31
31
  "@modelcontextprotocol/client": "2.1.0",
32
32
  "@modelcontextprotocol/express": "2.0.1",
33
33
  "@modelcontextprotocol/node": "2.1.0",