@sodiumhq/mcp-pm 0.1.0-beta.6257 → 0.1.0-beta.6351
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 +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-CMzdZk6e.mjs → src-CRE2Nlq7.mjs} +56 -34
- package/package.json +1 -1
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-CRE2Nlq7.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-CRE2Nlq7.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
@@ -2070,11 +2070,26 @@ const getTaskItem = (options) => (options.client ?? client).get({
|
|
|
2070
2070
|
...options
|
|
2071
2071
|
});
|
|
2072
2072
|
/**
|
|
2073
|
-
*
|
|
2073
|
+
* Patch TaskItem
|
|
2074
2074
|
*
|
|
2075
|
-
* Updates
|
|
2075
|
+
* Updates part of one task, following JSON Merge Patch. Send only the fields to change: a field left
|
|
2076
|
+
* out is not touched, so a quick action (moving the task on the calendar, a status button, a checklist
|
|
2077
|
+
* tick) never overwrites details it did not send, such as the description. A field sent as null is
|
|
2078
|
+
* cleared: description, statutory due date, time estimate, checklist, assignee, team, category, service
|
|
2079
|
+
* and primary client. The name, status, dates and times are required on a task, so sending one of those
|
|
2080
|
+
* as null is a 400.
|
|
2081
|
+
*
|
|
2082
|
+
* **Clients**: the same rules as a full update. The primary client always stays on the task, and a task
|
|
2083
|
+
* with clients but no primary gets its first client as primary. To remove every client, send the client
|
|
2084
|
+
* list and the primary client as null. Changing the primary client clears the task's service and
|
|
2085
|
+
* pipeline links (they belong to a client) unless a service code is sent.
|
|
2086
|
+
*
|
|
2087
|
+
* The change is saved through the same update as a full update, so dated workflow steps follow the
|
|
2088
|
+
* task when its dates move (unless MoveWorkflowStepDates is false), and colleagues see the change live.
|
|
2089
|
+
*
|
|
2090
|
+
* Only a saved task can be patched. A projected (upcoming) task must be materialised first.
|
|
2076
2091
|
*/
|
|
2077
|
-
const
|
|
2092
|
+
const patchTaskItem = (options) => (options.client ?? client).patch({
|
|
2078
2093
|
security: [{
|
|
2079
2094
|
name: "x-api-key",
|
|
2080
2095
|
type: "apiKey"
|
|
@@ -3756,9 +3771,9 @@ var SodiumApiClient = class {
|
|
|
3756
3771
|
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, "create task");
|
|
3757
3772
|
return data;
|
|
3758
3773
|
}
|
|
3759
|
-
async
|
|
3774
|
+
async patchTask(code, body) {
|
|
3760
3775
|
const correlationId = randomUUID();
|
|
3761
|
-
const { data, error, response } = await
|
|
3776
|
+
const { data, error, response } = await patchTaskItem({
|
|
3762
3777
|
path: {
|
|
3763
3778
|
tenant: this.tenant,
|
|
3764
3779
|
code
|
|
@@ -7299,26 +7314,23 @@ const UpdateTaskInputSchema = {
|
|
|
7299
7314
|
};
|
|
7300
7315
|
async function handleUpdateTask(api, args) {
|
|
7301
7316
|
try {
|
|
7302
|
-
const current = await api.getTask(args.taskCode);
|
|
7303
7317
|
const has = (key) => args[key] !== void 0;
|
|
7304
|
-
const body = {
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
};
|
|
7321
|
-
const updated = await api.updateTask(args.taskCode, body);
|
|
7318
|
+
const body = {};
|
|
7319
|
+
if (has("status")) body.status = args.status;
|
|
7320
|
+
if (has("name")) body.name = args.name;
|
|
7321
|
+
if (has("description")) body.description = args.description;
|
|
7322
|
+
if (has("startDate")) body.startDate = args.startDate;
|
|
7323
|
+
if (has("dueDate")) body.dueDate = args.dueDate;
|
|
7324
|
+
if (has("statutoryDueDate")) body.statutoryDueDate = args.statutoryDueDate;
|
|
7325
|
+
if (has("timeEstimateMinutes")) body.timeEstimateMinutes = args.timeEstimateMinutes;
|
|
7326
|
+
if (has("assignedUserCode")) body.assignedUserCode = args.assignedUserCode;
|
|
7327
|
+
if (has("assignedTeamCode")) body.assignedTeamCode = args.assignedTeamCode;
|
|
7328
|
+
if (has("categoryCode")) body.categoryCode = args.categoryCode;
|
|
7329
|
+
if (Object.keys(body).length === 0) return { content: [{
|
|
7330
|
+
type: "text",
|
|
7331
|
+
text: `Task ${args.taskCode} not changed: no fields were passed to update.`
|
|
7332
|
+
}] };
|
|
7333
|
+
const updated = await api.patchTask(args.taskCode, body);
|
|
7322
7334
|
const changes = [];
|
|
7323
7335
|
if (has("status")) changes.push(`status → ${updated.status}`);
|
|
7324
7336
|
if (has("name")) changes.push(`name → ${updated.name}`);
|
|
@@ -7332,7 +7344,7 @@ async function handleUpdateTask(api, args) {
|
|
|
7332
7344
|
if (has("timeEstimateMinutes")) changes.push(`estimate → ${updated.timeEstimateMinutes ?? "cleared"}m`);
|
|
7333
7345
|
return { content: [{
|
|
7334
7346
|
type: "text",
|
|
7335
|
-
text: [`Task updated: ${updated.name} (${updated.code})`,
|
|
7347
|
+
text: [`Task updated: ${updated.name} (${updated.code})`, `Changed: ${changes.join(", ")}`].join("\n")
|
|
7336
7348
|
}] };
|
|
7337
7349
|
} catch (error) {
|
|
7338
7350
|
return {
|
|
@@ -9364,15 +9376,25 @@ function captureClientInfo(server, api) {
|
|
|
9364
9376
|
version: info.version
|
|
9365
9377
|
});
|
|
9366
9378
|
}
|
|
9379
|
+
function withAnnotationTitle(config) {
|
|
9380
|
+
if (!config.title) return config;
|
|
9381
|
+
return {
|
|
9382
|
+
...config,
|
|
9383
|
+
annotations: {
|
|
9384
|
+
title: config.title,
|
|
9385
|
+
...config.annotations
|
|
9386
|
+
}
|
|
9387
|
+
};
|
|
9388
|
+
}
|
|
9367
9389
|
function registerTenantTool(server, api, name, config, cb) {
|
|
9368
9390
|
const inputSchema = {
|
|
9369
9391
|
...config.inputSchema ?? {},
|
|
9370
9392
|
practice: practiceField
|
|
9371
9393
|
};
|
|
9372
|
-
server.registerTool(name, {
|
|
9394
|
+
server.registerTool(name, withAnnotationTitle({
|
|
9373
9395
|
...config,
|
|
9374
9396
|
inputSchema
|
|
9375
|
-
}, async (args, extra) => {
|
|
9397
|
+
}), async (args, extra) => {
|
|
9376
9398
|
const started = Date.now();
|
|
9377
9399
|
captureClientInfo(server, api);
|
|
9378
9400
|
const { practice, ...rest } = args;
|
|
@@ -9452,7 +9474,7 @@ async function buildServer(config) {
|
|
|
9452
9474
|
openWorldHint: true
|
|
9453
9475
|
}
|
|
9454
9476
|
}, () => handleGetPracticeDetails(api));
|
|
9455
|
-
server.registerTool("whoami", {
|
|
9477
|
+
server.registerTool("whoami", withAnnotationTitle({
|
|
9456
9478
|
title: "Show current user and tenant info",
|
|
9457
9479
|
description: "Returns the identity of the authenticated user (name, email, code), the tenant/practice the call runs against (name, code, status), and the practice name. Use this when the user asks 'who am I?', 'which tenant am I connected to?', 'what account is this?', or when debugging authentication/permission issues. The optional 'practice' argument picks the practice section shown; without it the user's lone practice is used, and the identity section still answers when no practice can be resolved.",
|
|
9458
9480
|
inputSchema: { practice: practiceField },
|
|
@@ -9461,12 +9483,12 @@ async function buildServer(config) {
|
|
|
9461
9483
|
idempotentHint: true,
|
|
9462
9484
|
openWorldHint: true
|
|
9463
9485
|
}
|
|
9464
|
-
}, async (args) => {
|
|
9486
|
+
}), async (args) => {
|
|
9465
9487
|
captureClientInfo(server, api);
|
|
9466
9488
|
await resolveTenantForCall(api, args.practice);
|
|
9467
9489
|
return handleWhoami(api);
|
|
9468
9490
|
});
|
|
9469
|
-
server.registerTool("list_practices", {
|
|
9491
|
+
server.registerTool("list_practices", withAnnotationTitle({
|
|
9470
9492
|
title: "List the practices you can work in",
|
|
9471
9493
|
description: "List the practices (tenants) the signed-in user belongs to. Use this when the user belongs to more than one practice and you need the codes to pass in other tools' 'practice' argument, or when the user asks 'which practices can I access?'. Practices flagged 'unavailable' cannot be worked in.",
|
|
9472
9494
|
inputSchema: {},
|
|
@@ -9475,7 +9497,7 @@ async function buildServer(config) {
|
|
|
9475
9497
|
idempotentHint: true,
|
|
9476
9498
|
openWorldHint: true
|
|
9477
9499
|
}
|
|
9478
|
-
}, () => {
|
|
9500
|
+
}), () => {
|
|
9479
9501
|
captureClientInfo(server, api);
|
|
9480
9502
|
return handleListPractices(api);
|
|
9481
9503
|
});
|
|
@@ -9682,7 +9704,7 @@ async function buildServer(config) {
|
|
|
9682
9704
|
inputSchema: ListWorkflowOccurrencesInputSchema,
|
|
9683
9705
|
annotations: reportAnnotations
|
|
9684
9706
|
}, (args) => handleListWorkflowOccurrences(api, args));
|
|
9685
|
-
server.registerTool("get_usage_examples", {
|
|
9707
|
+
server.registerTool("get_usage_examples", withAnnotationTitle({
|
|
9686
9708
|
title: "Show example prompts for this integration",
|
|
9687
9709
|
description: "Returns a curated cookbook of example prompts this Sodium integration answers well, grouped by topic (daily-workflow, clients, tasks-and-deadlines, client-requests, time-tracking, reports, companies-house, proposals-and-engagements, making-changes). Use when the user asks 'what can you do?', 'what can I ask about my Sodium data?', 'give me some examples', or seems unsure how to get value from the integration. Also useful onboarding a new user: show the overview, then drill into the topic nearest their role. Static content — makes no API call.",
|
|
9688
9710
|
inputSchema: GetUsageExamplesInputSchema,
|
|
@@ -9691,7 +9713,7 @@ async function buildServer(config) {
|
|
|
9691
9713
|
idempotentHint: true,
|
|
9692
9714
|
openWorldHint: false
|
|
9693
9715
|
}
|
|
9694
|
-
}, (args) => handleGetUsageExamples(args));
|
|
9716
|
+
}), (args) => handleGetUsageExamples(args));
|
|
9695
9717
|
const lookupAnnotations = {
|
|
9696
9718
|
readOnlyHint: true,
|
|
9697
9719
|
idempotentHint: true,
|
|
@@ -10064,7 +10086,7 @@ async function buildServer(config) {
|
|
|
10064
10086
|
}, (args) => handleCreateTask(api, args));
|
|
10065
10087
|
registerWriteTool(server, api, config.context, "update_task", {
|
|
10066
10088
|
title: "Update a task (status, dates, assignment, details)",
|
|
10067
|
-
description: "Update fields on an existing task by code: status (mark Completed / InProgress / Blocked / Skipped), name, description, start/due/statutory dates, time estimate, assigned user or team, and category. Only the fields you pass change —
|
|
10089
|
+
description: "Update fields on an existing task by code: status (mark Completed / InProgress / Blocked / Skipped), name, description, start/due/statutory dates, time estimate, assigned user or team, and category. Only the fields you pass change — everything else on the task (clients, checklist, start and due times, service and recurring-task links) is left exactly as it is, so it's safe to pass just { taskCode, status: 'Completed' } for 'mark it done'. Pass null to clear a clearable field (description, statutory date, estimate, assignee, team, category). Use for 'mark TSK-123 complete', 'push the deadline to Friday', 'reassign it to Jane' (resolve her code from the roster), 'unassign this task' (assignedUserCode=null). Completing a task does NOT complete its workflow steps — if get_task_context showed open steps, tell the user they remain open. Cannot delete tasks — deletion isn't available through the MCP.",
|
|
10068
10090
|
inputSchema: UpdateTaskInputSchema,
|
|
10069
10091
|
annotations: {
|
|
10070
10092
|
readOnlyHint: false,
|