@doist/automations-mcp 1.0.0 → 1.1.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
@@ -70,7 +70,10 @@ An MCP client can point at the stdio build directly, with the same environment:
70
70
  semantic-release with the configuration in [`release.config.js`](./release.config.js). The version
71
71
  comes from the conventional-commit messages that touched this directory, so nothing is bumped by
72
72
  hand and the repository holds no version number of its own. Releases go to the `latest` dist tag:
73
- the consumer is the hosted server, which pins an exact version and lets Renovate bump it.
73
+ the consumer is the hosted server, which pins an exact version. After publishing, the workflow sends
74
+ an `automations-mcp-updated` dispatch to `Doist/todoist-ai-integrations`, whose update workflow
75
+ installs the version, runs its checks, commits and redeploys, so a release reaches `ai.todoist.net`
76
+ without waiting for a dependency PR.
74
77
 
75
78
  The workspace libraries the package uses are not published, so `npm run build` compiles them into
76
79
  `dist/` and only the packages under `dependencies` stay external. Because a release is scoped to
@@ -131,6 +131,81 @@ var WEBHOOK_SIGNATURE_TOLERANCE_SECONDS = 5 * 60;
131
131
  var WEBHOOK_SUBSCRIPTION_STATUSES = ["active", "paused", "error"];
132
132
  var PROVIDER_TYPES = ["direct", "pubsub", "app-level"];
133
133
 
134
+ // ../../packages/core/dist/esm/models.js
135
+ var MODEL_CATALOG = {
136
+ "gemini-2.5-flash-lite": {
137
+ provider: "gemini",
138
+ family: "2.5",
139
+ providerModelId: "gemini-2.5-flash-lite"
140
+ },
141
+ "gemini-2.5-flash": {
142
+ provider: "gemini",
143
+ family: "2.5",
144
+ providerModelId: "gemini-2.5-flash"
145
+ },
146
+ "gemini-3.1-pro": {
147
+ provider: "gemini",
148
+ family: "3",
149
+ providerModelId: "gemini-3.1-pro-preview"
150
+ },
151
+ "gemini-3.8-flash": {
152
+ provider: "gemini",
153
+ family: "3",
154
+ providerModelId: "gemini-3.8-flash"
155
+ },
156
+ "claude-opus-4-6": {
157
+ provider: "anthropic",
158
+ family: "4.6",
159
+ providerModelId: "claude-opus-4-6"
160
+ },
161
+ "claude-sonnet-5": {
162
+ provider: "anthropic",
163
+ family: "5",
164
+ providerModelId: "claude-sonnet-5"
165
+ },
166
+ "claude-sonnet-4-6": {
167
+ provider: "anthropic",
168
+ family: "4.6",
169
+ providerModelId: "claude-sonnet-4-6"
170
+ },
171
+ "claude-haiku-4-5": {
172
+ provider: "anthropic",
173
+ family: "4.5",
174
+ providerModelId: "claude-haiku-4-5"
175
+ },
176
+ "deepseek-v4-flash": {
177
+ provider: "openrouter",
178
+ family: "deepseek",
179
+ providerModelId: "deepseek/deepseek-v4-flash-0731"
180
+ },
181
+ "deepseek-v4-pro": {
182
+ provider: "openrouter",
183
+ family: "deepseek",
184
+ providerModelId: "deepseek/deepseek-v4-pro"
185
+ },
186
+ "mimo-v2.5": {
187
+ provider: "openrouter",
188
+ family: "mimo",
189
+ providerModelId: "xiaomi/mimo-v2.5"
190
+ },
191
+ "mimo-v2.5-pro": {
192
+ provider: "openrouter",
193
+ family: "mimo",
194
+ providerModelId: "xiaomi/mimo-v2.5-pro"
195
+ },
196
+ "glm-5.2": {
197
+ provider: "openrouter",
198
+ family: "glm",
199
+ providerModelId: "z-ai/glm-5.2"
200
+ }
201
+ };
202
+ var SUPPORTED_LLM_MODELS = Object.keys(MODEL_CATALOG);
203
+ var SUPPORTED_SEARCH_MODELS = SUPPORTED_LLM_MODELS.filter(supportsWebSearch);
204
+ function supportsWebSearch(modelId) {
205
+ const { provider } = MODEL_CATALOG[modelId];
206
+ return provider === "gemini" || provider === "anthropic";
207
+ }
208
+
134
209
  // ../../packages/core/dist/esm/schemas/admin.schema.js
135
210
  import { z } from "zod";
