@sodiumhq/mcp-pm 0.1.0-beta.2771 → 0.1.0-beta.2774
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/index.js +139 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -829,6 +829,26 @@ const listContacts = (options) => (options.client ?? client).get({
|
|
|
829
829
|
...options
|
|
830
830
|
});
|
|
831
831
|
/**
|
|
832
|
+
* Create Contact
|
|
833
|
+
*
|
|
834
|
+
* Creates a new Contact for the specified tenant.
|
|
835
|
+
*/
|
|
836
|
+
const createContact = (options) => (options.client ?? client).post({
|
|
837
|
+
security: [{
|
|
838
|
+
name: "x-api-key",
|
|
839
|
+
type: "apiKey"
|
|
840
|
+
}, {
|
|
841
|
+
scheme: "bearer",
|
|
842
|
+
type: "http"
|
|
843
|
+
}],
|
|
844
|
+
url: "/tenants/{tenant}/contacts",
|
|
845
|
+
...options,
|
|
846
|
+
headers: {
|
|
847
|
+
"Content-Type": "application/json",
|
|
848
|
+
...options.headers
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
/**
|
|
832
852
|
* Get Contact
|
|
833
853
|
*
|
|
834
854
|
* Gets a Contact for the specified tenant.
|
|
@@ -1576,6 +1596,16 @@ var SodiumApiClient = class {
|
|
|
1576
1596
|
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, `get contact ${code}`);
|
|
1577
1597
|
return data;
|
|
1578
1598
|
}
|
|
1599
|
+
async createContact(body) {
|
|
1600
|
+
const correlationId = randomUUID();
|
|
1601
|
+
const { data, error, response } = await createContact({
|
|
1602
|
+
path: { tenant: this.ctx.tenant },
|
|
1603
|
+
body,
|
|
1604
|
+
headers: { "X-Correlation-Id": correlationId }
|
|
1605
|
+
});
|
|
1606
|
+
if (error !== void 0 || !data) throw this.toError(response, error, correlationId, "create contact");
|
|
1607
|
+
return data;
|
|
1608
|
+
}
|
|
1579
1609
|
async updateContact(code, body) {
|
|
1580
1610
|
const correlationId = randomUUID();
|
|
1581
1611
|
const { data, error, response } = await updateContact({
|
|
@@ -1596,6 +1626,15 @@ var SodiumApiClient = class {
|
|
|
1596
1626
|
const obj = error;
|
|
1597
1627
|
const detail = obj.detail ?? obj.message;
|
|
1598
1628
|
if (typeof detail === "string") message = `${detail} (HTTP ${status}, ${operation})`;
|
|
1629
|
+
const errors = obj.errors;
|
|
1630
|
+
if (errors && typeof errors === "object" && !Array.isArray(errors)) {
|
|
1631
|
+
const fieldLines = [];
|
|
1632
|
+
for (const [field, msgs] of Object.entries(errors)) {
|
|
1633
|
+
const msgList = Array.isArray(msgs) ? msgs.join("; ") : String(msgs);
|
|
1634
|
+
fieldLines.push(` ${field}: ${msgList}`);
|
|
1635
|
+
}
|
|
1636
|
+
if (fieldLines.length > 0) message += `\nField errors:\n${fieldLines.join("\n")}`;
|
|
1637
|
+
}
|
|
1599
1638
|
} else if (typeof error === "string") message = error;
|
|
1600
1639
|
return new SodiumApiError(message, status, correlationId);
|
|
1601
1640
|
}
|
|
@@ -2971,6 +3010,85 @@ async function handleCreateClient(api, args) {
|
|
|
2971
3010
|
}
|
|
2972
3011
|
}
|
|
2973
3012
|
//#endregion
|
|
3013
|
+
//#region ../mcp-core/src/tools/create-contact.ts
|
|
3014
|
+
const CreateContactInputSchema = {
|
|
3015
|
+
lastName: z.string().min(1, "Last name is required").describe("The contact's last name (required)."),
|
|
3016
|
+
title: z.string().nullable().optional().describe("Title (e.g. Mr, Mrs, Dr)."),
|
|
3017
|
+
firstName: z.string().nullable().optional().describe("First name."),
|
|
3018
|
+
middleName: z.string().nullable().optional().describe("Middle name."),
|
|
3019
|
+
email: z.string().nullable().optional().describe("Email address."),
|
|
3020
|
+
phone: z.string().nullable().optional().describe("Landline phone number."),
|
|
3021
|
+
mobile: z.string().nullable().optional().describe("Mobile phone number."),
|
|
3022
|
+
dateOfBirth: z.string().nullable().optional().describe("Date of birth in ISO 8601 format (e.g. '1985-03-15')."),
|
|
3023
|
+
utr: z.string().nullable().optional().describe("Self Assessment UTR."),
|
|
3024
|
+
niNumber: z.string().nullable().optional().describe("National Insurance Number."),
|
|
3025
|
+
address: z.string().nullable().optional().describe("Contact address.")
|
|
3026
|
+
};
|
|
3027
|
+
async function handleCreateContact(api, args) {
|
|
3028
|
+
try {
|
|
3029
|
+
const created = await api.createContact(args);
|
|
3030
|
+
const lines = [`Created contact: ${[created.firstName, created.lastName].filter(Boolean).join(" ") || "(no name)"} (${created.code ?? "(no code)"})`];
|
|
3031
|
+
if (created.email) lines.push(`Email: ${created.email}`);
|
|
3032
|
+
if (created.phone) lines.push(`Phone: ${created.phone}`);
|
|
3033
|
+
if (created.mobile) lines.push(`Mobile: ${created.mobile}`);
|
|
3034
|
+
return { content: [{
|
|
3035
|
+
type: "text",
|
|
3036
|
+
text: lines.join("\n")
|
|
3037
|
+
}] };
|
|
3038
|
+
} catch (error) {
|
|
3039
|
+
return {
|
|
3040
|
+
content: [{
|
|
3041
|
+
type: "text",
|
|
3042
|
+
text: error instanceof SodiumApiError ? `Error creating contact: ${error.message} (correlation: ${error.correlationId})` : `Error creating contact: ${error instanceof Error ? error.message : String(error)}`
|
|
3043
|
+
}],
|
|
3044
|
+
isError: true
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
//#endregion
|
|
3049
|
+
//#region ../mcp-core/src/tools/get-contact.ts
|
|
3050
|
+
const GetContactInputSchema = { contactCode: z.string().min(1, "Contact code is required").describe("The contact code (identifier). Discoverable via list_contacts or the contacts section of get_client_summary.") };
|
|
3051
|
+
async function handleGetContact(api, args) {
|
|
3052
|
+
try {
|
|
3053
|
+
const c = await api.getContact(args.contactCode);
|
|
3054
|
+
const lines = [];
|
|
3055
|
+
const name = [
|
|
3056
|
+
c.title,
|
|
3057
|
+
c.firstName,
|
|
3058
|
+
c.middleName,
|
|
3059
|
+
c.lastName
|
|
3060
|
+
].filter(Boolean).join(" ") || "(no name)";
|
|
3061
|
+
lines.push(`Contact: ${name} (${c.code ?? args.contactCode})`);
|
|
3062
|
+
if (c.email) lines.push(`Email: ${c.email}`);
|
|
3063
|
+
if (c.phone) lines.push(`Phone: ${c.phone}`);
|
|
3064
|
+
if (c.mobile) lines.push(`Mobile: ${c.mobile}`);
|
|
3065
|
+
if (c.address) lines.push(`Address: ${c.address}`);
|
|
3066
|
+
if (c.dateOfBirth) lines.push(`Date of birth: ${c.dateOfBirth}`);
|
|
3067
|
+
if (c.nationality) lines.push(`Nationality: ${c.nationality}`);
|
|
3068
|
+
if (c.maritalStatus) lines.push(`Marital status: ${c.maritalStatus}`);
|
|
3069
|
+
if (c.utr) lines.push(`UTR: ${c.utr}`);
|
|
3070
|
+
if (c.niNumber) lines.push(`NI number: ${c.niNumber}`);
|
|
3071
|
+
if (c.personalCode) lines.push(`Companies House person code: ${c.personalCode}`);
|
|
3072
|
+
if (c.isDeceased) lines.push(`Deceased: yes${c.deceasedDate ? ` (${c.deceasedDate})` : ""}`);
|
|
3073
|
+
if (c.clientCount !== void 0) lines.push(`Linked to ${c.clientCount} client(s)`);
|
|
3074
|
+
if (c.client) lines.push(`Primary client: ${c.client.name} (${c.client.code})`);
|
|
3075
|
+
if (c.individualClient) lines.push(`Individual client record: ${c.individualClient.name} (${c.individualClient.code})`);
|
|
3076
|
+
if (c.portalUser) lines.push(`Portal user: ${c.portalUser.name} (${c.portalUser.code})`);
|
|
3077
|
+
return { content: [{
|
|
3078
|
+
type: "text",
|
|
3079
|
+
text: lines.join("\n")
|
|
3080
|
+
}] };
|
|
3081
|
+
} catch (error) {
|
|
3082
|
+
return {
|
|
3083
|
+
content: [{
|
|
3084
|
+
type: "text",
|
|
3085
|
+
text: error instanceof SodiumApiError ? `Error getting contact: ${error.message} (correlation: ${error.correlationId})` : `Error getting contact: ${error instanceof Error ? error.message : String(error)}`
|
|
3086
|
+
}],
|
|
3087
|
+
isError: true
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
//#endregion
|
|
2974
3092
|
//#region ../mcp-core/src/tools/list-client-notes.ts
|
|
2975
3093
|
const sortFieldEnum$1 = z.enum(["Date", "UpdatedDate"]);
|
|
2976
3094
|
const ListClientNotesInputSchema = {
|
|
@@ -3350,6 +3468,16 @@ async function buildServer(config) {
|
|
|
3350
3468
|
openWorldHint: true
|
|
3351
3469
|
}
|
|
3352
3470
|
}, (args) => handleListContacts(api, args));
|
|
3471
|
+
server.registerTool("get_contact", {
|
|
3472
|
+
title: "Get full details of a contact",
|
|
3473
|
+
description: "Get all fields for a single contact by code: name, title, email, phone, mobile, address, date of birth, nationality, marital status, UTR, NI number, Companies House person code, deceased status, linked clients, and portal user. Use after list_contacts identifies the contact of interest, or when the user asks for details about a specific contact. Also useful before update_contact to see current values.",
|
|
3474
|
+
inputSchema: GetContactInputSchema,
|
|
3475
|
+
annotations: {
|
|
3476
|
+
readOnlyHint: true,
|
|
3477
|
+
idempotentHint: true,
|
|
3478
|
+
openWorldHint: true
|
|
3479
|
+
}
|
|
3480
|
+
}, (args) => handleGetContact(api, args));
|
|
3353
3481
|
registerWriteTool(server, config.context, "add_task_note", {
|
|
3354
3482
|
title: "Add a note to a task",
|
|
3355
3483
|
description: "Create a new note on a task. Additive — does not modify or delete existing notes. The note is attributed to the authenticated API user (the current practice member) and timestamped to 'now'. Use this when the user asks you to capture something on a task: 'add a note on the Greggs year-end task that we're waiting on the rental schedule', 'log on the task that I called John today and got voicemail'. Notes can be pinned; only pin when the user explicitly asks for it. The user can always edit or delete notes in the Sodium UI if the wording isn't right.",
|
|
@@ -3405,6 +3533,17 @@ async function buildServer(config) {
|
|
|
3405
3533
|
openWorldHint: true
|
|
3406
3534
|
}
|
|
3407
3535
|
}, (args) => handleUpdateContact(api, args));
|
|
3536
|
+
registerWriteTool(server, config.context, "create_contact", {
|
|
3537
|
+
title: "Create a new contact",
|
|
3538
|
+
description: "Create a new contact record. Requires at least a last name. Optionally set title, first name, email, phone, mobile, date of birth, UTR, NI number, and address. The contact code is auto-generated. Use when the user says 'add a contact', 'create contact John Smith', 'add a new director for ACME'. Note: this creates the contact record only — to link it to a client, use the Sodium web UI.",
|
|
3539
|
+
inputSchema: CreateContactInputSchema,
|
|
3540
|
+
annotations: {
|
|
3541
|
+
readOnlyHint: false,
|
|
3542
|
+
destructiveHint: false,
|
|
3543
|
+
idempotentHint: false,
|
|
3544
|
+
openWorldHint: true
|
|
3545
|
+
}
|
|
3546
|
+
}, (args) => handleCreateContact(api, args));
|
|
3408
3547
|
return server;
|
|
3409
3548
|
}
|
|
3410
3549
|
//#endregion
|