@agifyai/leadify-mcp 8.1.1 → 8.3.0

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/README.md CHANGED
@@ -203,6 +203,7 @@ Conséquences pratiques :
203
203
  | `signal_disable` | Désactiver un signal (faux positif / écarté manuellement). Flip de `state` uniquement. |
204
204
  | `signal_delete` | Supprimer définitivement un signal (cas rare : donnée erronée, doublon). |
205
205
  | `add_activity` | Journaliser une interaction prospect (LinkedIn, email, call) dans le feed du lead. |
206
+ | `compile_context_pack` | Compiler en lecture seule un Context Pack canonique depuis une cible explicite (`organization`, `lead_group`, `campaign`, `account`, `person`) ou un couple lead + campagne pour `WRITE_OUTREACH`. Retourne publications courantes, sources, freshness, contradictions et provenance. N’utilise jamais la Data Room legacy ni ne choisit de cible implicite. |
206
207
  | `get_context_workspace` | Lire le Context Workspace canonique versionné (`company_brain` ou `gtm_playbook`) d'une organisation explicitement sélectionnée. Retourne le brouillon et la dernière version publiée. |
207
208
  | `update_company_brain_sections` | Modifier uniquement les sections indiquées du Company Brain : le MCP relit le brouillon ou la dernière publication, fusionne les sections ciblées, puis sauvegarde avec révision attendue et clé d'idempotence. |
208
209
  | `update_gtm_playbook_sections` | Modifier uniquement les sections indiquées du GTM Playbook, avec la même lecture-fusion-révision atomiquement contrôlée. |
package/dist/server.js CHANGED
@@ -13,14 +13,16 @@ import { registerOrganizationTools } from "./tools/organizations.js";
13
13
  import { registerPipelineTools } from "./tools/pipeline.js";
14
14
  import { registerFineTuningTools } from "./tools/fine_tuning.js";
15
15
  import { registerContextWorkspaceTools } from "./tools/context_workspace.js";
16
+ import { registerLeadViewTools } from "./tools/views.js";
16
17
  export function createServer() {
17
18
  const server = new McpServer({
18
19
  name: "leadify",
19
- version: "8.1.1",
20
+ version: "8.3.0",
20
21
  });
21
22
  registerAuthTools(server);
22
23
  registerOrganizationTools(server);
23
24
  registerLeadGroupTools(server);
25
+ registerLeadViewTools(server);
24
26
  registerLeadTools(server);
25
27
  registerSchemaTools(server);
26
28
  registerLogTools(server);
@@ -4,6 +4,9 @@ export interface ContextWorkspaceClient {
4
4
  put(path: string, body: unknown): Promise<unknown>;
5
5
  post(path: string, body: unknown): Promise<unknown>;
6
6
  }
7
+ export interface ContextPackClient {
8
+ post(path: string, body: unknown): Promise<unknown>;
9
+ }
7
10
  /** Bounded projection for agents: the active draft and latest published version only. */
8
11
  export declare function projectContextWorkspaceRead(data: unknown): Record<string, unknown>;
9
12
  export declare function registerContextWorkspaceTools(server: McpServer, client?: ContextWorkspaceClient): void;
@@ -102,6 +102,37 @@ async function updateSections(client, input) {
102
102
  });
103
103
  }