136
211
  var AdminAccessResponseSchema = z.object({
@@ -1181,21 +1256,16 @@ var baseStepSchema = z7.object({
1181
1256
  description: "Overrides the global execution policy (timeout and retries) for this step."
1182
1257
  })
1183
1258
  });
1184
- var SUPPORTED_LLM_MODELS = [
1185
- "gemini-2.5-flash-lite",
1186
- "gemini-2.5-flash",
1187
- "gemini-3.1-pro",
1188
- "claude-haiku-4-5",
1189
- "claude-sonnet-4-6"
1190
- ];
1191
- var DEFAULT_LLM_MODEL = "claude-haiku-4-5";
1259
+ var MODEL_TIERS = ["lite", "flash", "pro"];
1260
+ var SUPPORTED_MODEL_REFERENCES = [...MODEL_TIERS, ...SUPPORTED_LLM_MODELS];
1261
+ var modelReferenceSchema = z7.enum(SUPPORTED_MODEL_REFERENCES).meta({
1262
+ description: "A stable model tier (lite, flash, pro) or a supported literal model override."
1263
+ });
1192
1264
  var llmStepSchema = baseStepSchema.merge(z7.object({
1193
1265
  type: z7.literal("llm"),
1194
1266
  prompt: z7.string().meta({ description: "The prompt template to be sent to the LLM." }),
1195
1267
  outputSchema: stepOutputSchema,
1196
- model: z7.enum(SUPPORTED_LLM_MODELS).meta({
1197
- description: `The specific model to use. Supported models: ${SUPPORTED_LLM_MODELS.join(", ")}.`
1198
- }),
1268
+ model: modelReferenceSchema,
1199
1269
  tools: z7.record(z7.string(), z7.array(z7.string())).default({}).meta({
1200
1270
  description: 'A mapping from MCP server connector IDs to arrays of their tool names (e.g., {"todoist": ["find-tasks-by-date"], "linear": ["create-issue"]}).'
1201
1271
  })
@@ -1206,9 +1276,7 @@ var codegenStepSchema = baseStepSchema.merge(z7.object({
1206
1276
  description: "The goal or instruction for what the generated code should accomplish."
1207
1277
  }),
1208
1278
  outputSchema: stepOutputSchema,
1209
- model: z7.enum(SUPPORTED_LLM_MODELS).meta({
1210
- description: `The specific model to use for code generation. Supported models: ${SUPPORTED_LLM_MODELS.join(", ")}.`
1211
- }),
1279
+ model: modelReferenceSchema,
1212
1280
  tools: z7.record(z7.string(), z7.array(z7.string())).default({}).meta({
1213
1281
  description: 'A mapping from MCP server connector IDs to arrays of their tool names that will be available in the generated code (e.g., {"todoist": ["find-tasks", "update-tasks"]}).'
1214
1282
  }),
@@ -1245,8 +1313,8 @@ var searchStepSchema = baseStepSchema.merge(z7.object({
1245
1313
  description: "The search prompt to execute using web search."
1246
1314
  }),
1247
1315
  outputSchema: searchStepOutputSchema,
1248
- model: z7.enum(SUPPORTED_LLM_MODELS).optional().meta({
1249
- description: `The specific model to use for processing search results. Defaults to ${DEFAULT_LLM_MODEL}.`
1316
+ model: z7.enum([...MODEL_TIERS, ...SUPPORTED_SEARCH_MODELS]).optional().meta({
1317
+ description: "A stable tier (lite, flash, pro) or a supported search-enabled literal model override."
1250
1318
  })
1251
1319
  }));
1252
1320
  var delayStepOutputSchema = z7.object({
@@ -1554,8 +1622,8 @@ function validateManifestResultFrom(data, ctx) {
1554
1622
  });
1555
1623
  return;
1556
1624
  }
1557
- const outputSchema19 = referencedStep.outputSchema;
1558
- if (!outputSchema19) {
1625
+ const outputSchema21 = referencedStep.outputSchema;
1626
+ if (!outputSchema21) {
1559
1627
  ctx.addIssue({
1560
1628
  code: z7.ZodIssueCode.custom,
1561
1629
  message: `resultFrom.stepId references step "${referencedStep.id}" without an outputSchema.`,
@@ -1564,7 +1632,7 @@ function validateManifestResultFrom(data, ctx) {
1564
1632
  return;
1565
1633
  }
1566
1634
  if (!data.resultFrom.path) {
1567
- if (!isPlainStringSchema(outputSchema19)) {
1635
+ if (!isPlainStringSchema(outputSchema21)) {
1568
1636
  ctx.addIssue({
1569
1637
  code: z7.ZodIssueCode.custom,
1570
1638
  message: "resultFrom.path may be omitted only when the referenced step outputSchema is a string.",
@@ -1574,7 +1642,7 @@ function validateManifestResultFrom(data, ctx) {
1574
1642
  return;
1575
1643
  }
1576
1644
  const propertyPath = data.resultFrom.path.split(".");
1577
- const resolvedSchema = resolvePropertySchemaInSchema(outputSchema19, propertyPath);
1645
+ const resolvedSchema = resolvePropertySchemaInSchema(outputSchema21, propertyPath);
1578
1646
  if (!resolvedSchema) {
1579
1647
  ctx.addIssue({
1580
1648
  code: z7.ZodIssueCode.custom,
@@ -1623,11 +1691,11 @@ function validateIfConditionLiteral({ condition, context, stepId }) {
1623
1691
  const referencedStepId = parts[1];
1624
1692
  if (!referencedStepId)
1625
1693
  return null;
1626
- const outputSchema19 = context.steps.get(referencedStepId);
1627
- if (!outputSchema19)
1694
+ const outputSchema21 = context.steps.get(referencedStepId);
1695
+ if (!outputSchema21)
1628
1696
  return null;
1629
1697
  const propertyPath = parts.slice(2);
1630
- const resolved = propertyPath.length === 0 ? outputSchema19 : resolvePropertySchemaInSchema(outputSchema19, propertyPath);
1698
+ const resolved = propertyPath.length === 0 ? outputSchema21 : resolvePropertySchemaInSchema(outputSchema21, propertyPath);
1631
1699
  if (!resolved)
1632
1700
  return null;
1633
1701
  return ifConditionLiteralError({ reference, literal, stepId, schema: resolved });
@@ -3142,17 +3210,18 @@ var AuthorizeUsageRequestSchema = z33.object({
3142
3210
  category: z33.string().min(1).max(CATEGORY_MAX_LENGTH)
3143
3211
  });
3144
3212
  var UsageBillingUnitsSchema = z33.number().int().nonnegative();
3213
+ var UsageBillingBalanceSchema = z33.number().int();
3145
3214
  var RecordUsageRefsSchema = z33.record(z33.string().max(40), z33.string().max(500)).refine((refs) => Object.keys(refs).length <= 50);
3146
3215
  var AuthorizeUsageResponseSchema = z33.discriminatedUnion("decision", [
3147
3216
  z33.object({
3148
3217
  decision: z33.literal("allowed"),
3149
3218
  reservation_id: z33.string().min(1),
3150
- available_units: UsageBillingUnitsSchema
3219
+ available_units: UsageBillingBalanceSchema
3151
3220
  }),
3152
3221
  z33.object({
3153
3222
  decision: z33.literal("denied"),
3154
3223
  reason: z33.enum(["insufficient_credit", "no_billing_account"]),
3155
- available_units: UsageBillingUnitsSchema
3224
+ available_units: UsageBillingBalanceSchema
3156
3225
  })
3157
3226
  ]);
3158
3227
  var RecordUsageRequestSchema = z33.object({
@@ -3169,7 +3238,7 @@ var RecordUsageRequestSchema = z33.object({
3169
3238
  var RecordUsageResponseSchema = z33.object({
3170
3239
  recorded: z33.boolean(),
3171
3240
  charged_units: UsageBillingUnitsSchema,
3172
- available_units: UsageBillingUnitsSchema
3241
+ available_units: UsageBillingBalanceSchema
3173
3242
  });
3174
3243
  var TOP_UP_USD_MIN_AMOUNT = 500;
3175
3244
  var TopUpCurrencySchema = z33.preprocess((value) => typeof value === "string" ? value.toLowerCase() : value, z33.literal("usd"));
@@ -3191,8 +3260,8 @@ var BillingPortalUrlResponseSchema = z33.object({
3191
3260
  billing_portal_url: z33.url()
3192
3261
  });
3193
3262
  var ReadStateResponseSchema = z33.object({
3194
- available_units: z33.number().int(),
3195
- available_amount: z33.number().int(),
3263
+ available_units: UsageBillingBalanceSchema,
3264
+ available_amount: UsageBillingBalanceSchema,
3196
3265
  currency: z33.string(),
3197
3266
  usage_allowed: z33.boolean(),
3198
3267
  low_balance: z33.boolean(),
@@ -5818,7 +5887,7 @@ import { McpServer } from "@modelcontextprotocol/server";
5818
5887
  // package.json
5819
5888
  var package_default = {
5820
5889
  name: "@doist/automations-mcp",
5821
- version: "1.0.0",
5890
+ version: "1.1.0",
5822
5891
  description: "MCP server and importable AI tools for Todoist Automations",
5823
5892
  type: "module",
5824
5893
  main: "./dist/index.js",
@@ -5875,7 +5944,7 @@ var package_default = {
5875
5944
  "@doist/automations-sdk": "*",
5876
5945
  "@modelcontextprotocol/client": "2.0.0",
5877
5946
  "@modelcontextprotocol/server": "2.0.0",
5878
- "@types/node": "24.13.4",
5947
+ "@types/node": "24.13.5",
5879
5948
  "conventional-changelog-conventionalcommits": "9.3.1",
5880
5949
  esbuild: "0.28.2",
5881
5950
  "gpt-tokenizer": "4.0.0",
@@ -6034,7 +6103,7 @@ function registerTool({
6034
6103
  transport
6035
6104
  }) {
6036
6105
  const execute = tool.execute;
6037
- const { input: inputSchema, output: outputSchema19 } = getToolSchemas(tool);
6106
+ const { input: inputSchema, output: outputSchema21 } = getToolSchemas(tool);
6038
6107
  const callback = async (args, ctx) => {
6039
6108
  try {
6040
6109
  const { textContent, structuredContent } = await execute(args, {
@@ -6061,7 +6130,7 @@ function registerTool({
6061
6130
  {
6062
6131
  description: tool.description,
6063
6132
  inputSchema,
6064
- ...outputSchema19 ? { outputSchema: outputSchema19 } : {},
6133
+ ...outputSchema21 ? { outputSchema: outputSchema21 } : {},
6065
6134
  annotations: getMcpAnnotations(tool)
6066
6135
  },
6067
6136
  callback
@@ -6163,6 +6232,9 @@ var automationSummarySchema = z60.object({
6163
6232
  visibility: z60.enum(AUTOMATION_VISIBILITIES),
6164
6233
  isOwner: z60.boolean(),
6165
6234
  workspaceId: z60.string().optional().describe("Absent for personal automations."),
6235
+ updatedBy: z60.string().optional().describe(
6236
+ "The Todoist user id of whoever last changed the automation, which in a workspace can be an admin rather than the creator. Absent until someone has changed it."
6237
+ ),
6166
6238
  disabledReason: z60.enum(AUTOMATION_DISABLED_REASONS).optional().describe(
6167
6239
  "Present when the system, not the user, disabled it; it cannot be enabled until fixed."
6168
6240
  ),
@@ -6391,6 +6463,7 @@ function summarizeAutomationForList(dto) {
6391
6463
  visibility: automation.visibility,
6392
6464
  isOwner: automation.isOwner,
6393
6465
  ...automation.workspaceId ? { workspaceId: automation.workspaceId } : {},
6466
+ ...automation.updatedBy ? { updatedBy: automation.updatedBy } : {},
6394
6467
  ...automation.disabledReason ? { disabledReason: automation.disabledReason } : {},
6395
6468
  triggers: triggers.flatMap((trigger) => summarizeTrigger(trigger) ?? []),
6396
6469
  connections: automation.connections.map((connection) => ({
@@ -6643,6 +6716,8 @@ var ToolNames = {
6643
6716
  // Mutation
6644
6717
  UPDATE_AUTOMATION: "update-automation",
6645
6718
  SET_AUTOMATION_SCHEDULE: "set-automation-schedule",
6719
+ SET_AUTOMATION_VISIBILITY: "set-automation-visibility",
6720
+ MOVE_AUTOMATION: "move-automation",
6646
6721
  TRIGGER_AUTOMATION: "trigger-automation",
6647
6722
  // Connection
6648
6723
  CONNECT_SERVICE: "connect-service",
@@ -6969,6 +7044,10 @@ import { z as z66 } from "zod";
6969
7044
  var workspaceIdParameter = z66.string().optional().describe(
6970
7045
  "Act on this Todoist workspace. Omit for the personal space. The two are separate: a workspace automation is not found in the personal space, and vice versa."
6971
7046
  );
7047
+ var requiredWorkspaceIdParameter = z66.string().describe("The Todoist workspace, as returned by list-workspaces.");
7048
+ function describeVisibility(visibility) {
7049
+ return visibility === "workspace" ? "visible to the workspace" : "private to its creator";
7050
+ }
6972
7051
  function describeScope(workspaceId) {
6973
7052
  return workspaceId === void 0 ? "personal" : `workspace ${workspaceId}`;
6974
7053
  }
@@ -7443,36 +7522,69 @@ var listWorkspaces = {
7443
7522
  }
7444
7523
  };
7445
7524
 
7446
- // src/tools/repair-connection.ts
7525
+ // src/tools/move-automation.ts
7447
7526
  import { z as z78 } from "zod";
7448
7527
  var parameters16 = {
7449
- connectionId: z78.string().describe(
7528
+ automationId: z78.string().describe(
7529
+ "The id of the automation to move, as returned by find-automations. It may be a personal automation or one in another workspace."
7530
+ ),
7531
+ workspaceId: z78.string().describe("The workspace to move it into, as returned by list-workspaces."),
7532
+ visibility: z78.enum(AUTOMATION_VISIBILITIES).optional().describe(
7533
+ 'How the automation is shared once moved. Defaults to "workspace", visible to every member; "private" keeps it to its creator.'
7534
+ )
7535
+ };
7536
+ var outputSchema15 = { automation: automationSummarySchema };
7537
+ var moveAutomation = {
7538
+ name: ToolNames.MOVE_AUTOMATION,
7539
+ description: "Moves an automation the user created into a workspace, from their personal space or from another workspace they can still use. It keeps running on the creator\u2019s own connections, and any unpublished edits move with it. The destination is always a workspace: nothing moves back to the personal space. Fails when the user did not create the automation, or when the workspace it is in now no longer includes them or Automations. Takes effect immediately with no confirmation of its own, so confirm intent with the user first.",
7540
+ parameters: parameters16,
7541
+ outputSchema: outputSchema15,
7542
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
7543
+ async execute({ automationId, workspaceId, visibility }, { api, signal }) {
7544
+ const dto = await api.workspaceAutomations.move(
7545
+ workspaceId,
7546
+ automationId,
7547
+ visibility === void 0 ? {} : { visibility },
7548
+ { signal }
7549
+ );
7550
+ const automation = summarizeAutomationForList(dto);
7551
+ return {
7552
+ textContent: `Moved "${automation.name}" to workspace ${workspaceId}; it is now ${describeVisibility(automation.visibility)}.`,
7553
+ structuredContent: { automation }
7554
+ };
7555
+ }
7556
+ };
7557
+
7558
+ // src/tools/repair-connection.ts
7559
+ import { z as z79 } from "zod";
7560
+ var parameters17 = {
7561
+ connectionId: z79.string().describe(
7450
7562
  "The connection to repair, as listed by get-connector or reported by check-connection."
7451
7563
  )
7452
7564
  };
7453
- var outputSchema15 = {
7454
- connectionId: z78.string().describe("The connection to pass to check-connection next."),
7455
- connectorId: z78.string(),
7456
- serviceName: z78.string(),
7457
- resumed: z78.boolean().describe(
7565
+ var outputSchema16 = {
7566
+ connectionId: z79.string().describe("The connection to pass to check-connection next."),
7567
+ connectorId: z79.string(),
7568
+ serviceName: z79.string(),
7569
+ resumed: z79.boolean().describe(
7458
7570
  "True when the existing pending setup was returned; false when a replacement was started."
7459
7571
  ),
7460
- replacedConnectionId: z78.string().optional().describe(
7572
+ replacedConnectionId: z79.string().optional().describe(
7461
7573
  "The broken connection the replacement stands in for. Present when resumed is false."
7462
7574
  ),
7463
- status: z78.enum(["pending", "authorized"]).describe(
7575
+ status: z79.enum(["pending", "authorized"]).describe(
7464
7576
  '"pending" until the user completes the setup; "authorized" when nothing was needed.'
7465
7577
  ),
7466
7578
  setup: connectionSetupSchema.optional().describe("What the user must complete. Absent when authorized."),
7467
- automations: z78.array(affectedAutomationSchema).optional().describe(
7579
+ automations: z79.array(affectedAutomationSchema).optional().describe(
7468
7580
  "Personal automations that move to the replacement once it is authorised. Present when resumed is false."
7469
7581
  )
7470
7582
  };
7471
7583
  var repairConnection = {
7472
7584
  name: ToolNames.REPAIR_CONNECTION,
7473
7585
  description: "Fixes a connection that is not authorised. A pending one gets its setup returned again; an expired, errored or stale one is replaced by a new connection that the personal automations using it move to once the user authorises it. Returns what the user must complete, never waits, and tells you which connectionId to pass to check-connection.",
7474
- parameters: parameters16,
7475
- outputSchema: outputSchema15,
7586
+ parameters: parameters17,
7587
+ outputSchema: outputSchema16,
7476
7588
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
7477
7589
  async execute({ connectionId }, { api, signal }) {
7478
7590
  const options = { signal };
@@ -7527,26 +7639,26 @@ var repairConnection = {
7527
7639
  };
7528
7640
 
7529
7641
  // src/tools/set-automation-schedule.ts
7530
- import { z as z79 } from "zod";
7531
- var parameters17 = {
7532
- automationId: z79.string().describe("The id of the automation, as returned by find-automations."),
7642
+ import { z as z80 } from "zod";
7643
+ var parameters18 = {
7644
+ automationId: z80.string().describe("The id of the automation, as returned by find-automations."),
7533
7645
  workspaceId: workspaceIdParameter,
7534
- cron: z79.string().optional().describe(
7646
+ cron: z80.string().optional().describe(
7535
7647
  'A five-part cron expression such as "0 9 * * 1-5". Requires timezone. Use this or interval, not both.'
7536
7648
  ),
7537
- timezone: z79.string().optional().describe(
7649
+ timezone: z80.string().optional().describe(
7538
7650
  'The IANA zone the cron expression is read in, such as "Europe/London". Only with cron.'
7539
7651
  ),
7540
- interval: z79.string().optional().describe(
7652
+ interval: z80.string().optional().describe(
7541
7653
  'How often to run, as a number and unit: "45m", "6h", "1d", "1w". Use this or cron, not both.'
7542
7654
  )
7543
7655
  };
7544
- var outputSchema16 = { automation: automationSummarySchema };
7656
+ var outputSchema17 = { automation: automationSummarySchema };
7545
7657
  var setAutomationSchedule = {
7546
7658
  name: ToolNames.SET_AUTOMATION_SCHEDULE,
7547
7659
  description: 'Changes when a schedule-triggered automation runs, as either a cron expression with a timezone or a fixed interval. Natural language such as "every weekday morning" is not accepted; translate it first. Takes effect immediately with no confirmation of its own, so confirm intent with the user first. Fails for automations that run on events or API calls.',
7548
- parameters: parameters17,
7549
- outputSchema: outputSchema16,
7660
+ parameters: parameters18,
7661
+ outputSchema: outputSchema17,
7550
7662
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
7551
7663
  async execute({ automationId, workspaceId, cron, timezone, interval }, { api, signal }) {
7552
7664
  const value = resolveScheduleInput(
@@ -7569,21 +7681,55 @@ var setAutomationSchedule = {
7569
7681
  }
7570
7682
  };
7571
7683
 
7684
+ // src/tools/set-automation-visibility.ts
7685
+ import { z as z81 } from "zod";
7686
+ var parameters19 = {
7687
+ automationId: z81.string().describe("The id of the automation, as returned by find-automations."),
7688
+ workspaceId: requiredWorkspaceIdParameter,
7689
+ visibility: z81.enum(AUTOMATION_VISIBILITIES).describe(
7690
+ '"workspace": every member can see and run it. "private": only its creator can see it, workspace admins included.'
7691
+ )
7692
+ };
7693
+ var outputSchema18 = { automation: automationSummarySchema };
7694
+ var setAutomationVisibility = {
7695
+ name: ToolNames.SET_AUTOMATION_VISIBILITY,
7696
+ description: "Shares a workspace automation with the whole workspace, or takes it back to private. Only the creator can change it, or a workspace admin while it is team-visible; once private it is out of every admin\u2019s reach until the creator shares it again. Takes effect immediately with no confirmation of its own, so confirm intent with the user first. Workspace automations only: a personal automation has no team to be visible to.",
7697
+ parameters: parameters19,
7698
+ outputSchema: outputSchema18,
7699
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
7700
+ async execute({ automationId, workspaceId, visibility }, { api, signal }) {
7701
+ const dto = await api.workspaceAutomations.updateVisibility(
7702
+ workspaceId,
7703
+ automationId,
7704
+ { visibility },
7705
+ { signal }
7706
+ );
7707
+ const automation = summarizeAutomationForList(dto);
7708
+ return {
7709
+ textContent: `"${automation.name}" is now ${describeVisibility(automation.visibility)}.`,
7710
+ structuredContent: { automation }
7711
+ };
7712
+ }
7713
+ };
7714
+
7572
7715
  // src/tools/start-conversation.ts
7573
- import { z as z80 } from "zod";
7574
- var parameters18 = {
7575
- message: z80.string().min(1).describe(
7716
+ import { z as z82 } from "zod";
7717
+ var parameters20 = {
7718
+ workspaceId: workspaceIdParameter.describe(
7719
+ "Author the automation in this Todoist workspace: the conversation, its draft and the published automation all belong there, and continue-conversation follows it automatically. Omit for the personal space."
7720
+ ),
7721
+ message: z82.string().min(1).describe(
7576
7722
  "What the user wants automated, in their words. Say whether the automation should be published or left as a draft; the agent otherwise asks."
7577
7723
  )
7578
7724
  };
7579
7725
  var startConversation = {
7580
7726
  name: ToolNames.START_CONVERSATION,
7581
- description: "Creates a conversation with the Automations agent and runs its first turn: the agent designs an automation from the message, asks questions, or asks for service connections. Blocks until the turn ends, which can take minutes; progress is reported meanwhile. Returns the conversationId to continue with and the outcome: awaiting_input (reply with continue-conversation), action_required (resolve pendingAction first) or published. Personal space only.",
7582
- parameters: parameters18,
7727
+ description: "Creates a conversation with the Automations agent and runs its first turn: the agent designs an automation from the message, asks questions, or asks for service connections. Blocks until the turn ends, which can take minutes; progress is reported meanwhile. Returns the conversationId to continue with and the outcome: awaiting_input (reply with continue-conversation), action_required (resolve pendingAction first) or published. Runs on the user\u2019s own connections in either space.",
7728
+ parameters: parameters20,
7583
7729
  outputSchema: turnResultSchema,
7584
7730
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
7585
- async execute({ message }, { api, transport, signal, reportProgress }) {
7586
- const conversation = await api.chat.createConversation({}, { signal });
7731
+ async execute({ workspaceId, message }, { api, transport, signal, reportProgress }) {
7732
+ const conversation = workspaceId === void 0 ? await api.chat.createConversation({}, { signal }) : await api.workspaceChat.createConversation(workspaceId, {}, { signal });
7587
7733
  const result = summarizeTurnResult(
7588
7734
  await runTurn({
7589
7735
  api,
@@ -7602,21 +7748,21 @@ var startConversation = {
7602
7748
  };
7603
7749
 
7604
7750
  // src/tools/trigger-automation.ts
7605
- import { z as z81 } from "zod";
7606
- var parameters19 = {
7607
- automationId: z81.string().describe("The id of the automation, as returned by find-automations."),
7751
+ import { z as z83 } from "zod";
7752
+ var parameters21 = {
7753
+ automationId: z83.string().describe("The id of the automation, as returned by find-automations."),
7608
7754
  workspaceId: workspaceIdParameter
7609
7755
  };
7610
- var outputSchema17 = {
7611
- automationId: z81.string(),
7612
- name: z81.string(),
7613
- accepted: z81.literal(true).describe("The backend accepted the run. It has not finished.")
7756
+ var outputSchema19 = {
7757
+ automationId: z83.string(),
7758
+ name: z83.string(),
7759
+ accepted: z83.literal(true).describe("The backend accepted the run. It has not finished.")
7614
7760
  };
7615
7761
  var triggerAutomation = {
7616
7762
  name: ToolNames.TRIGGER_AUTOMATION,
7617
7763
  description: "Starts a run of a schedule-triggered automation now, without waiting for its next scheduled time, and returns as soon as the backend accepts it. The run happens in the background; find-runs shows the outcome. Runs even when the automation is disabled. Cannot start automations that run on events or API calls. Confirm intent with the user first.",
7618
- parameters: parameters19,
7619
- outputSchema: outputSchema17,
7764
+ parameters: parameters21,
7765
+ outputSchema: outputSchema19,
7620
7766
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
7621
7767
  async execute({ automationId, workspaceId }, { api, signal }) {
7622
7768
  const options = { signal };
@@ -7641,22 +7787,22 @@ var triggerAutomation = {
7641
7787
  };
7642
7788
 
7643
7789
  // src/tools/update-automation.ts
7644
- import { z as z82 } from "zod";
7645
- var parameters20 = {
7646
- automationId: z82.string().describe("The id of the automation, as returned by find-automations."),
7790
+ import { z as z84 } from "zod";
7791
+ var parameters22 = {
7792
+ automationId: z84.string().describe("The id of the automation, as returned by find-automations."),
7647
7793
  workspaceId: workspaceIdParameter,
7648
- name: z82.string().min(1).optional().describe("A new name. Omit to keep the current one."),
7649
- description: z82.string().optional().describe("A new description. Omit to keep the current one."),
7650
- enabled: z82.boolean().optional().describe(
7794
+ name: z84.string().min(1).optional().describe("A new name. Omit to keep the current one."),
7795
+ description: z84.string().optional().describe("A new description. Omit to keep the current one."),
7796
+ enabled: z84.boolean().optional().describe(
7651
7797
  "Turn the automation on or off. Enabling fails while disabledReason is set: the system stopped it and the cause must be fixed first."
7652
7798
  )
7653
7799
  };
7654
- var outputSchema18 = { automation: automationSummarySchema };
7800
+ var outputSchema20 = { automation: automationSummarySchema };
7655
7801
  var updateAutomation = {
7656
7802
  name: ToolNames.UPDATE_AUTOMATION,
7657
7803
  description: "Renames, describes, enables or disables an automation. Any one field can change alone; the others keep their current values. Takes effect immediately with no confirmation of its own, so confirm intent with the user first. Does not change what the automation does; that needs a conversation.",
7658
- parameters: parameters20,
7659
- outputSchema: outputSchema18,
7804
+ parameters: parameters22,
7805
+ outputSchema: outputSchema20,
7660
7806
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
7661
7807
  async execute({ automationId, workspaceId, name, description, enabled }, context) {
7662
7808
  const client = createClient(automationId, workspaceId, context);
@@ -7722,6 +7868,8 @@ var toolRegistry = {
7722
7868
  // Mutation
7723
7869
  updateAutomation,
7724
7870
  setAutomationSchedule,
7871
+ setAutomationVisibility,
7872
+ moveAutomation,
7725
7873
  triggerAutomation,
7726
7874
  // Connection
7727
7875
  connectService,
@@ -7744,8 +7892,12 @@ You have access to a user's Todoist Automations through the tools listed.
7744
7892
 
7745
7893
  - Every reference is an opaque id taken from a find- or get- tool. There is no lookup by name and no URL parsing: list first, then act on the id. Connector ids are the one exception: they are stable slugs such as github or slack.
7746
7894
  - An automation belongs either to the user's personal space or to one Todoist workspace, and the two are separate. Pass workspaceId to reach workspace automations; omit it for personal ones.
7747
- - update-automation, set-automation-schedule, trigger-automation and disconnect-service act immediately: no preview, and no confirmation of their own. Read the target first (get-automation, or get-connector for a connection) so it is the right one, and confirm intent with the user before changing or running anything they did not explicitly ask for.
7895
+ - update-automation, set-automation-schedule, set-automation-visibility, move-automation, trigger-automation and disconnect-service act immediately: no preview, and no confirmation of their own. Read the target first (get-automation, or get-connector for a connection) so it is the right one, and confirm intent with the user before changing or running anything they did not explicitly ask for.
7748
7896
  - trigger-automation returns before the run finishes; find-runs shows the outcome.
7897
+ - A workspace automation is either visible to the whole workspace or private to its creator; isOwner says whether the user created it. Another member's automation is read-only for the user, but trigger-automation still works on it and the run executes on its creator's connections; find-runs shows who started each run as triggeredBy.
7898
+ - A workspace admin can update-automation and set-automation-visibility on another member's team-visible automation, but cannot reschedule it, change what it does (that needs its creator's draft or conversation) or reach a private one. updatedBy on an automation tells the creator's own change from an admin's.
7899
+ - move-automation puts an automation the user created into a workspace, from the personal space or another workspace, and never back out. Connections stay personal in every space: a moved or shared automation keeps running on its creator's own connections.
7900
+ - Authoring happens in the space the conversation was started in: pass workspaceId to start-conversation to author a workspace automation, and continue-conversation follows it automatically.
7749
7901
  - connect-service and repair-connection never wait. They return what the user must complete (an authorisation link, or instructions and a code): relay it verbatim, let the user finish, then call check-connection with the connectionId. Retrying reuses the pending setup rather than creating another connection.
7750
7902
  - disconnect-service refuses when enabled automations depend on the connection and returns them; disable them first, or pass force only after the user has agreed.
7751
7903
  - New automations are authored in a conversation with the Automations agent: start-conversation, then continue-conversation with the same conversationId. Each call runs one turn and blocks until it ends, which can take minutes. A turn ends in one of three outcomes: awaiting_input (reply with a message), action_required (resolve pendingAction: have the user choose or authorise the listed connections, or enable push notifications in a Todoist app, then continue-conversation with no message) or published (an automation exists; get-automation shows it). Say in the message whether the automation should be published or kept as a draft; the agent otherwise asks.
@@ -7777,4 +7929,4 @@ export {
7777
7929
  DEFAULT_BASE_URL,
7778
7930
  getMcpServer
7779
7931
  };
7780
- //# sourceMappingURL=chunk-WN2JU6T5.js.map
7932
+ //# sourceMappingURL=chunk-BU6WJ7QM.js.map