notifyme-csm-mcp 1.0.11 → 1.0.13
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 +91 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -410,7 +410,7 @@ const TOOLS = [
|
|
|
410
410
|
},
|
|
411
411
|
{
|
|
412
412
|
name: "get_funnel_entities",
|
|
413
|
-
description: "List the actual companies behind a Reports funnel stage count — e.g. which agencies were 'Approached' in
|
|
413
|
+
description: "List the actual companies behind a Reports funnel stage count — e.g. which agencies were 'Approached' or 'Replied' in a window. Stages: 'approached' (CSM email, Gmail thread, LinkedIn outreach, or log_outreach event — notes do NOT count), 'replied' (LinkedIn reply_received, a Gmail thread that became a conversation, or a move to a Replied column), 'meeting scheduled', 'meeting attended', or any pipeline column name. Supports channel filtering, per-channel grouping, and tag-based segment slicing.",
|
|
414
414
|
inputSchema: {
|
|
415
415
|
type: "object",
|
|
416
416
|
properties: {
|
|
@@ -434,8 +434,37 @@ const TOOLS = [
|
|
|
434
434
|
},
|
|
435
435
|
stage: {
|
|
436
436
|
type: "string",
|
|
437
|
-
description: "Funnel stage / pipeline column name (default: 'approached'). e.g. 'approached', 'meeting scheduled', 'meeting attended', 'qualified', 'won'.",
|
|
437
|
+
description: "Funnel stage / pipeline column name (default: 'approached'). e.g. 'approached', 'replied', 'meeting scheduled', 'meeting attended', 'qualified', 'won'.",
|
|
438
438
|
},
|
|
439
|
+
channel: {
|
|
440
|
+
type: "string",
|
|
441
|
+
enum: ["email", "linkedin", "call", "whatsapp", "other"],
|
|
442
|
+
description: "Only count touches on this channel (applies to 'approached' and 'replied'; call/whatsapp/other come from log_outreach events).",
|
|
443
|
+
},
|
|
444
|
+
groupByChannel: {
|
|
445
|
+
type: "boolean",
|
|
446
|
+
description: "Also return per-channel counts for the stage as `byChannel`. A company touched on two channels appears in both buckets.",
|
|
447
|
+
},
|
|
448
|
+
tags: {
|
|
449
|
+
type: "array",
|
|
450
|
+
items: { type: "string" },
|
|
451
|
+
description: "Slice by segment: only companies carrying ALL of these tags (e.g. [\"tier:enterprise\", \"vertical:beauty\"]).",
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: "get_funnel_rates",
|
|
458
|
+
description: "Conversion rates for a window + filters, from distinct companies per stage: reachRate (approached/total companies), interactionRate (replied/approached), bookingRate (meeting scheduled/replied), showUpRate (attended/scheduled). channel narrows approached+replied; tags slice every stage and the total. Rates are percentages, null when the denominator is 0.",
|
|
459
|
+
inputSchema: {
|
|
460
|
+
type: "object",
|
|
461
|
+
properties: {
|
|
462
|
+
entityType: { type: "string", enum: ["agency", "merchant", "both"], description: "Which entities (default: agency)." },
|
|
463
|
+
timeframe: { type: "string", enum: ["last7days", "last30days", "last90days", "mtd", "qtd", "ytd", "custom"], description: "Reporting window (default: last7days). Use custom with startDate/endDate." },
|
|
464
|
+
startDate: { type: "string", description: "YYYY-MM-DD; passing dates implies timeframe=custom (server-TZ)." },
|
|
465
|
+
endDate: { type: "string", description: "YYYY-MM-DD inclusive; passing dates implies timeframe=custom (server-TZ)." },
|
|
466
|
+
channel: { type: "string", enum: ["email", "linkedin", "call", "whatsapp", "other"], description: "Narrow approached+replied to one channel." },
|
|
467
|
+
tags: { type: "array", items: { type: "string" }, description: "Only companies carrying ALL of these tags." },
|
|
439
468
|
},
|
|
440
469
|
},
|
|
441
470
|
},
|
|
@@ -457,6 +486,32 @@ const TOOLS = [
|
|
|
457
486
|
required: ["agencyCompanyId", "merchantCompanyId"],
|
|
458
487
|
},
|
|
459
488
|
},
|
|
489
|
+
{
|
|
490
|
+
name: "merge_companies",
|
|
491
|
+
description: "Merge a duplicate company into its canonical record. EVERYTHING moves to the target — notes, meetings, emails, reminders, Kanban cards (deduped to the furthest-along), activity, Gmail threads — and the source's primary contact plus any previously merged contacts are preserved on the target's Contacts block with provenance. An audit note is written on the target, then the source record is deleted (its full history now lives on the target; nothing is stranded). IRREVERSIBLE — double-check ids with get_company first.",
|
|
492
|
+
inputSchema: {
|
|
493
|
+
type: "object",
|
|
494
|
+
properties: {
|
|
495
|
+
sourceCompanyId: { type: "number", description: "companies.id of the DUPLICATE to merge away" },
|
|
496
|
+
targetCompanyId: { type: "number", description: "companies.id of the CANONICAL record that keeps everything" },
|
|
497
|
+
},
|
|
498
|
+
required: ["sourceCompanyId", "targetCompanyId"],
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "add_contact",
|
|
503
|
+
description: "Append a secondary contact to a company's Contacts block (structured — shows on the company page). Deduped against the primary contact and existing entries. Use update_company for the PRIMARY contact slot; use this for additional people.",
|
|
504
|
+
inputSchema: {
|
|
505
|
+
type: "object",
|
|
506
|
+
properties: {
|
|
507
|
+
companyId: { type: "number", description: "Company id" },
|
|
508
|
+
email: { type: "string", description: "Contact email (required, the dedupe key)" },
|
|
509
|
+
name: { type: "string", description: "Full name" },
|
|
510
|
+
phone: { type: "string", description: "Phone" },
|
|
511
|
+
},
|
|
512
|
+
required: ["companyId", "email"],
|
|
513
|
+
},
|
|
514
|
+
},
|
|
460
515
|
{
|
|
461
516
|
name: "log_outreach",
|
|
462
517
|
description: "Log an outbound touch to a company — the SOURCE OF TRUTH for outreach with no dedicated integration (phone calls, WhatsApp, in-person). The 'Approached' reporting stage counts these alongside CSM emails, LinkedIn outreach logs, and Gmail threads. Notes do NOT count as outreach — log real touches here instead. Use search_companies first to get the companyId.",
|
|
@@ -689,9 +744,33 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
689
744
|
qs.set("endDate", String(a.endDate));
|
|
690
745
|
if (a.stage)
|
|
691
746
|
qs.set("stage", String(a.stage));
|
|
747
|
+
if (a.channel)
|
|
748
|
+
qs.set("channel", String(a.channel));
|
|
749
|
+
if (a.groupByChannel)
|
|
750
|
+
qs.set("groupByChannel", "true");
|
|
751
|
+
if (a.tags?.length)
|
|
752
|
+
qs.set("tags", a.tags.join(","));
|
|
692
753
|
data = await api("GET", `/funnel-entities?${qs.toString()}`);
|
|
693
754
|
break;
|
|
694
755
|
}
|
|
756
|
+
case "get_funnel_rates": {
|
|
757
|
+
const a = args;
|
|
758
|
+
const qs = new URLSearchParams();
|
|
759
|
+
if (a.entityType)
|
|
760
|
+
qs.set("entityType", String(a.entityType));
|
|
761
|
+
if (a.timeframe)
|
|
762
|
+
qs.set("timeframe", String(a.timeframe));
|
|
763
|
+
if (a.startDate)
|
|
764
|
+
qs.set("startDate", String(a.startDate));
|
|
765
|
+
if (a.endDate)
|
|
766
|
+
qs.set("endDate", String(a.endDate));
|
|
767
|
+
if (a.channel)
|
|
768
|
+
qs.set("channel", String(a.channel));
|
|
769
|
+
if (a.tags?.length)
|
|
770
|
+
qs.set("tags", a.tags.join(","));
|
|
771
|
+
data = await api("GET", `/funnel-rates?${qs.toString()}`);
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
695
774
|
case "link_merchant_to_agency": {
|
|
696
775
|
const a = args;
|
|
697
776
|
data = await api("POST", "/agencies/link-merchant", {
|
|
@@ -700,6 +779,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
700
779
|
});
|
|
701
780
|
break;
|
|
702
781
|
}
|
|
782
|
+
case "merge_companies": {
|
|
783
|
+
const a = args;
|
|
784
|
+
data = await api("POST", "/companies/merge", a);
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
case "add_contact": {
|
|
788
|
+
const { companyId, ...body } = args;
|
|
789
|
+
data = await api("POST", `/companies/${companyId}/contacts`, body);
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
703
792
|
case "log_outreach": {
|
|
704
793
|
const a = args;
|
|
705
794
|
data = await api("POST", "/outreach", a);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "notifyme-csm-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "NotifyMe CSM — MCP server for LLM integrations (Claude Code, Cursor, etc.)",
|
|
5
5
|
"_versionPolicy": "The version field above is a placeholder and is NEVER updated in git. The real published version lives only on npm — run `npm view notifyme-csm-mcp version` to check. To publish a new release, use the GitHub workflow `Publish MCP` (Actions tab → Publish notifyme-csm-mcp → Run workflow). This prevents recurring merge conflicts across feature/dev/main branches that used to plague every PR.",
|
|
6
6
|
"type": "module",
|