conduyt-mcp 4.3.2 → 4.3.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/index.js +1 -1
- package/dist/tools/deals.js +45 -8
- package/package.json +2 -2
- package/dist/tools/knowledge.d.ts +0 -14
- package/dist/tools/knowledge.js +0 -38
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ if (!apiKey.startsWith("cdy_")) {
|
|
|
45
45
|
const client = new ConduytClient({ apiUrl, apiKey });
|
|
46
46
|
const server = new McpServer({
|
|
47
47
|
name: "conduyt",
|
|
48
|
-
version: "4.3.
|
|
48
|
+
version: "4.3.3",
|
|
49
49
|
});
|
|
50
50
|
registerDiscoveryTools(server, client);
|
|
51
51
|
registerContactTools(server, client);
|
package/dist/tools/deals.js
CHANGED
|
@@ -1,20 +1,57 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult } from "../client.js";
|
|
3
3
|
export function registerDealTools(server, client) {
|
|
4
|
-
server.tool("conduyt_list_deals", "List deals with filtering by pipeline, stage, assignee, or status. Returns deal title, value, stage, contact, and dates.", {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
server.tool("conduyt_list_deals", "List deals with filtering by pipeline, stage, assignee, or status. Returns deal title, value, stage, contact, and dates. Filter by pipeline/stage NAME (the same names you import with) or by UUID — both camelCase (pipelineName) and snake_case (pipeline_name) argument names are accepted. An unknown name returns a clear error, never the whole account.", {
|
|
5
|
+
pipeline: z.string().optional().describe("Filter by pipeline UUID (canonical). Aliases: pipelineId, pipeline_id."),
|
|
6
|
+
pipelineId: z.string().optional().describe("Filter by pipeline UUID (alias of pipeline)."),
|
|
7
|
+
pipeline_id: z.string().optional().describe("snake_case alias of pipelineId."),
|
|
8
|
+
pipelineName: z.string().optional().describe("Filter by pipeline NAME (the same name used in conduyt_import_deals/create) — resolved to its UUID; errors if not found. Alias: pipeline_name."),
|
|
9
|
+
pipeline_name: z.string().optional().describe("snake_case alias of pipelineName."),
|
|
10
|
+
stage: z.string().optional().describe("Filter by stage UUID (canonical). Aliases: stageId, stage_id."),
|
|
11
|
+
stageId: z.string().optional().describe("Filter by stage UUID (alias of stage)."),
|
|
12
|
+
stage_id: z.string().optional().describe("snake_case alias of stageId."),
|
|
13
|
+
stageName: z.string().optional().describe("Filter by stage NAME within the pipeline — resolved to its UUID; errors if not found. Alias: stage_name."),
|
|
14
|
+
stage_name: z.string().optional().describe("snake_case alias of stageName."),
|
|
7
15
|
assignedTo: z.string().optional().describe("Filter by assigned user UUID"),
|
|
8
16
|
status: z.enum(["open", "won", "lost"]).optional().describe("Filter by deal status"),
|
|
9
17
|
search: z.string().optional().describe("Search deal titles"),
|
|
10
18
|
page: z.number().optional().describe("Page number (default 1)"),
|
|
11
19
|
per_page: z.number().optional().describe("Results per page (default 25, max 100)"),
|
|
12
|
-
}, async (
|
|
20
|
+
}, async (a) => {
|
|
13
21
|
const params = new URLSearchParams();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
// Accept every reasonable casing of each filter (canonical bare name +
|
|
23
|
+
// camelCase + snake_case) so an agent's provided filter is NEVER silently
|
|
24
|
+
// stripped by the schema. Coalesce each alias GROUP to a single value
|
|
25
|
+
// locally — conflicting non-blank values in a group are a contradictory
|
|
26
|
+
// request and raise a clear tool error (don't emit ambiguous duplicate
|
|
27
|
+
// query params and hope the parser picks the right one) — then send ONE
|
|
28
|
+
// canonical wire param (pipeline / stage / pipeline_name / stage_name, the
|
|
29
|
+
// params the live contract advertises). A blank value is forwarded so the
|
|
30
|
+
// server rejects it; an id/name cross-conflict is caught by the server.
|
|
31
|
+
const coalesce = (label, ...vals) => {
|
|
32
|
+
const present = vals.filter((v) => v !== undefined);
|
|
33
|
+
if (present.length === 0)
|
|
34
|
+
return undefined;
|
|
35
|
+
const distinct = [...new Set(present.map((v) => v.trim().toLowerCase()).filter((v) => v !== ""))];
|
|
36
|
+
if (distinct.length > 1) {
|
|
37
|
+
throw new Error(`Conflicting ${label} values — pass only one.`);
|
|
38
|
+
}
|
|
39
|
+
// prefer a non-blank original; else keep a blank so the server can reject it
|
|
40
|
+
return present.find((v) => v.trim() !== "") ?? present[0];
|
|
41
|
+
};
|
|
42
|
+
const { assignedTo, status, search, page, per_page } = a;
|
|
43
|
+
const pipelineV = coalesce("pipeline id", a.pipeline, a.pipelineId, a.pipeline_id);
|
|
44
|
+
const pipelineNameV = coalesce("pipeline name", a.pipelineName, a.pipeline_name);
|
|
45
|
+
const stageV = coalesce("stage id", a.stage, a.stageId, a.stage_id);
|
|
46
|
+
const stageNameV = coalesce("stage name", a.stageName, a.stage_name);
|
|
47
|
+
if (pipelineV !== undefined)
|
|
48
|
+
params.set("pipeline", pipelineV);
|
|
49
|
+
if (pipelineNameV !== undefined)
|
|
50
|
+
params.set("pipeline_name", pipelineNameV);
|
|
51
|
+
if (stageV !== undefined)
|
|
52
|
+
params.set("stage", stageV);
|
|
53
|
+
if (stageNameV !== undefined)
|
|
54
|
+
params.set("stage_name", stageNameV);
|
|
18
55
|
if (assignedTo)
|
|
19
56
|
params.set("assigned_to", assignedTo);
|
|
20
57
|
if (status)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conduyt-mcp",
|
|
3
|
-
"version": "4.3.
|
|
4
|
-
"description": "MCP server for Conduyt CRM
|
|
3
|
+
"version": "4.3.3",
|
|
4
|
+
"description": "MCP server for Conduyt CRM — expose CRM operations as AI-accessible tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { ConduytClient } from "../client.js";
|
|
3
|
-
/**
|
|
4
|
-
* Document knowledge base (RAG) — tier 2 of Conduyt's AI model: "use our AI with
|
|
5
|
-
* YOUR model." Uploaded documents are retrieved and fed to the chat model on
|
|
6
|
-
* every call, so the feature is gated to accounts running their OWN AI engine
|
|
7
|
-
* (BYO key). Caps: BYO = 20 docs, + $50/mo AI Knowledge add-on = 100, >100 is
|
|
8
|
-
* handled manually ("reach out to us").
|
|
9
|
-
*
|
|
10
|
-
* All JSON surfaces (API / MCP / CLI) expose the same subset: list / add-URL /
|
|
11
|
-
* delete / reindex. Binary file upload (TXT/MD/CSV) is multipart and is web-UI
|
|
12
|
-
* only — neither MCP tool calls nor the generated CLI carry a file body.
|
|
13
|
-
*/
|
|
14
|
-
export declare function registerKnowledgeTools(server: McpServer, client: ConduytClient): void;
|
package/dist/tools/knowledge.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { formatResult } from "../client.js";
|
|
3
|
-
/**
|
|
4
|
-
* Document knowledge base (RAG) — tier 2 of Conduyt's AI model: "use our AI with
|
|
5
|
-
* YOUR model." Uploaded documents are retrieved and fed to the chat model on
|
|
6
|
-
* every call, so the feature is gated to accounts running their OWN AI engine
|
|
7
|
-
* (BYO key). Caps: BYO = 20 docs, + $50/mo AI Knowledge add-on = 100, >100 is
|
|
8
|
-
* handled manually ("reach out to us").
|
|
9
|
-
*
|
|
10
|
-
* All JSON surfaces (API / MCP / CLI) expose the same subset: list / add-URL /
|
|
11
|
-
* delete / reindex. Binary file upload (TXT/MD/CSV) is multipart and is web-UI
|
|
12
|
-
* only — neither MCP tool calls nor the generated CLI carry a file body.
|
|
13
|
-
*/
|
|
14
|
-
export function registerKnowledgeTools(server, client) {
|
|
15
|
-
server.tool("conduyt_list_knowledge_sources", "List the account's AI knowledge-base documents and the current entitlement. Returns each source (name, type, status: queued|indexing|indexed|stale|failed) plus byoActive (whether the document KB is unlocked by an own-AI-key), addon (whether the $50/mo add-on is active), docLimit, and used count.", {}, async () => {
|
|
16
|
-
const result = await client.get("/api/v1/knowledge/sources");
|
|
17
|
-
return formatResult(result);
|
|
18
|
-
});
|
|
19
|
-
server.tool("conduyt_add_knowledge_url", "Add a web page to the AI knowledge base by URL. The page is scraped, chunked, embedded, and becomes retrievable for AI answers. Requires the account to have its own AI key connected (byoActive) and to be under its document cap. To add a file (TXT/MD/CSV), use the web UI — file upload is multipart and not available over MCP or CLI.", {
|
|
20
|
-
url: z.string().describe("Public http(s) URL of the page to learn from"),
|
|
21
|
-
name: z.string().optional().describe("Optional friendly name (defaults to the URL)"),
|
|
22
|
-
}, async (params) => {
|
|
23
|
-
const result = await client.post("/api/v1/knowledge/sources", params);
|
|
24
|
-
return formatResult(result);
|
|
25
|
-
});
|
|
26
|
-
server.tool("conduyt_delete_knowledge_source", "Remove a document from the AI knowledge base. Deletes the stored file (if any) and all of its embeddings. Account-scoped.", {
|
|
27
|
-
id: z.string().describe("Knowledge source UUID"),
|
|
28
|
-
}, async ({ id }) => {
|
|
29
|
-
const result = await client.del(`/api/v1/knowledge/sources/${id}`);
|
|
30
|
-
return formatResult(result);
|
|
31
|
-
});
|
|
32
|
-
server.tool("conduyt_reindex_knowledge_source", "Re-learn a document — re-fetches/re-extracts and rebuilds its embeddings. Use to refresh a URL whose content changed, or to retry a source that failed indexing.", {
|
|
33
|
-
id: z.string().describe("Knowledge source UUID"),
|
|
34
|
-
}, async ({ id }) => {
|
|
35
|
-
const result = await client.post(`/api/v1/knowledge/sources/${id}/reindex`, {});
|
|
36
|
-
return formatResult(result);
|
|
37
|
-
});
|
|
38
|
-
}
|