@agifyai/leadify-mcp 7.1.1 → 7.1.3
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/server.js
CHANGED
|
@@ -16,7 +16,7 @@ import { registerFineTuningTools } from "./tools/fine_tuning.js";
|
|
|
16
16
|
export function createServer() {
|
|
17
17
|
const server = new McpServer({
|
|
18
18
|
name: "leadify",
|
|
19
|
-
version: "
|
|
19
|
+
version: "7.1.3",
|
|
20
20
|
});
|
|
21
21
|
registerAuthTools(server);
|
|
22
22
|
registerOrganizationTools(server);
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export declare function assertLeadGroupsBelongToOrganization(data: unknown, organizationId: string): Array<Record<string, unknown>>;
|
|
2
3
|
export declare function registerOrganizationTools(server: McpServer): void;
|
|
@@ -1,5 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import { getClient } from "../client.js";
|
|
2
3
|
import { toolResult, handleToolError } from "../types.js";
|
|
4
|
+
export function assertLeadGroupsBelongToOrganization(data, organizationId) {
|
|
5
|
+
if (!data ||
|
|
6
|
+
typeof data !== "object" ||
|
|
7
|
+
!Array.isArray(data.leadGroups)) {
|
|
8
|
+
throw new Error("Leadify returned an invalid lead group list response");
|
|
9
|
+
}
|
|
10
|
+
const leadGroups = data.leadGroups;
|
|
11
|
+
for (const group of leadGroups) {
|
|
12
|
+
if (!group || typeof group !== "object") {
|
|
13
|
+
throw new Error("Leadify returned an invalid lead group");
|
|
14
|
+
}
|
|
15
|
+
const actualOrganizationId = group.organizationId;
|
|
16
|
+
if (actualOrganizationId !== organizationId) {
|
|
17
|
+
const groupId = group.id;
|
|
18
|
+
throw new Error(`Leadify returned group ${typeof groupId === "string" ? groupId : "without an id"} ` +
|
|
19
|
+
`from organization ${typeof actualOrganizationId === "string" ? actualOrganizationId : "without an organization"} ` +
|
|
20
|
+
`while ${organizationId} was requested`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return leadGroups;
|
|
24
|
+
}
|
|
3
25
|
export function registerOrganizationTools(server) {
|
|
4
26
|
// ── list_organizations ─────────────────────────────────────────────────
|
|
5
27
|
server.tool("list_organizations", "List every organization accessible to the caller, returning each with id, name, and " +
|
|
@@ -14,4 +36,67 @@ export function registerOrganizationTools(server) {
|
|
|
14
36
|
return handleToolError(error);
|
|
15
37
|
}
|
|
16
38
|
});
|
|
39
|
+
server.tool("list_lead_groups", "List lead groups visible in one explicitly selected organization. Returns a compact " +
|
|
40
|
+
"navigation view only: id, name, organizationId, lead count, published and refresh state. " +
|
|
41
|
+
"Start with discover_leadify_context when no organization_id is known.", {
|
|
42
|
+
organization_id: z.string().describe("Organization ID explicitly selected from list_organizations or discover_leadify_context."),
|
|
43
|
+
limit: z.number().int().min(1).max(100).optional().default(50).describe("Maximum groups returned, bounded to 100."),
|
|
44
|
+
}, async ({ organization_id, limit }) => {
|
|
45
|
+
try {
|
|
46
|
+
const params = new URLSearchParams({ organizationId: organization_id });
|
|
47
|
+
const data = await getClient().get("/api/lead-groups", params);
|
|
48
|
+
const groups = assertLeadGroupsBelongToOrganization(data, organization_id);
|
|
49
|
+
return toolResult({
|
|
50
|
+
organizationId: organization_id,
|
|
51
|
+
leadGroups: groups.slice(0, limit).map((group) => ({
|
|
52
|
+
id: group.id,
|
|
53
|
+
name: group.name,
|
|
54
|
+
organizationId: group.organizationId,
|
|
55
|
+
leadCount: group._count?.leads ?? 0,
|
|
56
|
+
published: group.published ?? false,
|
|
57
|
+
refreshEnabled: group.refreshEnabled ?? false,
|
|
58
|
+
})),
|
|
59
|
+
total: groups.length,
|
|
60
|
+
truncated: groups.length > limit,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
return handleToolError(error);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
server.tool("discover_leadify_context", "Safe zero-ID entry point for Leadify. With no organization_id, lists accessible organizations " +
|
|
68
|
+
"and never chooses one when several are available. With an explicit organization_id, returns " +
|
|
69
|
+
"a compact list of its lead groups. Use the returned lead_group_id with lead, campaign, persona " +
|
|
70
|
+
"and data-room tools.", {
|
|
71
|
+
organization_id: z.string().optional().describe("Organization selected explicitly after discovery. Omit only for the first step."),
|
|
72
|
+
limit: z.number().int().min(1).max(100).optional().default(50).describe("Maximum lead groups returned after selection."),
|
|
73
|
+
}, async ({ organization_id, limit }) => {
|
|
74
|
+
try {
|
|
75
|
+
const orgData = await getClient().get("/api/organizations");
|
|
76
|
+
const organizations = Array.isArray(orgData.organizations)
|
|
77
|
+
? orgData.organizations.map((org) => ({ id: org.id, name: org.name ?? null, slug: org.slug ?? null }))
|
|
78
|
+
: [];
|
|
79
|
+
if (!organization_id) {
|
|
80
|
+
if (organizations.length !== 1) {
|
|
81
|
+
return toolResult({ organizations, selectionRequired: organizations.length > 1, message: organizations.length === 0 ? "No accessible organization." : "Select organization_id explicitly before reading lead groups." });
|
|
82
|
+
}
|
|
83
|
+
organization_id = String(organizations[0].id);
|
|
84
|
+
}
|
|
85
|
+
if (!organizations.some((org) => org.id === organization_id)) {
|
|
86
|
+
return toolResult({ organizations, selectionRequired: true, message: "organization_id is not accessible to this key." });
|
|
87
|
+
}
|
|
88
|
+
const groupsData = await getClient().get("/api/lead-groups", new URLSearchParams({ organizationId: organization_id }));
|
|
89
|
+
const groups = assertLeadGroupsBelongToOrganization(groupsData, organization_id);
|
|
90
|
+
return toolResult({
|
|
91
|
+
organization: organizations.find((org) => org.id === organization_id),
|
|
92
|
+
leadGroups: groups.slice(0, limit).map((group) => ({ id: group.id, name: group.name, organizationId: group.organizationId, leadCount: group._count?.leads ?? 0, published: group.published ?? false })),
|
|
93
|
+
total: groups.length,
|
|
94
|
+
truncated: groups.length > limit,
|
|
95
|
+
next: "Choose a lead_group_id, then use get_leads, get_data_room_context, or get_lead_group_persona.",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return handleToolError(error);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
17
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agifyai/leadify-mcp",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.3",
|
|
4
4
|
"description": "MCP server for Leadify lead management API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"build": "rm -rf dist && tsc && chmod +x dist/index.js",
|
|
16
16
|
"start": "node dist/index.js",
|
|
17
17
|
"dev": "tsc --watch",
|
|
18
|
-
"prepublishOnly": "npm run build"
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "npm run build && node --test test/**/*.test.mjs"
|
|
19
20
|
},
|
|
20
21
|
"repository": {
|
|
21
22
|
"type": "git",
|