@sodiumhq/mcp-pm 0.1.0-beta.6355 → 0.1.0-beta.6357

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/dist/http.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as buildServer } from "./src--vw5xenq.mjs";
2
+ import { t as buildServer } from "./src-BVx86BgG.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--vw5xenq.mjs";
2
+ import { t as buildServer } from "./src-BVx86BgG.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
5
5
  import { parseArgs } from "node:util";
@@ -4342,7 +4342,7 @@ const DEFAULT_CATCH_UP_FEE_LABEL = "Catch-up fee";
4342
4342
  function labelInSentence(label) {
4343
4343
  return /^[A-Z][A-Z]/.test(label) ? label : label.charAt(0).toLowerCase() + label.slice(1);
4344
4344
  }
4345
- const GetEngagementSummaryInputSchema = { code: z.string().min(1, "Engagement code is required").describe("REQUIRED: The engagement code (identifier, e.g. 'ENG-123'). This is the unique code of a specific engagement — NOT a description like 'the unsent proposal' or 'ACME's proposal'. If the user describes an engagement by attribute (status, client, date) rather than by code, you MUST call list_proposals or list_engagement_letters first (with the appropriate filters) to find the engagement's code, then pass that code here.") };
4345
+ const GetEngagementSummaryInputSchema = { code: z.string().min(1, "Engagement code is required").describe("REQUIRED: The engagement code (identifier, e.g. 'ENG-123'). This is the unique code of a specific engagement — NOT a description like 'the unsent proposal' or 'ACME's proposal'. list_proposals and list_engagement_letters return engagement codes and filter by status, client and date.") };
4346
4346
  async function handleGetEngagementSummary(api, { code }) {
4347
4347
  const [practice, [engagementResult, emailsResult, settingsResult]] = await Promise.all([api.getPracticeLocale(), Promise.allSettled([
4348
4348
  api.getEngagement(code),
@@ -4943,12 +4943,12 @@ const stepTypeEnum$1 = z.enum([
4943
4943
  "DocumentUpload"
4944
4944
  ]);
4945
4945
  const ListTasksInputSchema = {
4946
- user: z.array(z.string()).optional().describe("Filter by assigned user codes. For 'my tasks' use the current user's code from the startup context. For another team member's tasks, pass their code. Omit to see tasks across all users (useful for practice managers)."),
4946
+ user: z.array(z.string()).optional().describe("Filter by assigned user codes. For 'my tasks', this is the signed-in user's practice user code, which whoami shows. For another team member's tasks, pass their code. Omit to see tasks across all users (useful for practice managers)."),
4947
4947
  client: z.array(z.string()).optional().describe("Filter by client codes — tasks belonging to these specific clients only."),
4948
- status: z.array(statusEnum$14).optional().describe("Filter by task status. Typical: ['NotStarted', 'InProgress'] to exclude completed/skipped. Leave empty for all statuses. IMPORTANT: if the query includes NotStarted (the default for new tasks), you must ALSO provide one of: dateRange, isOverdue=true, or restrict status to non-NotStarted values only — otherwise the API rejects the call to prevent unbounded queries."),
4948
+ status: z.array(statusEnum$14).optional().describe("Filter by task status. Typical: ['NotStarted', 'InProgress'] to exclude completed/skipped. Leave empty for all statuses. If the query includes NotStarted (the default for new tasks), it also needs one of: dateRange, isOverdue=true, or restrict status to non-NotStarted values only — otherwise the API rejects the call to prevent unbounded queries."),
4949
4949
  isOverdue: z.boolean().optional().describe("Set true to return only overdue tasks (DueDate before today, not completed/skipped). When true, no date range is required. Useful for sidestepping the NotStarted + date-range requirement."),
4950
4950
  dateRange: dateRangeEnum$2.optional().describe("Preset date range. Use 'Today' for today's tasks, 'Next7Days' for 'due this week', 'Last30Days' for recent activity. If 'CustomDateRange', also provide startDate and/or endDate. REQUIRED when querying NotStarted tasks unless you pass isOverdue=true."),
4951
- startDate: z.string().optional().describe("Start of custom date range (YYYY-MM-DD). Used when dateRange='CustomDateRange'. Prefer specifying both startDate and endDate with a narrow window for performance — broad ranges strain the API. If startDate > endDate the API swaps them silently. Maximum allowed total range is 2 years."),
4951
+ startDate: z.string().optional().describe("Start of custom date range (YYYY-MM-DD). Used when dateRange='CustomDateRange'. Both startDate and endDate with a narrow window perform best — broad ranges strain the API. If startDate > endDate the API swaps them silently. Maximum allowed total range is 2 years."),
4952
4952
  endDate: z.string().optional().describe("End of custom date range (YYYY-MM-DD). Used when dateRange='CustomDateRange'. Pair with startDate to define a narrow window — avoid open-ended ranges."),
4953
4953
  dateBasis: dateBasisEnum$1.optional().describe("Which date field to apply the date range filter to. Use 'DueDate' for 'what's due when' questions; 'StartDate' (default) for 'what's been worked on'."),
4954
4954
  category: z.array(z.string()).optional().describe("Filter by task category codes (e.g. tax, audit, compliance categories)."),
@@ -4963,7 +4963,7 @@ const ListTasksInputSchema = {
4963
4963
  currentStep: z.array(z.string()).optional().describe("Filter to tasks whose CURRENT workflow step has one of these exact names (as shown in get_workflow). Use for 'everything sitting at Partner review'."),
4964
4964
  isUnassigned: z.boolean().optional().describe("Include tasks with no assignee. Alone: only unassigned tasks. Combined with `user`: unassigned OR assigned to those users. Use for 'what needs an owner'."),
4965
4965
  isAutomationDisabled: z.boolean().optional().describe("true = only tasks with automation switched off; false = only those with it on. Task previews are excluded either way. Rarely needed."),
4966
- search: z.string().min(3).optional().describe("Free-text search across task name, task code and primary client name (minimum 3 characters). Projected tasks are excluded when set. Prefer `client` when the client code is known."),
4966
+ search: z.string().min(3).optional().describe("Free-text search across task name, task code and primary client name (minimum 3 characters). Projected tasks are excluded when set. `client` is more precise when the client code is known."),
4967
4967
  savedFilter: z.string().optional().describe("Apply a user-saved filter by its code. Other filter parameters override fields from the saved filter."),
4968
4968
  includeProjected: z.boolean().optional().describe("Set true to include projected (virtual, not-yet-materialised) tasks in the results. Projected tasks are always NotStarted. Useful for 'what's coming up' queries."),
4969
4969
  includeWorkflowSteps: z.boolean().optional().describe("Set true for Agenda Mode: returns both tasks AND their workflow steps as individual rows. Each step row has its parent task's properties plus step-specific details. Useful for 'what's the next action on X' or when workflow step granularity matters."),
@@ -5376,7 +5376,7 @@ const CreateClientInputSchema = {
5376
5376
  email: z.string().nullable().optional().describe("Client email address."),
5377
5377
  telephone: z.string().nullable().optional().describe("Client telephone number."),
5378
5378
  internalReference: z.string().nullable().optional().describe("Internal reference number/code for the client."),
5379
- managerCode: z.string().nullable().optional().describe("Code of the user who will manage this client. Discoverable via list_users or the team roster in the startup context."),
5379
+ managerCode: z.string().nullable().optional().describe("Code of the user who will manage this client. Codes are listed by list_users and shown in the team roster."),
5380
5380
  partnerCode: z.string().nullable().optional().describe("Code of the partner user for this client."),
5381
5381
  associateCode: z.string().nullable().optional().describe("Code of the associate user for this client."),
5382
5382
  teamCode: z.string().nullable().optional().describe("Code of the team to assign to this client.")
@@ -5569,7 +5569,7 @@ function reportWindowFields(windowNoun) {
5569
5569
  const reportEntityFilters = {
5570
5570
  service: z.array(z.string()).optional().describe("Restrict the cohort to these billable service code(s). Use for 'how are we doing on VAT returns?' — get codes from list_services."),
5571
5571
  client: z.array(z.string()).optional().describe("Restrict the cohort to these client code(s). Use for a single-client view — get codes from list_clients."),
5572
- user: z.array(z.string()).optional().describe("Restrict the cohort to tasks assigned to these user code(s). For 'my …' questions use the current user's code from the startup context."),
5572
+ user: z.array(z.string()).optional().describe("Restrict the cohort to tasks assigned to these user code(s). For 'my …' questions, this is the signed-in user's practice user code, which whoami shows."),
5573
5573
  team: z.array(z.string()).optional().describe("Restrict the cohort to tasks assigned to these team code(s)."),
5574
5574
  category: z.array(z.string()).optional().describe("Restrict the cohort to these task category code(s).")
5575
5575
  };
@@ -6487,7 +6487,7 @@ async function handleUpdateServiceCategory(api, args) {
6487
6487
  //#region ../mcp-core/src/tools/list-saved-task-filters.ts
6488
6488
  const sortByEnum$13 = z.enum(["Name", "UpdatedDate"]);
6489
6489
  const ListSavedTaskFiltersInputSchema = {
6490
- menuOnly: z.boolean().optional().describe("Only return filters the user has pinned to their menu. These are the views they use daily, so prefer menuOnly=true when guessing which saved view the user means."),
6490
+ menuOnly: z.boolean().optional().describe("Only return filters the user has pinned to their menu. These are the views they use daily."),
6491
6491
  sortBy: sortByEnum$13.optional().describe("Field to sort by. Defaults to Name. Use UpdatedDate + sortDesc=true for recently edited views."),
6492
6492
  sortDesc: z.boolean().optional().describe("Sort in descending order. Defaults to ascending."),
6493
6493
  limit: z.number().int().min(0).max(50).optional().describe("Maximum filters per page. Default 10, max 50. Pass 0 for count-only."),
@@ -6552,7 +6552,7 @@ async function handleListSavedTaskFilters(api, args) {
6552
6552
  const sortByEnum$12 = z.enum(["Name", "UpdatedDate"]);
6553
6553
  const ListSavedClientFiltersInputSchema = {
6554
6554
  search: z.string().optional().describe("Search across saved view name and description."),
6555
- menuOnly: z.boolean().optional().describe("Only return filters the user has pinned to their menu. Prefer menuOnly=true when guessing which saved view the user means."),
6555
+ menuOnly: z.boolean().optional().describe("Only return filters the user has pinned to their menu. These are the views they use daily."),
6556
6556
  sortBy: sortByEnum$12.optional().describe("Field to sort by. Defaults to Name. Use UpdatedDate + sortDesc=true for recently edited views."),
6557
6557
  sortDesc: z.boolean().optional().describe("Sort in descending order. Defaults to ascending."),
6558
6558
  limit: z.number().int().min(0).max(50).optional().describe("Maximum filters per page. Default 10, max 50. Pass 0 for count-only."),
@@ -6915,10 +6915,10 @@ const sortByEnum$9 = z.enum([
6915
6915
  "IsBillable"
6916
6916
  ]);
6917
6917
  const ListTimeEntriesInputSchema = {
6918
- userCode: z.string().optional().describe("Filter by team member code. For 'my time this week' use the current user's code from the startup context. Omit for practice-wide time."),
6918
+ userCode: z.string().optional().describe("Filter by team member code. For 'my time this week', this is the signed-in user's practice user code, which whoami shows. Omit for practice-wide time."),
6919
6919
  clientCode: z.string().optional().describe("Filter by linked client code — 'how much time have we spent on ACME?'."),
6920
6920
  taskItemCode: z.string().optional().describe("Filter by linked task code — 'time logged against the Greggs year-end task'."),
6921
- dateRange: dateRangeEnum$1.optional().describe("Preset date range for the entry window. Use 'Today' / 'ThisWeek' / 'ThisMonth' for recent-time questions; 'CustomDateRange' with fromDate + toDate for explicit windows. Prefer a narrow range — time queries without a window scan everything."),
6921
+ dateRange: dateRangeEnum$1.optional().describe("Preset date range for the entry window. Use 'Today' / 'ThisWeek' / 'ThisMonth' for recent-time questions; 'CustomDateRange' with fromDate + toDate for explicit windows. Narrow ranges are faster — time queries without a window scan everything."),
6922
6922
  fromDate: z.string().optional().describe("Window start (YYYY-MM-DD), inclusive. Use with dateRange='CustomDateRange'."),
6923
6923
  toDate: z.string().optional().describe("Window end (YYYY-MM-DD), inclusive. Use with dateRange='CustomDateRange'."),
6924
6924
  isBillable: z.boolean().optional().describe("Filter by billable flag. true for 'billable time only', false for internal/non-chargeable time."),
@@ -7320,13 +7320,13 @@ const CreateTaskInputSchema = {
7320
7320
  name: z.string().min(1).describe("The task name — short and action-oriented, e.g. 'Chase rental schedule for year-end'."),
7321
7321
  description: z.string().optional().describe("Longer description of what needs doing. Optional."),
7322
7322
  status: statusEnum$10.optional().describe("Initial status. Defaults to NotStarted — only override when the work is already underway (InProgress)."),
7323
- startDate: z.string().describe("When work should start (YYYY-MM-DD). For ad-hoc tasks, today is usually right — get today's date from the startup context."),
7323
+ startDate: z.string().describe("When work should start (YYYY-MM-DD). For ad-hoc tasks, today's date is usually right."),
7324
7324
  dueDate: z.string().describe("When the task is due (YYYY-MM-DD). Must be on or after startDate."),
7325
7325
  statutoryDueDate: z.string().optional().describe("The statutory deadline (YYYY-MM-DD), for compliance tasks with a legal filing date distinct from the internal due date."),
7326
7326
  timeEstimateMinutes: z.number().int().min(1).optional().describe("Estimated effort in whole minutes."),
7327
7327
  clientCodes: z.array(z.string()).optional().describe("Client code(s) the task is for. Get codes from list_clients. Omit for internal practice work."),
7328
7328
  primaryClientCode: z.string().optional().describe("Which of clientCodes is the primary client. Only needed when passing more than one client."),
7329
- assignedUserCode: z.string().optional().describe("User code to assign the task to. For 'create a task for me', use the current user's code from the startup context. Resolve names via the roster or list_users."),
7329
+ assignedUserCode: z.string().optional().describe("User code to assign the task to. For 'create a task for me', this is the signed-in user's practice user code, which whoami shows. Names resolve to codes via the roster or list_users."),
7330
7330
  assignedTeamCode: z.string().optional().describe("Team code to assign to instead of an individual. Get codes from list_teams. Don't pass both this and assignedUserCode unless the user asked for both."),
7331
7331
  clientBillableServiceCode: z.string().optional().describe("The client-billable-service code linking this task to a service the client subscribes to (visible in get_client_summary's services section)."),
7332
7332
  categoryCode: z.string().optional().describe("Task category code. Get codes from list_task_categories."),
@@ -7446,7 +7446,7 @@ async function handleUpdateTask(api, args) {
7446
7446
  //#endregion
7447
7447
  //#region ../mcp-core/src/tools/log-time-entry.ts
7448
7448
  const LogTimeEntryInputSchema = {
7449
- entryDate: z.string().describe("The day the work was done (YYYY-MM-DD). For 'log 2 hours on ACME' with no date given, use today from the startup context."),
7449
+ entryDate: z.string().describe("The day the work was done (YYYY-MM-DD). For 'log 2 hours on ACME' with no date given, today's date applies."),
7450
7450
  durationMinutes: z.number().int().min(1).describe("How long the work took, in whole minutes. Convert user phrasing: '2 hours' → 120, 'half an hour' → 30."),
7451
7451
  description: z.string().optional().describe("What the time was spent on. Strongly recommended — it's what appears on billing narratives."),
7452
7452
  userCode: z.string().optional().describe("Who did the work. Defaults to the authenticated user — only pass this when logging time on someone else's behalf."),
@@ -7516,7 +7516,7 @@ const sortByEnum$7 = z.enum([
7516
7516
  const ListSentEmailsInputSchema = {
7517
7517
  status: statusEnum$8.optional().describe("Filter by delivery status. 'Failed' answers 'which emails didn't get through?' — the most actionable query. 'Queued'/'Processing' show what's still going out."),
7518
7518
  search: z.string().optional().describe("Search in email subject and recipient email address — 'emails to john@acme.co.uk', 'the proposal email'."),
7519
- fromDate: z.string().optional().describe("Only emails created on or after this date (YYYY-MM-DD). Prefer setting a window — unbounded queries scan all history."),
7519
+ fromDate: z.string().optional().describe("Only emails created on or after this date (YYYY-MM-DD). A window keeps results small; unbounded queries scan all history."),
7520
7520
  toDate: z.string().optional().describe("Only emails created on or before this date (YYYY-MM-DD)."),
7521
7521
  metadataParam: z.array(z.string()).optional().describe("Filter by metadata stored with the email, each entry as 'key=value' (e.g. ['entityType=Proposal']). Only use when you know the metadata key from a previous result — otherwise omit."),
7522
7522
  sortBy: sortByEnum$7.optional().describe("Field to sort by. Defaults to CreatedDate — pair with sortDesc=true for newest first."),
@@ -7830,7 +7830,7 @@ const ListBillingLineItemsInputSchema = {
7830
7830
  clientCode: z.string().optional().describe("Filter to one client's billing lines — 'what are we about to bill ACME?'."),
7831
7831
  billableServiceCode: z.string().optional().describe("Filter by the billable service — 'what bookkeeping revenue is queued?'. Get codes from list_services."),
7832
7832
  clientBillableServiceCode: z.string().optional().describe("Filter by one client's specific service subscription (the code from get_client_summary's services section). Narrower than billableServiceCode."),
7833
- billingDateFrom: z.string().optional().describe("Only lines with billing date on or after this date (YYYY-MM-DD). Prefer a window for revenue questions."),
7833
+ billingDateFrom: z.string().optional().describe("Only lines with billing date on or after this date (YYYY-MM-DD). A window keeps revenue questions fast."),
7834
7834
  billingDateTo: z.string().optional().describe("Only lines with billing date on or before this date (YYYY-MM-DD)."),
7835
7835
  sortBy: sortByEnum$5.optional().describe("Field to sort by. Defaults to BillingDate. Use UnitPrice + sortDesc=true for the biggest lines first."),
7836
7836
  sortDesc: z.boolean().optional().describe("Sort in descending order. Defaults to ascending."),
@@ -7960,7 +7960,7 @@ const sortByEnum$4 = z.enum([
7960
7960
  "StepType"
7961
7961
  ]);
7962
7962
  const ListPendingWorkflowStepsInputSchema = {
7963
- assignedUserCode: z.string().optional().describe("Filter to steps assigned to this user. For 'what steps are waiting on me?' use the current user's code from the startup context."),
7963
+ assignedUserCode: z.string().optional().describe("Filter to steps assigned to this user. For 'what steps are waiting on me?', this is the signed-in user's practice user code, which whoami shows."),
7964
7964
  assignedTeamCode: z.string().optional().describe("Filter to steps assigned to this team (codes from list_teams)."),
7965
7965
  isUnassigned: z.boolean().optional().describe("true = only steps with no assigned user — 'what work is nobody picking up?'. Combines with assignedUserCode as OR (mine + unassigned)."),
7966
7966
  stepType: stepTypeEnum.optional().describe("Filter by step type. 'Standard' = internal work steps; 'DocumentRequest'/'DocumentApproval'/'ClientConfirmation'/'SendDataForm' = client-facing steps."),
@@ -9189,7 +9189,7 @@ async function handleSendDataForm(api, args) {
9189
9189
  const typeEnum = z.enum(["ProposalAndEngagementLetter", "EngagementLetter"]);
9190
9190
  const CreateProposalInputSchema = {
9191
9191
  clientCode: z.string().min(1).describe("The client the proposal is for. Get the code from list_clients."),
9192
- date: z.string().describe("The engagement date (YYYY-MM-DD) — usually today, from the startup context."),
9192
+ date: z.string().describe("The engagement date (YYYY-MM-DD) — usually today's date."),
9193
9193
  type: typeEnum.optional().describe("'ProposalAndEngagementLetter' (default) generates both documents; 'EngagementLetter' for existing clients who only need the letter."),
9194
9194
  recipientFirstName: z.string().optional().describe("Recipient's first name. Usually the client's main contact — check get_client_summary."),
9195
9195
  recipientLastName: z.string().optional().describe("Recipient's last name."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sodiumhq/mcp-pm",
3
- "version": "0.1.0-beta.6355",
3
+ "version": "0.1.0-beta.6357",
4
4
  "description": "Sodium Practice Management MCP server — lets AI assistants interact with your Sodium tenant",
5
5
  "type": "module",
6
6
  "bin": {