@sodiumhq/mcp-pm 0.1.0-beta.6353 → 0.1.0-beta.6355
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 +1 -0
- package/dist/http.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-C2ETa30c.mjs → src--vw5xenq.mjs} +112 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -168,6 +168,7 @@ Only enable write mode with an AI client you trust — it hands the client the a
|
|
|
168
168
|
- **`log_time_entry`** — record time after the fact, optionally against a client, task, or workflow step. "Log 2 hours on ACME for today — reviewing the draft accounts."
|
|
169
169
|
- **`add_task_note`** — capture a note against a specific task. Attributed to your API user, timestamped to now.
|
|
170
170
|
- **`add_client_note`** — capture a note against a client record. Same shape as `add_task_note` but scoped to the client.
|
|
171
|
+
- **`add_workflow_step_note`** — capture a note against one workflow step of a task, so it shows on that step in Sodium.
|
|
171
172
|
- **`update_client_custom_fields`** — set or clear custom field values on a client. Accepts a map of field codes to values, validates against the field's data type (Text, Number, Date, Boolean, Select, MultiSelect). Pass null to clear a field. Field codes are discoverable via `get_client_summary`.
|
|
172
173
|
- **`update_contact`** — update a contact's details: name, preferred name (used in email greetings), email, phone, mobile, date of birth, UTR, NI number, address. Requires the contact code (discoverable via `list_contacts`).
|
|
173
174
|
|
package/dist/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as buildServer } from "./src
|
|
2
|
+
import { t as buildServer } from "./src--vw5xenq.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { SUPPORTED_PROTOCOL_VERSIONS, createMcpHandler } from "@modelcontextprotocol/server";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as buildServer } from "./src
|
|
2
|
+
import { t as buildServer } from "./src--vw5xenq.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
@@ -1904,6 +1904,26 @@ const createTaskItemNote = (options) => (options.client ?? client).post({
|
|
|
1904
1904
|
}
|
|
1905
1905
|
});
|
|
1906
1906
|
/**
|
|
1907
|
+
* Create Note for Workflow Step
|
|
1908
|
+
*
|
|
1909
|
+
* Creates a new note for the specified workflow step.
|
|
1910
|
+
*/
|
|
1911
|
+
const createStepNote = (options) => (options.client ?? client).post({
|
|
1912
|
+
security: [{
|
|
1913
|
+
name: "x-api-key",
|
|
1914
|
+
type: "apiKey"
|
|
1915
|
+
}, {
|
|
1916
|
+
scheme: "bearer",
|
|
1917
|
+
type: "http"
|
|
1918
|
+
}],
|
|
1919
|
+
url: "/tenants/{tenant}/tasks/{taskCode}/groups/{groupNumber}/steps/{stepNumber}/notes",
|
|
1920
|
+
...options,
|
|
1921
|
+
headers: {
|
|
1922
|
+
"Content-Type": "application/json",
|
|
1923
|
+
...options.headers
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1926
|
+
/**
|
|
1907
1927
|
* Get Task Workflow Groups
|
|
1908
1928
|
*
|
|
1909
1929
|
* Retrieves comprehensive workflow progress information for a TaskItem.
|
|
@@ -2756,6 +2776,22 @@ var SodiumApiClient = class {
|
|
|
2756
2776
|
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, `add note to task ${taskCode}`);
|
|
2757
2777
|
return data;
|
|
2758
2778
|
}
|
|
2779
|
+
async createStepNote(taskCode, groupNumber, stepNumber, body) {
|
|
2780
|
+
const correlationId = randomUUID();
|
|
2781
|
+
const { data, error, response } = await createStepNote({
|
|
2782
|
+
path: {
|
|
2783
|
+
tenant: this.tenant,
|
|
2784
|
+
taskCode,
|
|
2785
|
+
groupNumber,
|
|
2786
|
+
stepNumber
|
|
2787
|
+
},
|
|
2788
|
+
body,
|
|
2789
|
+
headers: { "X-Correlation-Id": correlationId },
|
|
2790
|
+
client: this.http
|
|
2791
|
+
});
|
|
2792
|
+
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, `add note to step ${groupNumber}.${stepNumber} of task ${taskCode}`);
|
|
2793
|
+
return data;
|
|
2794
|
+
}
|
|
2759
2795
|
async createClientNote(clientCode, body) {
|
|
2760
2796
|
const correlationId = randomUUID();
|
|
2761
2797
|
const { data, error, response } = await createClientNoteForClient({
|
|
@@ -4231,7 +4267,9 @@ function format$3(input) {
|
|
|
4231
4267
|
const svcName = s.billableService?.name ?? "(unnamed)";
|
|
4232
4268
|
const freq = s.billingFrequency ? ` ${s.billingFrequency}` : "";
|
|
4233
4269
|
const price = s.effectivePrice !== void 0 ? ` — ${money(s.effectivePrice, practice)}${freq}` : freq ? ` —${freq}` : "";
|
|
4234
|
-
|
|
4270
|
+
const svcCode = s.code ? ` (client service code: ${s.code})` : "";
|
|
4271
|
+
const stage = s.stage?.name ? ` · stage: ${s.stage.name}${s.stage.code ? ` (${s.stage.code})` : ""}` : "";
|
|
4272
|
+
lines.push(`- ${svcName}${svcCode}${price}${stage}`);
|
|
4235
4273
|
}
|
|
4236
4274
|
lines.push("", "--- Tasks ---");
|
|
4237
4275
|
lines.push(`Overdue: ${overdueTasks.length}`);
|
|
@@ -4442,6 +4480,9 @@ function format$1(s, practice) {
|
|
|
4442
4480
|
lines.push("", "--- Applicable Client Types ---");
|
|
4443
4481
|
if (!s.clientTypes || s.clientTypes.length === 0) lines.push("All client types (no restriction configured).");
|
|
4444
4482
|
else for (const ct of s.clientTypes) lines.push(`- ${ct}`);
|
|
4483
|
+
lines.push("", `--- Stages (${s.stages?.length ?? 0}) ---`);
|
|
4484
|
+
if (!s.stages || s.stages.length === 0) lines.push("No stages configured.");
|
|
4485
|
+
else for (const st of s.stages) lines.push(`- ${st.name ?? "(no name)"} (${st.code ?? "(no code)"})`);
|
|
4445
4486
|
lines.push("", `--- HMRC Agent Authorisations (${s.agentAuthorisations?.length ?? 0}) ---`);
|
|
4446
4487
|
if (!s.agentAuthorisations || s.agentAuthorisations.length === 0) lines.push("None configured.");
|
|
4447
4488
|
else for (const a of s.agentAuthorisations) lines.push(`- ${a}`);
|
|
@@ -4560,11 +4601,12 @@ function format(input) {
|
|
|
4560
4601
|
const doneSteps = task.workflowStepsComplete ?? sumBy(workflowGroups, (g) => g.completedSteps ?? 0);
|
|
4561
4602
|
lines.push("", `--- Workflow progress (${doneSteps}/${totalSteps} steps complete) ---`);
|
|
4562
4603
|
for (const group of workflowGroups) {
|
|
4563
|
-
const gName = group.groupName ??
|
|
4604
|
+
const gName = group.groupName ?? "(unnamed)";
|
|
4605
|
+
const gNumber = group.groupNumber ?? "?";
|
|
4564
4606
|
const gTotal = group.totalSteps ?? 0;
|
|
4565
4607
|
const gDone = group.completedSteps ?? 0;
|
|
4566
4608
|
const deadline = group.groupDeadline ? ` — deadline ${group.groupDeadline}` : "";
|
|
4567
|
-
lines.push(`Group: ${gName} (${gDone}/${gTotal})${deadline}`);
|
|
4609
|
+
lines.push(`Group ${gNumber}: ${gName} (${gDone}/${gTotal})${deadline}`);
|
|
4568
4610
|
for (const step of group.steps ?? []) lines.push(` ${formatStep$4(step)}`);
|
|
4569
4611
|
}
|
|
4570
4612
|
}
|
|
@@ -5155,6 +5197,38 @@ async function handleAddTaskNote(api, args) {
|
|
|
5155
5197
|
}
|
|
5156
5198
|
}
|
|
5157
5199
|
//#endregion
|
|
5200
|
+
//#region ../mcp-core/src/tools/add-workflow-step-note.ts
|
|
5201
|
+
const AddWorkflowStepNoteInputSchema = {
|
|
5202
|
+
taskCode: z.string().min(1, "Task code is required").describe("The task that holds the workflow. Usually discovered via list_tasks or get_task_context."),
|
|
5203
|
+
groupNumber: z.number().int().min(1).describe("The workflow group number the step sits in (1-based). Shown as 'Group N' in get_task_context's workflow section."),
|
|
5204
|
+
stepNumber: z.number().int().min(1).describe("The step number within that group (1-based). Shown as 'Step N' under each group in get_task_context's workflow section."),
|
|
5205
|
+
text: z.string().min(1, "Note text cannot be empty").describe("The note body. Keep it concise and factual — something the user can scan later. The user can edit or delete the note in the UI if the wording isn't right."),
|
|
5206
|
+
pinnedLevel: z.number().int().min(0).max(2).optional().describe("Pin level for the note. 0 = not pinned (default), 1 = pinned to the notes section, 2 = pinned to the top of the page. Only set above 0 if the user explicitly asks for the note to be pinned.")
|
|
5207
|
+
};
|
|
5208
|
+
async function handleAddWorkflowStepNote(api, args) {
|
|
5209
|
+
try {
|
|
5210
|
+
const authorCode = await api.getCurrentTenantUserCode();
|
|
5211
|
+
const note = await api.createStepNote(args.taskCode, args.groupNumber, args.stepNumber, {
|
|
5212
|
+
text: args.text,
|
|
5213
|
+
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5214
|
+
noteFromUserCode: authorCode,
|
|
5215
|
+
pinnedLevel: args.pinnedLevel ?? 0
|
|
5216
|
+
});
|
|
5217
|
+
return { content: [{
|
|
5218
|
+
type: "text",
|
|
5219
|
+
text: `Added note to step ${args.groupNumber}.${args.stepNumber} of task ${args.taskCode} (note code: ${note.code ?? "(no code)"}).`
|
|
5220
|
+
}] };
|
|
5221
|
+
} catch (error) {
|
|
5222
|
+
return {
|
|
5223
|
+
content: [{
|
|
5224
|
+
type: "text",
|
|
5225
|
+
text: error instanceof SodiumApiError ? `Error adding step note: ${error.message} (correlation: ${error.correlationId})` : `Error adding step note: ${error instanceof Error ? error.message : String(error)}`
|
|
5226
|
+
}],
|
|
5227
|
+
isError: true
|
|
5228
|
+
};
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
//#endregion
|
|
5158
5232
|
//#region ../mcp-core/src/tools/set-client-custom-fields.ts
|
|
5159
5233
|
const SetClientCustomFieldsInputSchema = {
|
|
5160
5234
|
clientCode: z.string().min(1, "Client code is required").describe("The client code (identifier). Usually discovered via list_clients or get_client_summary."),
|
|
@@ -9526,7 +9600,7 @@ async function buildServer(config) {
|
|
|
9526
9600
|
}, (args) => handleListClients(api, args));
|
|
9527
9601
|
registerTenantTool(server, api, "get_client_summary", {
|
|
9528
9602
|
title: "Get a full summary of one client",
|
|
9529
|
-
description: "Get a consolidated overview of a single client by code: identity (name, status, type, assignments), business details (company number, incorporation date, trading name, registered address, VAT status, UTR, PAYE ref), custom fields (all user-defined fields with current values, data types, and field codes — use these codes with update_client_custom_fields), key statutory dates (year-end, accounts due, VAT return due, confirmation statement due, etc. — upcoming first, then past), all contacts, active services with pricing, overdue task count + top 5, and tasks due in the next 7 days.
|
|
9603
|
+
description: "Get a consolidated overview of a single client by code: identity (name, status, type, assignments), business details (company number, incorporation date, trading name, registered address, VAT status, UTR, PAYE ref), custom fields (all user-defined fields with current values, data types, and field codes — use these codes with update_client_custom_fields), key statutory dates (year-end, accounts due, VAT return due, confirmation statement due, etc. — upcoming first, then past), all contacts, active services with pricing, overdue task count + top 5, and tasks due in the next 7 days. Takes a client code, as returned by list_clients or given by the user. Also answers 'when is ACME's year-end?' / 'is ACME VAT registered?' / 'what are ACME's custom fields?' in a single call. Tolerates partial failures — if one section can't be loaded, the rest is still returned with a note about what's missing.",
|
|
9530
9604
|
inputSchema: GetClientSummaryInputSchema,
|
|
9531
9605
|
annotations: {
|
|
9532
9606
|
readOnlyHint: true,
|
|
@@ -9556,7 +9630,7 @@ async function buildServer(config) {
|
|
|
9556
9630
|
}, (args) => handleListClientNotes(api, args));
|
|
9557
9631
|
registerTenantTool(server, api, "list_tasks", {
|
|
9558
9632
|
title: "List / filter tasks across the practice",
|
|
9559
|
-
description: "List tasks with any combination of filters: assigned user(s), unassigned, client(s), the primary client's client manager / partner (portfolio views: 'tasks across the clients Jane manages'), status, overdue flag, preset date range (Today / ThisWeek / Next7Days / CustomDateRange etc), category, team, billable service, workflow, workflow step type, current step name, recurring task template, free-text search, saved filter, include-projected, include-workflow-steps (Agenda Mode), sort, and pagination. Use for: 'my tasks' (
|
|
9633
|
+
description: "List tasks with any combination of filters: assigned user(s), unassigned, client(s), the primary client's client manager / partner (portfolio views: 'tasks across the clients Jane manages'), status, overdue flag, preset date range (Today / ThisWeek / Next7Days / CustomDateRange etc), category, team, billable service, workflow, workflow step type, current step name, recurring task template, free-text search, saved filter, include-projected, include-workflow-steps (Agenda Mode), sort, and pagination. Use for: 'my tasks' (user = the signed-in user's practice user code, which whoami shows), 'Jane's overdue tasks' (user + isOverdue), 'tasks for ACME due this week' (client + dateRange=Next7Days + dateBasis=DueDate), 'what is the team working on this month' (dateRange=ThisMonth, no user filter). Returns up to 50 tasks per page; each row shows due date, statutory due date (when set), client, billable service (name + code), assignee, status and workflow progress. Constraints that avoid API errors and keep queries efficient: (1) Querying NotStarted tasks requires one of — a dateRange, isOverdue=true, or restricting status to non-NotStarted values. (2) Narrow date ranges are cheaper: broad ranges (quarterly/yearly) are expensive, and Today / ThisWeek / Next7Days / ThisMonth answer most questions. (3) For 'oldest incomplete tasks', status=['InProgress','Blocked'] with sortBy=StartDate needs no date range; add isOverdue=true if 'oldest overdue' is meant. (4) For 'how many X?' questions, pass limit=0 to get just the total count without fetching any task data — much cheaper than fetching a full page and counting.",
|
|
9560
9634
|
inputSchema: ListTasksInputSchema,
|
|
9561
9635
|
annotations: {
|
|
9562
9636
|
readOnlyHint: true,
|
|
@@ -9566,7 +9640,7 @@ async function buildServer(config) {
|
|
|
9566
9640
|
}, (args) => handleListTasks(api, args));
|
|
9567
9641
|
registerTenantTool(server, api, "get_task_context", {
|
|
9568
9642
|
title: "Get full context for a single task",
|
|
9569
|
-
description: "Get a consolidated view of one task by code: identity (name, code, status, overdue flag, start/due/statutory dates, time estimate, assignee, category, billable service, recurring/workflow templates), description, task-level checklist, workflow progress (groups and steps with status, assignee, and completion info — only if the task has a workflow attached), notes (pinned first, then newest first), and the parent client.
|
|
9643
|
+
description: "Get a consolidated view of one task by code: identity (name, code, status, overdue flag, start/due/statutory dates, time estimate, assignee, category, billable service, recurring/workflow templates), description, task-level checklist, workflow progress (groups and steps with status, assignee, and completion info — only if the task has a workflow attached), notes (pinned first, then newest first), and the parent client. Takes a task code, as returned by list_tasks or given by the user. Tolerates partial failures — if notes or workflow steps can't be loaded, the task details are still returned with a note about what's missing. Only fails outright if the task itself can't be fetched (e.g. unknown code).",
|
|
9570
9644
|
inputSchema: GetTaskContextInputSchema,
|
|
9571
9645
|
annotations: {
|
|
9572
9646
|
readOnlyHint: true,
|
|
@@ -9596,7 +9670,7 @@ async function buildServer(config) {
|
|
|
9596
9670
|
}, (args) => handleListEngagements(api, args));
|
|
9597
9671
|
registerTenantTool(server, api, "get_proposal_summary", {
|
|
9598
9672
|
title: "Get full detail of one proposal",
|
|
9599
|
-
description: "Get a consolidated view of a single proposal by engagement code: identity (code, status, type, date), client, recipient, value breakdown (annual / quarterly / monthly / one-off incl. catch-up fees / total), the proposed services with pricing (and each service's catch-up fee share), acceptance record (if accepted), PDF availability (proposal + letter of engagement), email history, and the acceptance link.
|
|
9673
|
+
description: "Get a consolidated view of a single proposal by engagement code: identity (code, status, type, date), client, recipient, value breakdown (annual / quarterly / monthly / one-off incl. catch-up fees / total), the proposed services with pricing (and each service's catch-up fee share), acceptance record (if accepted), PDF availability (proposal + letter of engagement), email history, and the acceptance link. Requires a concrete engagement code as input. list_proposals returns the codes and filters by status, client and date, which covers descriptions such as 'the unsent proposal', 'the proposal for ACME', 'our most recent proposal' or 'the rejected one'. Returns identical data to get_engagement_letter_summary — both aliases back the same Engagement entity. Tolerates partial failures (email history or the practice's catch-up fee label may be missing with a note); only fails hard if the engagement itself can't be fetched.",
|
|
9600
9674
|
inputSchema: GetEngagementSummaryInputSchema,
|
|
9601
9675
|
annotations: {
|
|
9602
9676
|
readOnlyHint: true,
|
|
@@ -9606,7 +9680,7 @@ async function buildServer(config) {
|
|
|
9606
9680
|
}, (args) => handleGetEngagementSummary(api, args));
|
|
9607
9681
|
registerTenantTool(server, api, "get_engagement_letter_summary", {
|
|
9608
9682
|
title: "Get full detail of one letter of engagement",
|
|
9609
|
-
description: "Get a consolidated view of a single letter of engagement by code: identity (code, status, type, date), client, recipient, value breakdown (annual / quarterly / monthly / one-off incl. catch-up fees / total), services included with pricing (and each service's catch-up fee share), acceptance record (accepted date, whether accepted via portal or recorded manually), PDF availability (proposal + letter of engagement), email history, and the acceptance link.
|
|
9683
|
+
description: "Get a consolidated view of a single letter of engagement by code: identity (code, status, type, date), client, recipient, value breakdown (annual / quarterly / monthly / one-off incl. catch-up fees / total), services included with pricing (and each service's catch-up fee share), acceptance record (accepted date, whether accepted via portal or recorded manually), PDF availability (proposal + letter of engagement), email history, and the acceptance link. Requires a concrete engagement code as input. list_engagement_letters returns the codes and filters by status, search text and date, which covers descriptions such as 'ACME's letter of engagement', 'the most recent signed engagement' or 'the live engagement for Smith & Co'. Returns identical data to get_proposal_summary — both aliases back the same Engagement entity. Tolerates partial failures (email history or the practice's catch-up fee label may be missing with a note); only fails hard if the engagement itself can't be fetched.",
|
|
9610
9684
|
inputSchema: GetEngagementSummaryInputSchema,
|
|
9611
9685
|
annotations: {
|
|
9612
9686
|
readOnlyHint: true,
|
|
@@ -9626,7 +9700,7 @@ async function buildServer(config) {
|
|
|
9626
9700
|
}, (args) => handleListServices(api, args));
|
|
9627
9701
|
registerTenantTool(server, api, "get_service_details", {
|
|
9628
9702
|
title: "Get a single service's full configuration",
|
|
9629
|
-
description: "Get a consolidated view of one billable service by code: identity (name, code, category, status, VAT rate, accounting code, description, default manager, pricing mode), applicable client types (explicit list, or 'all client types' if unrestricted), HMRC agent authorisations, pricing options (one per billing frequency with base price + override counts), custom pricing tiers (only when pricingMode=CustomTiers), professional clearance request items, and pricing-factor presence (count + factor questions only — exact factor band values are intentionally not dumped; computed pricing per client lives in the proposal tools).
|
|
9703
|
+
description: "Get a consolidated view of one billable service by code: identity (name, code, category, status, VAT rate, accounting code, description, default manager, pricing mode), applicable client types (explicit list, or 'all client types' if unrestricted), HMRC agent authorisations, pricing options (one per billing frequency with base price + override counts), custom pricing tiers (only when pricingMode=CustomTiers), professional clearance request items, and pricing-factor presence (count + factor questions only — exact factor band values are intentionally not dumped; computed pricing per client lives in the proposal tools). Takes a service code, as returned by list_services or given by the user. Enables service-audit workflows like 'is Self Assessment correctly restricted to Individual clients?' and 'what clearance items do we request for new bookkeeping clients?'",
|
|
9630
9704
|
inputSchema: GetServiceDetailsInputSchema,
|
|
9631
9705
|
annotations: {
|
|
9632
9706
|
readOnlyHint: true,
|
|
@@ -9671,13 +9745,13 @@ async function buildServer(config) {
|
|
|
9671
9745
|
};
|
|
9672
9746
|
registerTenantTool(server, api, "get_service_delivery_report", {
|
|
9673
9747
|
title: "Service delivery turnaround report",
|
|
9674
|
-
description: "Are we delivering client services as quickly as we should? Cohort = tasks COMPLETED in the window. Summary KPIs (count, avg/median turnaround from planned start to completion, on-time %, statutory compliance %, currently-overdue snapshot) plus a breakdown grouped by Service (default), Client, AssignedUser, or Month. Answers 'how fast do we turn around VAT returns?', 'which clients' work runs late?', 'is our turnaround improving month on month?' (groupBy=Month over a long window).
|
|
9748
|
+
description: "Are we delivering client services as quickly as we should? Cohort = tasks COMPLETED in the window. Summary KPIs (count, avg/median turnaround from planned start to completion, on-time %, statutory compliance %, currently-overdue snapshot) plus a breakdown grouped by Service (default), Client, AssignedUser, or Month. Answers 'how fast do we turn around VAT returns?', 'which clients' work runs late?', 'is our turnaround improving month on month?' (groupBy=Month over a long window). It does not cover missed deadlines — a task still open past its deadline never completed, so it isn't in this cohort; get_deadline_compliance_report covers those. For per-step bottlenecks within one service, follow up with get_service_delivery_steps. Constraints: dateRange='CustomDateRange' requires both startDate and endDate; summary always covers the whole cohort even when breakdown rows are paged.",
|
|
9675
9749
|
inputSchema: GetServiceDeliveryReportInputSchema,
|
|
9676
9750
|
annotations: reportAnnotations
|
|
9677
9751
|
}, (args) => handleGetServiceDeliveryReport(api, args));
|
|
9678
9752
|
registerTenantTool(server, api, "get_service_delivery_steps", {
|
|
9679
9753
|
title: "Per-step bottlenecks for one service",
|
|
9680
|
-
description: "Where does the time go inside one billable service's workflow? For tasks of the given service completed in the window: average elapsed days per workflow step (measured from the previous step's completion, so queue/idle time counts), skip counts, chase counts, and each step flagged client-wait (waiting on the client: document requests, approvals, confirmations, data forms) vs internal — splitting 'we were slow' from 'the client was slow'.
|
|
9754
|
+
description: "Where does the time go inside one billable service's workflow? For tasks of the given service completed in the window: average elapsed days per workflow step (measured from the previous step's completion, so queue/idle time counts), skip counts, chase counts, and each step flagged client-wait (waiting on the client: document requests, approvals, confirmations, data forms) vs internal — splitting 'we were slow' from 'the client was slow'. Follows on from get_service_delivery_report when it flags a slow service, and answers 'why do accounts jobs take so long?' directly. Requires serviceCode (from list_services). Note: steps are compared by name across tasks, so a renamed workflow step appears as separate rows.",
|
|
9681
9755
|
inputSchema: GetServiceDeliveryStepsInputSchema,
|
|
9682
9756
|
annotations: reportAnnotations
|
|
9683
9757
|
}, (args) => handleGetServiceDeliverySteps(api, args));
|
|
@@ -9740,7 +9814,7 @@ async function buildServer(config) {
|
|
|
9740
9814
|
}, (args) => handleListWorkflows(api, args));
|
|
9741
9815
|
registerTenantTool(server, api, "get_workflow", {
|
|
9742
9816
|
title: "Get one workflow template's full structure",
|
|
9743
|
-
description: "Get a single workflow template by code: the ordered groups and steps with step types (email, document request, approval, client confirmation, data form, etc.), assignment rules, auto-execute flags, dependencies, time estimates, and conditions. Answers 'what are the steps in our VAT return workflow?' and 'which steps in this workflow wait on the client?'.
|
|
9817
|
+
description: "Get a single workflow template by code: the ordered groups and steps with step types (email, document request, approval, client confirmation, data form, etc.), assignment rules, auto-execute flags, dependencies, time estimates, and conditions. Answers 'what are the steps in our VAT return workflow?' and 'which steps in this workflow wait on the client?'. Requires a concrete workflow code, as listed by list_workflows. For how the workflow performs in practice (durations, bottlenecks), use get_workflow_step_analysis.",
|
|
9744
9818
|
inputSchema: GetWorkflowInputSchema,
|
|
9745
9819
|
annotations: lookupAnnotations
|
|
9746
9820
|
}, (args) => handleGetWorkflow(api, args));
|
|
@@ -9764,25 +9838,25 @@ async function buildServer(config) {
|
|
|
9764
9838
|
}, (args) => handleListServiceCategories(api, args));
|
|
9765
9839
|
registerTenantTool(server, api, "list_saved_task_filters", {
|
|
9766
9840
|
title: "List saved task views",
|
|
9767
|
-
description: "List the user's saved task views/filters, showing each view's code AND the criteria it encodes (statuses, date range, users, teams, clients, categories, overdue/unassigned flags). Use when the user references a saved view by name ('run my Weekly Review', 'my compliance filter') — resolve the code here, then pass it as list_tasks' savedFilter. The echoed criteria also let you answer 'what does my Weekly Review view actually show?' without running it.
|
|
9841
|
+
description: "List the user's saved task views/filters, showing each view's code AND the criteria it encodes (statuses, date range, users, teams, clients, categories, overdue/unassigned flags). Use when the user references a saved view by name ('run my Weekly Review', 'my compliance filter') — resolve the code here, then pass it as list_tasks' savedFilter. The echoed criteria also let you answer 'what does my Weekly Review view actually show?' without running it. menuOnly=true returns only the views pinned to the user's menu, which are the ones they use daily.",
|
|
9768
9842
|
inputSchema: ListSavedTaskFiltersInputSchema,
|
|
9769
9843
|
annotations: lookupAnnotations
|
|
9770
9844
|
}, (args) => handleListSavedTaskFilters(api, args));
|
|
9771
9845
|
registerTenantTool(server, api, "list_saved_client_filters", {
|
|
9772
9846
|
title: "List saved client views",
|
|
9773
|
-
description: "List the user's saved client views/filters, showing each view's code AND the criteria it encodes (statuses, client types, managers, partners, services, teams). Use when the user references a saved view by name ('my VAT clients view') — resolve the code here, then pass it as list_clients' savedFilter.
|
|
9847
|
+
description: "List the user's saved client views/filters, showing each view's code AND the criteria it encodes (statuses, client types, managers, partners, services, teams). Use when the user references a saved view by name ('my VAT clients view') — resolve the code here, then pass it as list_clients' savedFilter. menuOnly=true returns only the views pinned to the user's menu.",
|
|
9774
9848
|
inputSchema: ListSavedClientFiltersInputSchema,
|
|
9775
9849
|
annotations: lookupAnnotations
|
|
9776
9850
|
}, (args) => handleListSavedClientFilters(api, args));
|
|
9777
9851
|
registerTenantTool(server, api, "search_companies_house", {
|
|
9778
9852
|
title: "Search Companies House",
|
|
9779
|
-
description: "Search the Companies House public register by company name (full or partial) or company number. Returns matches with number, status, type, incorporation date, and registered address — live data from the register, not limited to the practice's clients. Use for prospect due diligence ('look up Bristol Roofing'), finding a company number before get_companies_house_profile, or checking name availability.
|
|
9853
|
+
description: "Search the Companies House public register by company name (full or partial) or company number. Returns matches with number, status, type, incorporation date, and registered address — live data from the register, not limited to the practice's clients. Use for prospect due diligence ('look up Bristol Roofing'), finding a company number before get_companies_house_profile, or checking name availability. An existing client's company number is in get_client_summary's business details.",
|
|
9780
9854
|
inputSchema: SearchCompaniesHouseInputSchema,
|
|
9781
9855
|
annotations: lookupAnnotations
|
|
9782
9856
|
}, (args) => handleSearchCompaniesHouse(api, args));
|
|
9783
9857
|
registerTenantTool(server, api, "get_companies_house_profile", {
|
|
9784
9858
|
title: "Get a company's full Companies House profile",
|
|
9785
|
-
description: "Get the live Companies House record for one company number: legal status, incorporation date, registered office, SIC codes, accounts and confirmation-statement deadlines (with OVERDUE flags), last-filed accounts, charges/insolvency/liquidation flags, and current + resigned officers. Answers 'when are ACME's accounts due at Companies House?', 'who are the directors?', 'does this prospect have insolvency history?'.
|
|
9859
|
+
description: "Get the live Companies House record for one company number: legal status, incorporation date, registered office, SIC codes, accounts and confirmation-statement deadlines (with OVERDUE flags), last-filed accounts, charges/insolvency/liquidation flags, and current + resigned officers. Answers 'when are ACME's accounts due at Companies House?', 'who are the directors?', 'does this prospect have insolvency history?'. Requires a company number: search_companies_house finds one by name, and get_client_summary's business details holds an existing client's. Pass includeOfficers=false when only filing dates matter. Officers tolerate partial failure — the profile still returns if they can't be loaded.",
|
|
9786
9860
|
inputSchema: GetCompaniesHouseProfileInputSchema,
|
|
9787
9861
|
annotations: lookupAnnotations
|
|
9788
9862
|
}, (args) => handleGetCompaniesHouseProfile(api, args));
|
|
@@ -9800,7 +9874,7 @@ async function buildServer(config) {
|
|
|
9800
9874
|
}, (args) => handleListDataFormRequests(api, args));
|
|
9801
9875
|
registerTenantTool(server, api, "list_time_entries", {
|
|
9802
9876
|
title: "List / filter time entries",
|
|
9803
|
-
description: "List recorded time entries with filters: team member, client, task, preset date range (or CustomDateRange + fromDate/toDate), billable flag, billed flag, search, sort, pagination. Answers 'how much time have I logged this week?' (userCode = current user, dateRange=ThisWeek), 'time spent on ACME this month' (clientCode + dateRange=ThisMonth), 'what unbilled time do we have?' (isBillable=true, isBilled=false — the WIP question), 'biggest time entries on this job' (taskItemCode, sortBy=DurationMinutes, sortDesc=true). Each page also shows its summed duration.
|
|
9877
|
+
description: "List recorded time entries with filters: team member, client, task, preset date range (or CustomDateRange + fromDate/toDate), billable flag, billed flag, search, sort, pagination. Answers 'how much time have I logged this week?' (userCode = current user, dateRange=ThisWeek), 'time spent on ACME this month' (clientCode + dateRange=ThisMonth), 'what unbilled time do we have?' (isBillable=true, isBilled=false — the WIP question), 'biggest time entries on this job' (taskItemCode, sortBy=DurationMinutes, sortDesc=true). Each page also shows its summed duration. Unwindowed queries scan all history, so a narrow dateRange is much faster. For 'how many entries?' pass limit=0. get_service_time_report gives aggregate per-service/per-client totals over a period, summing the whole window in one call instead of paging entries.",
|
|
9804
9878
|
inputSchema: ListTimeEntriesInputSchema,
|
|
9805
9879
|
annotations: lookupAnnotations
|
|
9806
9880
|
}, (args) => handleListTimeEntries(api, args));
|
|
@@ -9824,7 +9898,7 @@ async function buildServer(config) {
|
|
|
9824
9898
|
}, (args) => handleListRecurringTasks(api, args));
|
|
9825
9899
|
registerTenantTool(server, api, "list_sent_emails", {
|
|
9826
9900
|
title: "List emails Sodium sent (delivery audit trail)",
|
|
9827
|
-
description: "List the emails Sodium sent on the practice's behalf — proposal/engagement emails, document-request chases, portal invitations, broadcasts — with delivery status (Queued/Processing/Sent/Failed/Cancelled), recipient, subject, date window, search, sort, pagination. THE tool for 'did the proposal email to ACME actually go out?', 'which emails failed this week?' (status=Failed + fromDate), 'what chases went to John?' (search on his address). This is the OUTBOUND SYSTEM audit trail only — for two-way email correspondence with a client (their replies, ad-hoc emails) use list_client_emails instead.
|
|
9901
|
+
description: "List the emails Sodium sent on the practice's behalf — proposal/engagement emails, document-request chases, portal invitations, broadcasts — with delivery status (Queued/Processing/Sent/Failed/Cancelled), recipient, subject, date window, search, sort, pagination. THE tool for 'did the proposal email to ACME actually go out?', 'which emails failed this week?' (status=Failed + fromDate), 'what chases went to John?' (search on his address). This is the OUTBOUND SYSTEM audit trail only — for two-way email correspondence with a client (their replies, ad-hoc emails) use list_client_emails instead. A fromDate/toDate window keeps results small; limit=0 returns a count only. Follow up with get_sent_email for full recipient/error detail.",
|
|
9828
9902
|
inputSchema: ListSentEmailsInputSchema,
|
|
9829
9903
|
annotations: lookupAnnotations
|
|
9830
9904
|
}, (args) => handleListSentEmails(api, args));
|
|
@@ -9890,7 +9964,7 @@ async function buildServer(config) {
|
|
|
9890
9964
|
}, (args) => handleListUnbilledTimeClients(api, args));
|
|
9891
9965
|
registerTenantTool(server, api, "get_engagement_pipeline_summary", {
|
|
9892
9966
|
title: "Proposal pipeline totals (counts + values by status)",
|
|
9893
|
-
description: "One-call aggregate of the engagement pipeline: counts and total values for Unsent / Sent / Viewed / Accepted / Rejected, plus the open pipeline (sent + viewed awaiting a decision). Answers 'what's our proposal pipeline worth?', 'how much did we win this quarter?' (dateRange=ThisQuarter, read the Accepted line), 'how much value is sitting unsigned?'. Omit the window for the all-time picture. Much cheaper than paging list_proposals and adding up
|
|
9967
|
+
description: "One-call aggregate of the engagement pipeline: counts and total values for Unsent / Sent / Viewed / Accepted / Rejected, plus the open pipeline (sent + viewed awaiting a decision). Answers 'what's our proposal pipeline worth?', 'how much did we win this quarter?' (dateRange=ThisQuarter, read the Accepted line), 'how much value is sitting unsigned?'. Omit the window for the all-time picture. Much cheaper than paging list_proposals and adding up, so it suits any totals question; list_proposals lists the individual engagements. Constraints: dateRange='CustomDateRange' requires dateFrom and dateTo.",
|
|
9894
9968
|
inputSchema: GetEngagementPipelineSummaryInputSchema,
|
|
9895
9969
|
annotations: lookupAnnotations
|
|
9896
9970
|
}, (args) => handleGetEngagementPipelineSummary(api, args));
|
|
@@ -9944,7 +10018,7 @@ async function buildServer(config) {
|
|
|
9944
10018
|
}, (args) => handleGetEmailBroadcast(api, args));
|
|
9945
10019
|
registerTenantTool(server, api, "get_client_email_thread", {
|
|
9946
10020
|
title: "Read one email conversation (synced mailbox)",
|
|
9947
|
-
description: "Drill into one email thread from the synced mailbox: every message in order with date, sender, read/attachment flags, and preview text, plus which clients and tasks the thread is linked to. Requires configCode AND conversationId
|
|
10021
|
+
description: "Drill into one email thread from the synced mailbox: every message in order with date, sender, read/attachment flags, and preview text, plus which clients and tasks the thread is linked to. Requires configCode AND conversationId, both shown per thread in list_client_emails output. Answers 'what did ACME actually say in that thread?', 'show me the whole conversation about the VAT surcharge'. Message previews are snippets, not complete bodies — full bodies and attachments are opened in Sodium.",
|
|
9948
10022
|
inputSchema: GetClientEmailThreadInputSchema,
|
|
9949
10023
|
annotations: lookupAnnotations
|
|
9950
10024
|
}, (args) => handleGetClientEmailThread(api, args));
|
|
@@ -9989,7 +10063,7 @@ async function buildServer(config) {
|
|
|
9989
10063
|
}, (args) => handleUpdateServiceCategory(api, args));
|
|
9990
10064
|
registerWriteTool(server, api, config.context, "apply_service_package", {
|
|
9991
10065
|
title: "Apply a service package to a client",
|
|
9992
|
-
description: "Put a client on one of the practice's bundled packages in a single call. The package definition decides everything: which services the client gets, at what frequency, and whether they are billed as one package price or service by service. Requires clientCode (list_clients) and packageCode (list_service_packages — check its contents and pricing mode there first so you can tell the user what they are agreeing to). Optional: startDate (defaults to today), status (defaults to Active; use 'Proposed' when quoting), and createOnboardingTasks (defaults to true; pass false when recording an arrangement that is already running, e.g. migrating or backdating). Use for 'put ACME on the Growth package', 'add the Startup bundle to Bristol Roofing from 1 April'.
|
|
10066
|
+
description: "Put a client on one of the practice's bundled packages in a single call. The package definition decides everything: which services the client gets, at what frequency, and whether they are billed as one package price or service by service. Requires clientCode (list_clients) and packageCode (list_service_packages — check its contents and pricing mode there first so you can tell the user what they are agreeing to). Optional: startDate (defaults to today), status (defaults to Active; use 'Proposed' when quoting), and createOnboardingTasks (defaults to true; pass false when recording an arrangement that is already running, e.g. migrating or backdating). Use for 'put ACME on the Growth package', 'add the Startup bundle to Bristol Roofing from 1 April'. Notes: (1) The API does not check whether the client already has this package, so calling twice applies it a second time; get_client_summary shows whether it is already there. (2) Unlike repeated add_client_service calls, only this tool links the result to the package, which is what makes package pricing and package removal work in the Sodium UI. (3) Auto-invoicing follows the practice's client-billing settings; it is not controllable per call. (4) Nothing about the package can be overridden per client — use add_client_service for a bespoke arrangement. Archived packages are rejected.",
|
|
9993
10067
|
inputSchema: ApplyServicePackageInputSchema,
|
|
9994
10068
|
annotations: {
|
|
9995
10069
|
readOnlyHint: false,
|
|
@@ -10011,7 +10085,7 @@ async function buildServer(config) {
|
|
|
10011
10085
|
}, (args) => handleUpdateClientServiceStage(api, args));
|
|
10012
10086
|
registerWriteTool(server, api, config.context, "create_document_request", {
|
|
10013
10087
|
title: "Draft a document request for a client",
|
|
10014
|
-
description: "Create a document request as a DRAFT — nothing is sent and the client is not notified. Requires clientCode and a title; optional client-facing description (write it as the client will read it), deadline, and a team member to notify on submission. Use for 'ask ACME for their year-end records', 'request the Jan–Mar bank statements from Greggs'.
|
|
10088
|
+
description: "Create a document request as a DRAFT — nothing is sent and the client is not notified. Requires clientCode and a title; optional client-facing description (write it as the client will read it), deadline, and a team member to notify on submission. Use for 'ask ACME for their year-end records', 'request the Jan–Mar bank statements from Greggs'. It is saved as a draft and not sent; the user reviews and sends it from the client's Documents tab in Sodium. Track it afterwards with list_document_requests (status=Draft).",
|
|
10015
10089
|
inputSchema: CreateDocumentRequestInputSchema,
|
|
10016
10090
|
annotations: {
|
|
10017
10091
|
readOnlyHint: false,
|
|
@@ -10033,7 +10107,7 @@ async function buildServer(config) {
|
|
|
10033
10107
|
}, (args) => handleSendDataForm(api, args));
|
|
10034
10108
|
registerWriteTool(server, api, config.context, "create_proposal", {
|
|
10035
10109
|
title: "Draft a proposal / letter of engagement",
|
|
10036
|
-
description: "Create an engagement in UNSENT (draft) state — the client is NOT emailed; sending is a deliberate separate action in the Sodium UI. Requires clientCode and date. type defaults to ProposalAndEngagementLetter ('EngagementLetter' for existing clients needing only the letter). clientBillableServiceCodes are the CLIENT'S service-subscription codes (get_client_summary's services section), not catalogue codes — to propose a service the client doesn't have yet, first add_client_service with status 'Proposed', then include its new code here. Recipient defaults to the client's main contact when omitted; only use an email from the client's contacts or given by the user. Use for 'draft a proposal for Bristol Roofing covering bookkeeping and VAT'.
|
|
10110
|
+
description: "Create an engagement in UNSENT (draft) state — the client is NOT emailed; sending is a deliberate separate action in the Sodium UI. Requires clientCode and date. type defaults to ProposalAndEngagementLetter ('EngagementLetter' for existing clients needing only the letter). clientBillableServiceCodes are the CLIENT'S service-subscription codes (get_client_summary's services section), not catalogue codes — to propose a service the client doesn't have yet, first add_client_service with status 'Proposed', then include its new code here. Recipient defaults to the client's main contact when omitted; only use an email from the client's contacts or given by the user. Use for 'draft a proposal for Bristol Roofing covering bookkeeping and VAT'. The result states the drafted value and that it has not been sent; full detail via get_proposal_summary.",
|
|
10037
10111
|
inputSchema: CreateProposalInputSchema,
|
|
10038
10112
|
annotations: {
|
|
10039
10113
|
readOnlyHint: false,
|
|
@@ -10044,7 +10118,7 @@ async function buildServer(config) {
|
|
|
10044
10118
|
}, (args) => handleCreateProposal(api, args));
|
|
10045
10119
|
registerWriteTool(server, api, config.context, "update_client_dates", {
|
|
10046
10120
|
title: "Set key/statutory dates on a client",
|
|
10047
|
-
description: "Set one or more of a client's key dates (year-end, VAT return due, PAYE/CIS filing due, pension re-enrolment...). Takes an array of { dateType, date } — only the types you pass change; pass date=null to clear one. Current values are in get_client_summary's key-dates section. Use for 'set ACME's year-end to 31 March', 'record the pension re-enrolment date'.
|
|
10121
|
+
description: "Set one or more of a client's key dates (year-end, VAT return due, PAYE/CIS filing due, pension re-enrolment...). Takes an array of { dateType, date } — only the types you pass change; pass date=null to clear one. Current values are in get_client_summary's key-dates section. Use for 'set ACME's year-end to 31 March', 'record the pension re-enrolment date'. For clients connected to Companies House, register-derived dates (accounts due, confirmation statement) are synced automatically and manual values may be overwritten; YearEnd, VAT, PAYE and pension dates are safe to set on connected clients.",
|
|
10048
10122
|
inputSchema: UpdateClientDatesInputSchema,
|
|
10049
10123
|
annotations: {
|
|
10050
10124
|
readOnlyHint: false,
|
|
@@ -10077,7 +10151,7 @@ async function buildServer(config) {
|
|
|
10077
10151
|
}, (args) => handleCreateSavedTaskFilter(api, args));
|
|
10078
10152
|
registerWriteTool(server, api, config.context, "update_workflow_step", {
|
|
10079
10153
|
title: "Update a workflow step (complete, skip, block, reassign)",
|
|
10080
|
-
description: "Update one workflow step on a task: set status (Completed / Skipped / InProgress / Blocked with a blockedReason) and/or reassign to a user or team. Identify the step by taskCode + groupNumber + stepNumber exactly as shown in get_task_context's workflow section
|
|
10154
|
+
description: "Update one workflow step on a task: set status (Completed / Skipped / InProgress / Blocked with a blockedReason) and/or reassign to a user or team. Identify the step by taskCode + groupNumber + stepNumber exactly as shown in get_task_context's workflow section, which also shows each step's current status. Use for 'mark the review step on TSK-123 as done', 'skip the client-approval step, they confirmed by phone', 'assign the bookkeeping steps to Jane'. Constraints: steps with dependencies may be rejected until prior steps complete — report the API's reason rather than retrying; auto-executing steps (emails, document requests) fire when their turn comes, so completing them manually may skip the automated action — warn the user if get_task_context showed the step as auto-executing. Step content/configuration is not editable here — that's done in the Sodium UI.",
|
|
10081
10155
|
inputSchema: UpdateWorkflowStepInputSchema,
|
|
10082
10156
|
annotations: {
|
|
10083
10157
|
readOnlyHint: false,
|
|
@@ -10088,7 +10162,7 @@ async function buildServer(config) {
|
|
|
10088
10162
|
}, (args) => handleUpdateWorkflowStep(api, args));
|
|
10089
10163
|
registerWriteTool(server, api, config.context, "create_task", {
|
|
10090
10164
|
title: "Create a new task",
|
|
10091
|
-
description: "Create a one-off task. Requires name, startDate, and dueDate (YYYY-MM-DD — 'due Friday' resolves against today
|
|
10165
|
+
description: "Create a one-off task. Requires name, startDate, and dueDate (YYYY-MM-DD — 'due Friday' resolves against today's date). Optional: description, status (defaults NotStarted), statutory due date, time estimate, client(s) (codes from list_clients), assignee (user code from the roster/list_users, or team code from list_teams), linked client-billable-service, category (list_task_categories), and a checklist (array of item texts). Use for 'create a task to chase ACME's rental schedule, due Friday', 'add a task for Jane to review the draft accounts'. Do NOT use for recurring schedules or workflow-driven tasks — those are set up in the Sodium UI. If the user gave a client or person by name, resolve codes first; ask rather than guess when multiple matches exist.",
|
|
10092
10166
|
inputSchema: CreateTaskInputSchema,
|
|
10093
10167
|
annotations: {
|
|
10094
10168
|
readOnlyHint: false,
|
|
@@ -10110,7 +10184,7 @@ async function buildServer(config) {
|
|
|
10110
10184
|
}, (args) => handleUpdateTask(api, args));
|
|
10111
10185
|
registerWriteTool(server, api, config.context, "log_time_entry", {
|
|
10112
10186
|
title: "Log a time entry",
|
|
10113
|
-
description: "Record time spent, after the fact. Requires entryDate (YYYY-MM-DD —
|
|
10187
|
+
description: "Record time spent, after the fact. Requires entryDate (YYYY-MM-DD — today's date applies when none is given) and durationMinutes ('2 hours' → 120). Optional: description (strongly recommended — it feeds billing narratives), client code, task code, workflow group/step numbers (from get_task_context), billable flag, hourly rate, and userCode when logging on someone else's behalf (defaults to the authenticated user). Use for 'log 2 hours on ACME for today — reviewing the draft accounts', 'add 45 minutes against the Greggs VAT task'. Billable and rate default from practice/team-member configuration — only pass them when the user is explicit. Some practices require a client or task link; if the API rejects the entry saying so, ask the user which client/task to attach.",
|
|
10114
10188
|
inputSchema: LogTimeEntryInputSchema,
|
|
10115
10189
|
annotations: {
|
|
10116
10190
|
readOnlyHint: false,
|
|
@@ -10130,6 +10204,17 @@ async function buildServer(config) {
|
|
|
10130
10204
|
openWorldHint: true
|
|
10131
10205
|
}
|
|
10132
10206
|
}, (args) => handleAddTaskNote(api, args));
|
|
10207
|
+
registerWriteTool(server, api, config.context, "add_workflow_step_note", {
|
|
10208
|
+
title: "Add a note to a workflow step",
|
|
10209
|
+
description: "Create a new note on one step of a task's workflow, so it shows on that step in Sodium. Additive — does not modify or delete existing notes. The note is attributed to the signed-in user and timestamped to 'now'. Use this when the user names a step: 'add a note on step 1 of the Greggs accounts task that we're waiting on the bank statements'. Needs the task code plus the group and step numbers, which get_task_context shows for each workflow step. For a note on the whole task use add_task_note. The user can edit or delete notes in the Sodium UI.",
|
|
10210
|
+
inputSchema: AddWorkflowStepNoteInputSchema,
|
|
10211
|
+
annotations: {
|
|
10212
|
+
readOnlyHint: false,
|
|
10213
|
+
destructiveHint: false,
|
|
10214
|
+
idempotentHint: false,
|
|
10215
|
+
openWorldHint: true
|
|
10216
|
+
}
|
|
10217
|
+
}, (args) => handleAddWorkflowStepNote(api, args));
|
|
10133
10218
|
registerWriteTool(server, api, config.context, "create_client", {
|
|
10134
10219
|
title: "Create a new client",
|
|
10135
10220
|
description: "Create a new client record in the practice. Requires name and type (PrivateLimitedCompany, Individual, SoleTrader, etc.). Optionally set status (Active/Prospect/Inactive/LostProspect), email, telephone, internal reference, and assign a manager/partner/associate/team. The client code is auto-generated. Use when the user says 'add a new client', 'create client ACME Ltd', 'onboard a new prospect'.",
|