@agifyai/leadify-mcp 8.5.5 → 8.6.1
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 +22 -19
- package/dist/server.js +2 -0
- package/dist/tools/campaigns.js +3 -8
- package/dist/tools/context_entities.d.ts +668 -0
- package/dist/tools/context_entities.js +528 -0
- package/dist/tools/context_workspace.js +104 -49
- package/dist/tools/personas.js +142 -100
- package/dist/tools/pipeline.d.ts +4 -1
- package/dist/tools/pipeline.js +26 -35
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/tools/dataroom.d.ts +0 -2
- package/dist/tools/dataroom.js +0 -889
|
@@ -1,15 +1,43 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getClient } from "../client.js";
|
|
3
3
|
import { handleToolError, toolResult } from "../types.js";
|
|
4
|
-
const
|
|
4
|
+
const CONTEXT_KIND = "company_brain";
|
|
5
5
|
const MAX_READINESS_ISSUES = 20;
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const ACTIVE_CONTEXT_SECTIONS = [
|
|
7
|
+
"identity",
|
|
8
|
+
"positioning",
|
|
9
|
+
"allowedVocabulary",
|
|
10
|
+
"prohibitedVocabulary",
|
|
11
|
+
"legalConstraints",
|
|
12
|
+
];
|
|
13
|
+
const shortText = z.string().trim().max(500);
|
|
14
|
+
const longText = z.string().trim().max(20_000);
|
|
15
|
+
const section = (value) => z.object({
|
|
16
|
+
value,
|
|
9
17
|
evidenceIds: z.array(z.string().min(1)).max(100),
|
|
10
18
|
approved: z.boolean(),
|
|
11
19
|
}).strict();
|
|
12
|
-
const sectionPatchSchema = z.
|
|
20
|
+
const sectionPatchSchema = z.object({
|
|
21
|
+
identity: section(z.object({
|
|
22
|
+
companyName: shortText.optional(),
|
|
23
|
+
website: shortText.optional(),
|
|
24
|
+
industry: shortText.optional(),
|
|
25
|
+
summary: longText.optional(),
|
|
26
|
+
}).strict()).optional(),
|
|
27
|
+
positioning: section(z.object({
|
|
28
|
+
statement: longText.optional(),
|
|
29
|
+
elevatorPitch: longText.optional(),
|
|
30
|
+
geographies: z.array(shortText).max(50).optional(),
|
|
31
|
+
}).strict()).optional(),
|
|
32
|
+
allowedVocabulary: section(z.array(shortText).max(100)).optional(),
|
|
33
|
+
prohibitedVocabulary: section(z.array(shortText).max(100)).optional(),
|
|
34
|
+
legalConstraints: section(z.array(z.object({
|
|
35
|
+
id: z.string().trim().min(1).max(100),
|
|
36
|
+
title: shortText,
|
|
37
|
+
description: longText.optional(),
|
|
38
|
+
}).strict()).max(50)).optional(),
|
|
39
|
+
}).strict()
|
|
40
|
+
.refine((sections) => Object.keys(sections).length > 0, "At least one active section is required");
|
|
13
41
|
function compactReadiness(readiness) {
|
|
14
42
|
if (!readiness || typeof readiness !== "object" || Array.isArray(readiness))
|
|
15
43
|
return readiness;
|
|
@@ -25,6 +53,12 @@ function compactReadiness(readiness) {
|
|
|
25
53
|
: {}),
|
|
26
54
|
};
|
|
27
55
|
}
|
|
56
|
+
function activeContent(content) {
|
|
57
|
+
const source = record(content);
|
|
58
|
+
return Object.fromEntries(ACTIVE_CONTEXT_SECTIONS
|
|
59
|
+
.filter(section => Object.prototype.hasOwnProperty.call(source, section))
|
|
60
|
+
.map(section => [section, source[section]]));
|
|
61
|
+
}
|
|
28
62
|
function compactDraft(draft) {
|
|
29
63
|
if (!draft || typeof draft !== "object" || Array.isArray(draft))
|
|
30
64
|
return draft;
|
|
@@ -34,7 +68,7 @@ function compactDraft(draft) {
|
|
|
34
68
|
base_version: source.baseVersion,
|
|
35
69
|
rollback_from_version: source.rollbackFromVersion,
|
|
36
70
|
readiness: compactReadiness(source.readiness),
|
|
37
|
-
content: source.content,
|
|
71
|
+
content: activeContent(source.content),
|
|
38
72
|
created_at: source.createdAt,
|
|
39
73
|
updated_at: source.updatedAt,
|
|
40
74
|
};
|
|
@@ -47,7 +81,7 @@ function compactPublished(published) {
|
|
|
47
81
|
version: source.version,
|
|
48
82
|
source_draft_id: source.sourceDraftId,
|
|
49
83
|
readiness: compactReadiness(source.readiness),
|
|
50
|
-
content: source.content,
|
|
84
|
+
content: activeContent(source.content),
|
|
51
85
|
published_at: source.publishedAt,
|
|
52
86
|
};
|
|
53
87
|
}
|
|
@@ -57,10 +91,19 @@ export function projectContextWorkspaceRead(data) {
|
|
|
57
91
|
? data
|
|
58
92
|
: {};
|
|
59
93
|
const published = Array.isArray(source.published) ? source.published : [];
|
|
94
|
+
if (source.kind !== undefined && source.kind !== CONTEXT_KIND) {
|
|
95
|
+
throw new Error("Only company_brain remains exposed by the MCP Context Workspace.");
|
|
96
|
+
}
|
|
97
|
+
const latestPublished = published.reduce((latest, candidate) => {
|
|
98
|
+
const current = record(candidate);
|
|
99
|
+
const currentVersion = typeof current.version === "number" ? current.version : -1;
|
|
100
|
+
const latestVersion = typeof latest?.version === "number" ? latest.version : -1;
|
|
101
|
+
return currentVersion > latestVersion ? current : latest;
|
|
102
|
+
}, null);
|
|
60
103
|
return {
|
|
61
|
-
kind:
|
|
104
|
+
kind: CONTEXT_KIND,
|
|
62
105
|
draft: compactDraft(source.draft),
|
|
63
|
-
latest_published: compactPublished(
|
|
106
|
+
latest_published: compactPublished(latestPublished),
|
|
64
107
|
published_version_count: published.length,
|
|
65
108
|
...(published.length > 1 ? { historical_versions_omitted: published.length - 1 } : {}),
|
|
66
109
|
};
|
|
@@ -82,20 +125,34 @@ function mergeSections(read, sections) {
|
|
|
82
125
|
const published = Array.isArray(state.published) ? state.published : [];
|
|
83
126
|
// Start a new draft from the latest published document, then change only the
|
|
84
127
|
// named sections. This preserves every untouched section across revisions.
|
|
85
|
-
const
|
|
128
|
+
const latestPublished = published.reduce((latest, candidate) => {
|
|
129
|
+
const current = record(candidate);
|
|
130
|
+
const currentVersion = typeof current.version === "number" ? current.version : -1;
|
|
131
|
+
const latestVersion = typeof latest?.version === "number" ? latest.version : -1;
|
|
132
|
+
return currentVersion > latestVersion ? current : latest;
|
|
133
|
+
}, null);
|
|
134
|
+
const rawBase = Object.keys(draft).length > 0
|
|
86
135
|
? record(draft.content)
|
|
87
|
-
: record(
|
|
88
|
-
return { ...
|
|
136
|
+
: record(latestPublished?.content);
|
|
137
|
+
return { ...activeContent(rawBase), ...sections };
|
|
138
|
+
}
|
|
139
|
+
function assertActiveSections(sections) {
|
|
140
|
+
const allowed = new Set(ACTIVE_CONTEXT_SECTIONS);
|
|
141
|
+
const frozen = Object.keys(sections).filter(section => !allowed.has(section));
|
|
142
|
+
if (frozen.length > 0) {
|
|
143
|
+
throw new Error(`PRD-1415 strict ownership: company_brain.${frozen.sort().join(", company_brain.")} is historical and cannot be edited.`);
|
|
144
|
+
}
|
|
89
145
|
}
|
|
90
146
|
async function updateSections(client, input) {
|
|
91
|
-
|
|
147
|
+
assertActiveSections(input.sections);
|
|
148
|
+
const read = await client.get(`/api/context-workspace/${CONTEXT_KIND}`, new URLSearchParams({ organizationId: input.organizationId }));
|
|
92
149
|
const actualRevision = currentRevision(record(read).draft);
|
|
93
150
|
if (actualRevision !== input.expectedRevision) {
|
|
94
151
|
throw new Error(`Revision conflict before write: expected ${input.expectedRevision}, current ${actualRevision}. Re-read and retry without overwriting concurrent sections.`);
|
|
95
152
|
}
|
|
96
153
|
return client.put("/api/context-workspace/draft", {
|
|
97
154
|
organizationId: input.organizationId,
|
|
98
|
-
kind:
|
|
155
|
+
kind: CONTEXT_KIND,
|
|
99
156
|
content: mergeSections(read, input.sections),
|
|
100
157
|
expectedRevision: input.expectedRevision,
|
|
101
158
|
idempotencyKey: input.idempotencyKey,
|
|
@@ -135,50 +192,49 @@ export function registerContextWorkspaceTools(server, client = getClient()) {
|
|
|
135
192
|
});
|
|
136
193
|
server.registerTool("get_context_workspace", {
|
|
137
194
|
title: "Read canonical versioned Context Workspace",
|
|
138
|
-
description: "Read the
|
|
139
|
-
"Returns the current draft plus the latest published
|
|
140
|
-
"
|
|
195
|
+
description: "Read the versioned Company Brain for one explicitly selected organization. " +
|
|
196
|
+
"Returns the current draft plus the latest published version, with bounded readiness metadata. " +
|
|
197
|
+
"Verticals, Offers and Personas use their dedicated non-versioned tools; historical GTM Playbook rows are not exposed.",
|
|
141
198
|
inputSchema: {
|
|
142
199
|
organization_id: z.string().trim().min(1).describe("Required organization ID. Always select it explicitly; there is no default tenant."),
|
|
143
|
-
kind: kindSchema.describe("Canonical workspace document: `company_brain` or `gtm_playbook`."),
|
|
144
200
|
},
|
|
145
201
|
annotations: { readOnlyHint: true },
|
|
146
|
-
}, async ({ organization_id
|
|
202
|
+
}, async ({ organization_id }) => {
|
|
147
203
|
try {
|
|
148
204
|
const params = new URLSearchParams({ organizationId: organization_id });
|
|
149
|
-
const data = await client.get(`/api/context-workspace/${
|
|
205
|
+
const data = await client.get(`/api/context-workspace/${CONTEXT_KIND}`, params);
|
|
150
206
|
return toolResult(projectContextWorkspaceRead(data));
|
|
151
207
|
}
|
|
152
208
|
catch (error) {
|
|
153
209
|
return handleToolError(error);
|
|
154
210
|
}
|
|
155
211
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
}
|
|
212
|
+
server.registerTool("update_company_brain_sections", {
|
|
213
|
+
title: "Update Company Brain sections",
|
|
214
|
+
description: "Update only the named Company Brain sections. The MCP re-reads the current draft (or latest published version), merges only those sections, " +
|
|
215
|
+
`and saves with optimistic concurrency. Allowed sections: ${ACTIVE_CONTEXT_SECTIONS.join(", ")}. ` +
|
|
216
|
+
"Historical fields moved to Vertical, Offer, Persona or Lead Group are rejected by the closed schema.",
|
|
217
|
+
inputSchema: {
|
|
218
|
+
organization_id: z.string().trim().min(1).describe("Required organization ID; section writes require admin access."),
|
|
219
|
+
sections: sectionPatchSchema.describe("Only active Company Brain sections to change. Each section includes value, evidenceIds, and approved."),
|
|
220
|
+
expected_revision: z.number().int().nonnegative().describe("Current draft revision, or 0 when no draft exists. Re-read first."),
|
|
221
|
+
idempotency_key: z.string().trim().min(1).max(200).describe("Stable unique key for this exact section patch."),
|
|
222
|
+
},
|
|
223
|
+
annotations: { idempotentHint: true },
|
|
224
|
+
}, async ({ organization_id, sections, expected_revision, idempotency_key }) => {
|
|
225
|
+
try {
|
|
226
|
+
const data = await updateSections(client, {
|
|
227
|
+
organizationId: organization_id,
|
|
228
|
+
sections,
|
|
229
|
+
expectedRevision: expected_revision,
|
|
230
|
+
idempotencyKey: idempotency_key,
|
|
231
|
+
});
|
|
232
|
+
return toolResult(compactDraft(data));
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
return handleToolError(error);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
182
238
|
server.registerTool("publish_context_workspace", {
|
|
183
239
|
title: "Publish a ready Context Workspace draft",
|
|
184
240
|
description: "Publish exactly one ready draft revision of the canonical Context Workspace. This is a consequential action: it requires " +
|
|
@@ -186,17 +242,16 @@ export function registerContextWorkspaceTools(server, client = getClient()) {
|
|
|
186
242
|
"content with its readiness reasons and rejects stale revisions without overwriting anything.",
|
|
187
243
|
inputSchema: {
|
|
188
244
|
organization_id: z.string().trim().min(1).describe("Required organization ID; publication is restricted to an admin key for this tenant."),
|
|
189
|
-
kind: kindSchema,
|
|
190
245
|
expected_revision: z.number().int().positive().describe("Exact ready draft revision to publish, obtained from `get_context_workspace`."),
|
|
191
246
|
idempotency_key: z.string().trim().min(1).max(200).describe("Stable unique key for this exact publication request."),
|
|
192
247
|
confirm_publish: z.literal(true).describe("Must be explicitly true after the user has confirmed this publication."),
|
|
193
248
|
},
|
|
194
249
|
annotations: { destructiveHint: true, idempotentHint: true },
|
|
195
|
-
}, async ({ organization_id,
|
|
250
|
+
}, async ({ organization_id, expected_revision, idempotency_key }) => {
|
|
196
251
|
try {
|
|
197
252
|
const data = await client.post("/api/context-workspace/publish", {
|
|
198
253
|
organizationId: organization_id,
|
|
199
|
-
kind,
|
|
254
|
+
kind: CONTEXT_KIND,
|
|
200
255
|
expectedRevision: expected_revision,
|
|
201
256
|
idempotencyKey: idempotency_key,
|
|
202
257
|
});
|