104
104
  export function registerContextWorkspaceTools(server, client = getClient()) {
105
+ server.registerTool("compile_context_pack", {
106
+ title: "Compile the canonical Context Pack",
107
+ description: "Compile the canonical, tenant-scoped Context Pack for one explicitly selected target. Use `target_kind` + `target_id` for organization, " +
108
+ "lead group, campaign, account, or person; use lead + campaign only for the WRITE_OUTREACH pack. This is read-only and never uses Data Room.",
109
+ inputSchema: {
110
+ organization_id: z.string().trim().min(1).describe("Organization explicitly selected through discover_leadify_context."),
111
+ target_kind: z.enum(["organization", "lead_group", "campaign", "account", "person"]).optional().describe("Direct canonical target; never causes an implicit lead/campaign selection."),
112
+ target_id: z.string().trim().min(1).optional().describe("Required for every target except organization."),
113
+ lead_id: z.string().trim().min(1).optional().describe("Lead targeted by a WRITE_OUTREACH pack; requires campaign_id."),
114
+ campaign_id: z.string().trim().min(1).optional().describe("Campaign targeted by a WRITE_OUTREACH pack; requires lead_id."),
115
+ max_evidence_age_ms: z.number().int().positive().max(90 * 24 * 60 * 60 * 1000).optional().describe("Optional freshness limit; defaults to 30 days and never exceeds 90 days."),
116
+ },
117
+ annotations: { readOnlyHint: true },
118
+ }, async ({ organization_id, target_kind, target_id, lead_id, campaign_id, max_evidence_age_ms }) => {
119
+ try {
120
+ if (target_kind) {
121
+ if (target_kind !== "organization" && !target_id)
122
+ return toolResult({ error: "target_id is required for this target_kind" });
123
+ return toolResult(await client.post("/api/context-pack/target", { organizationId: organization_id, target: { kind: target_kind, ...(target_id ? { id: target_id } : {}) } }));
124
+ }
125
+ if (!lead_id || !campaign_id)
126
+ return toolResult({ error: "Provide target_kind (and target_id when needed), or both lead_id and campaign_id." });
127
+ const body = { organizationId: organization_id, leadId: lead_id, campaignId: campaign_id };
128
+ if (max_evidence_age_ms !== undefined)
129
+ body.maxEvidenceAgeMs = max_evidence_age_ms;
130
+ return toolResult(await client.post("/api/context-pack/compile", body));
131
+ }
132
+ catch (error) {
133
+ return handleToolError(error);
134
+ }
135
+ });
105
136
  server.registerTool("get_context_workspace", {
106
137
  title: "Read canonical versioned Context Workspace",
107
138
  description: "Read the canonical Leadify Context Workspace for one explicitly selected organization and kind. " +
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerLeadViewTools(server: McpServer): void;
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ import { getClient } from "../client.js";
3
+ import { handleToolError, toolResult } from "../types.js";
4
+ const filterSchema = z.object({
5
+ field: z.string().describe("A standard, virtual, or selected lead-group schema field."),
6
+ operator: z.enum(["equals", "contains", "gte", "lte", "not_equals", "not_contains", "is_true", "is_false", "is_null", "is_not_null", "activity_days_ago", "activity_count_equals", "activity_count_gte", "activity_count_lte", "bbox"]),
7
+ value: z.unknown().optional(),
8
+ });
9
+ const viewConfigSchema = {
10
+ organization_id: z.string().describe("Organization that owns the explicitly selected lead group."),
11
+ lead_group_id: z.string().describe("Lead group ID. The view is shared with this group's organization."),
12
+ name: z.string().min(1),
13
+ filters: z.array(filterSchema),
14
+ columns: z.array(z.string()).optional(),
15
+ sort: z.object({ field: z.string(), direction: z.enum(["asc", "desc"]) }).optional(),
16
+ pagination: z.object({ page: z.number().int().min(1), limit: z.number().int().min(1).max(1000) }).optional(),
17
+ };
18
+ export function registerLeadViewTools(server) {
19
+ server.tool("list_lead_views", "List the virtual read-only default view and every saved view shared by the selected lead group's organization. Use get_lead_view for one full configuration.", { organization_id: z.string(), lead_group_id: z.string() }, async ({ organization_id, lead_group_id }) => {
20
+ try {
21
+ const data = await getClient().get(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views`);
22
+ const result = data;
23
+ return toolResult({ ...result, organizationId: organization_id });
24
+ }
25
+ catch (error) {
26
+ return handleToolError(error);
27
+ }
28
+ });
29
+ server.tool("get_lead_view", "Read one selected saved view, or the read-only virtual view ID `default`, after selecting its organization and lead group.", { organization_id: z.string(), lead_group_id: z.string(), view_id: z.string() }, async ({ organization_id, lead_group_id, view_id }) => {
30
+ try {
31
+ const data = await getClient().get(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views/${encodeURIComponent(view_id)}`);
32
+ return toolResult({ ...data, organizationId: organization_id });
33
+ }
34
+ catch (error) {
35
+ return handleToolError(error);
36
+ }
37
+ });
38
+ server.tool("preview_lead_view", "Validate a proposed organization-shared lead view without writing it. Use this before create_lead_view; no data or preference is changed.", viewConfigSchema, async ({ organization_id, lead_group_id, name, filters, columns, sort, pagination }) => {
39
+ try {
40
+ const data = await getClient().post(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views/preview`, { organizationId: organization_id, name, filters, columns, sort, pagination });
41
+ return toolResult(data);
42
+ }
43
+ catch (error) {
44
+ return handleToolError(error);
45
+ }
46
+ });
47
+ server.tool("create_lead_view", "Create an organization-shared saved view after previewing it. Idempotency key is required: retry the same request with the same key; changing the payload with that key conflicts. Update and delete are intentionally unavailable.", { ...viewConfigSchema, idempotency_key: z.string().min(8).max(200) }, async ({ organization_id, lead_group_id, name, filters, columns, sort, pagination, idempotency_key }) => {
48
+ try {
49
+ const data = await getClient().post(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views`, { organizationId: organization_id, name, filters, columns, sort, pagination, idempotencyKey: idempotency_key });
50
+ return toolResult(data);
51
+ }
52
+ catch (error) {
53
+ return handleToolError(error);
54
+ }
55
+ });
56
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agifyai/leadify-mcp",
3
- "version": "8.1.1",
3
+ "version": "8.3.0",
4
4
  "description": "MCP server for Leadify lead management API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",