@kadoa/mcp 0.7.0-rc.2 → 0.7.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.
Files changed (2) hide show
  1. package/dist/index.js +90 -43
  2. package/package.json +1 -1
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.0",
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",
@@ -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]");
@@ -1888,11 +1893,11 @@ function scrapeResult(response, format) {
1888
1893
  };
1889
1894
  return withExtraContent(textOnlyResult(meta), { type: "text", text });
1890
1895
  }
1891
- function registerScrapeTools(server, ctx, helpers) {
1896
+ function registerScrapeTools(server, ctx, helpers, defaultProductType) {
1892
1897
  const { withErrorHandling } = helpers;
1893
1898
  server.registerTool("scrape", {
1894
1899
  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.",
1900
+ 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
1901
  inputSchema: strictSchema({
1897
1902
  url: z7.url().refine((value) => {
1898
1903
  const protocol = new URL(value).protocol;
@@ -2161,24 +2166,31 @@ function registerWhoamiTool(server, ctx, helpers) {
2161
2166
  const { withErrorHandling } = helpers;
2162
2167
  server.registerTool("whoami", {
2163
2168
  title: "Show Current User",
2164
- description: "Show current user details: email, authentication method, and team memberships",
2169
+ description: "Show current user details: email, authentication method, team memberships, and the team's default product",
2165
2170
  inputSchema: strictSchema({}),
2166
2171
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
2167
2172
  }, withErrorHandling("whoami", async () => {
2173
+ const defaultProductTypePromise = ctx.client.user.getFeatures().then((features) => parseDefaultProductType(features.defaultProductType), () => {
2174
+ return;
2175
+ });
2168
2176
  if (ctx.principal.connector) {
2169
- const teams = await ctx.client.listTeams();
2177
+ const [teams, defaultProductType] = await Promise.all([
2178
+ ctx.client.listTeams(),
2179
+ defaultProductTypePromise
2180
+ ]);
2170
2181
  const activeTeam = teams.find((team) => team.id === ctx.principal.teamId);
2171
2182
  if (!activeTeam) {
2172
2183
  throw new Error("The active team is unavailable for this credential. Reconnect and choose a team.");
2173
2184
  }
2174
2185
  return jsonResult({
2175
2186
  authMethod: "Shared organization service account",
2176
- team: { name: activeTeam.name }
2187
+ team: { name: activeTeam.name, ...defaultProductType ? { defaultProductType } : {} }
2177
2188
  });
2178
2189
  }
2179
- const [user, teams] = await Promise.all([
2190
+ const [user, teams, defaultProductType] = await Promise.all([
2180
2191
  ctx.client.user.getCurrentUser(),
2181
- ctx.client.listTeams()
2192
+ ctx.client.listTeams(),
2193
+ defaultProductTypePromise
2182
2194
  ]);
2183
2195
  const activeTeam = teams.find((team) => team.id === ctx.principal.teamId);
2184
2196
  if (!activeTeam) {
@@ -2189,7 +2201,8 @@ function registerWhoamiTool(server, ctx, helpers) {
2189
2201
  authMethod: ctx.principal.actor ? `Kadoa Assistant (delegated via ${ctx.principal.actor.sub})` : "Kadoa access token",
2190
2202
  team: {
2191
2203
  name: activeTeam.name,
2192
- ...activeTeam.memberRole ? { memberRole: activeTeam.memberRole } : {}
2204
+ ...activeTeam.memberRole ? { memberRole: activeTeam.memberRole } : {},
2205
+ ...defaultProductType ? { defaultProductType } : {}
2193
2206
  },
2194
2207
  scopes: ctx.principal.scopes
2195
2208
  });
@@ -2789,7 +2802,7 @@ function summarizeWorkflowAuditEntry(entry) {
2789
2802
  function historyEmptyHint(includeSnapshots) {
2790
2803
  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
2804
  }
2792
- function registerWorkflowCoreTools(server, ctx, helpers) {
2805
+ function registerWorkflowCoreTools(server, ctx, helpers, defaultProductType) {
2793
2806
  const { withErrorHandling } = helpers;
2794
2807
  function resolveUrls(args) {
2795
2808
  const urls = args.urls ?? (args.url ? [args.url] : []);
@@ -2897,7 +2910,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
2897
2910
 
2898
2911
  ` + "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
2912
 
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.",
2913
+ ` + "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
2914
  inputSchema: strictSchema({
2902
2915
  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
2916
  ...extractionInputShape,
@@ -3050,7 +3063,7 @@ function registerWorkflowCoreTools(server, ctx, helpers) {
3050
3063
  }
3051
3064
  server.registerTool("create_realtime_monitor", {
3052
3065
  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.
3066
+ 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
3067
 
3055
3068
  ` + "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
3069
  inputSchema: strictSchema({
@@ -3727,9 +3740,9 @@ var init_workflows = __esm(() => {
3727
3740
  function registerTools(server, ctx, capabilities) {
3728
3741
  const helpers = { withErrorHandling: createWithErrorHandling(ctx) };
3729
3742
  if (capabilities.scrape)
3730
- registerScrapeTools(server, ctx, helpers);
3743
+ registerScrapeTools(server, ctx, helpers, capabilities.defaultProductType);
3731
3744
  registerWhoamiTool(server, ctx, helpers);
3732
- registerWorkflowCoreTools(server, ctx, helpers);
3745
+ registerWorkflowCoreTools(server, ctx, helpers, capabilities.defaultProductType);
3733
3746
  registerAssistantTools(server, ctx, helpers);
3734
3747
  registerWorkflowHistoryTools(server, ctx, helpers);
3735
3748
  registerObservabilityTools(server, ctx, helpers);
@@ -4413,12 +4426,41 @@ var init_request_log = __esm(() => {
4413
4426
 
4414
4427
  // src/server.ts
4415
4428
  import { McpServer as McpServer2 } from "@modelcontextprotocol/server";
4429
+ function lifecycleInstruction2(defaultProductType) {
4430
+ 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.";
4431
+ }
4432
+ function routingInstructions2(defaultProductType) {
4433
+ if (defaultProductType === "realtime") {
4434
+ return [
4435
+ `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.`,
4436
+ "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."
4437
+ ];
4438
+ }
4439
+ return [
4440
+ "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.",
4441
+ "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."
4442
+ ];
4443
+ }
4416
4444
  async function createServer3(auth, options) {
4417
4445
  const ctx = {
4418
4446
  client: createKadoaClient(auth),
4419
4447
  principal: auth.principal,
4420
4448
  teamId: auth.principal.teamId
4421
4449
  };
4450
+ let capabilities = options?.capabilities;
4451
+ if (!capabilities) {
4452
+ try {
4453
+ const response = await ctx.client.user.getFeatures();
4454
+ capabilities = {
4455
+ scrape: response.features.scrape,
4456
+ defaultProductType: parseDefaultProductType(response.defaultProductType)
4457
+ };
4458
+ } catch (error) {
4459
+ const message = error instanceof Error ? error.message : "unknown error";
4460
+ console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
4461
+ capabilities = { scrape: false };
4462
+ }
4463
+ }
4422
4464
  const server = new McpServer2({ name: "kadoa", version: package_default.version }, {
4423
4465
  instructions: [
4424
4466
  "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,10 +4469,9 @@ async function createServer3(auth, options) {
4427
4469
  "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
4470
  "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
4471
  "",
4430
- "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.",
4472
+ lifecycleInstruction2(capabilities.defaultProductType),
4431
4473
  "",
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.",
4474
+ ...routingInstructions2(capabilities.defaultProductType),
4434
4475
  "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
4476
  "Use list_changes and get_change to retrieve detected diffs from realtime monitoring workflows.",
4436
4477
  "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.",
@@ -4444,17 +4485,6 @@ async function createServer3(auth, options) {
4444
4485
  ].join(`
4445
4486
  `)
4446
4487
  });
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
4488
  registerTools(server, ctx, capabilities);
4459
4489
  server.server.onerror = (error) => console.error("[MCP Error]", safeErrorSummary(error));
4460
4490
  return server;
@@ -4534,7 +4564,7 @@ async function requestNeedsCapabilityLookup(request) {
4534
4564
  return false;
4535
4565
  }
4536
4566
  }
4537
- return method === "tools/list" || method === "tools/call" && name === "scrape";
4567
+ return method === "initialize" || method === "server/discover" || method === "tools/list" || method === "tools/call" && name === "scrape";
4538
4568
  }
4539
4569
  function isClientCausedHandlerError(error) {
4540
4570
  if (error instanceof ProtocolError)
@@ -4874,12 +4904,41 @@ init_package();
4874
4904
  init_client();
4875
4905
  init_tools();
4876
4906
  import { McpServer } from "@modelcontextprotocol/server";
4907
+ function lifecycleInstruction(defaultProductType) {
4908
+ 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.";
4909
+ }
4910
+ function routingInstructions(defaultProductType) {
4911
+ if (defaultProductType === "realtime") {
4912
+ return [
4913
+ `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.`,
4914
+ "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."
4915
+ ];
4916
+ }
4917
+ return [
4918
+ "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.",
4919
+ "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."
4920
+ ];
4921
+ }
4877
4922
  async function createServer(auth, options) {
4878
4923
  const ctx = {
4879
4924
  client: createKadoaClient(auth),
4880
4925
  principal: auth.principal,
4881
4926
  teamId: auth.principal.teamId
4882
4927
  };
4928
+ let capabilities = options?.capabilities;
4929
+ if (!capabilities) {
4930
+ try {
4931
+ const response = await ctx.client.user.getFeatures();
4932
+ capabilities = {
4933
+ scrape: response.features.scrape,
4934
+ defaultProductType: parseDefaultProductType(response.defaultProductType)
4935
+ };
4936
+ } catch (error) {
4937
+ const message = error instanceof Error ? error.message : "unknown error";
4938
+ console.error(`[CAPABILITIES] Failed to resolve team capabilities; gated tools will be hidden: ${message}`);
4939
+ capabilities = { scrape: false };
4940
+ }
4941
+ }
4883
4942
  const server = new McpServer({ name: "kadoa", version: package_default.version }, {
4884
4943
  instructions: [
4885
4944
  "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,10 +4947,9 @@ async function createServer(auth, options) {
4888
4947
  "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
4948
  "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
4949
  "",
4891
- "Workflow lifecycle: create_workflow → get_workflow (check status) → fetch_data (get results). Workflows run asynchronously - never poll or sleep-wait.",
4950
+ lifecycleInstruction(capabilities.defaultProductType),
4892
4951
  "",
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.",
4952
+ ...routingInstructions(capabilities.defaultProductType),
4895
4953
  "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
4954
  "Use list_changes and get_change to retrieve detected diffs from realtime monitoring workflows.",
4897
4955
  "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.",
@@ -4905,17 +4963,6 @@ async function createServer(auth, options) {
4905
4963
  ].join(`
4906
4964
  `)
4907
4965
  });
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
4966
  registerTools(server, ctx, capabilities);
4920
4967
  server.server.onerror = (error) => console.error("[MCP Error]", safeErrorSummary(error));
4921
4968
  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.0",
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",