@wukongcrm/mcp-server 0.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 ADDED
@@ -0,0 +1,78 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { createToolHandlers } from "./tools.js";
4
+ const moduleSchema = z.union([z.string(), z.number()]);
5
+ const passthroughSchema = z.object({}).passthrough();
6
+ const toolDefinitions = [
7
+ ["crm_auth_status", "使用 CRM_API_KEY 自动换取 Admin-Token 后检查当前登录态,异常时提示检查 API Key。", z.object({}).optional()],
8
+ ["crm_list_modules", "列出当前 MCP 固定支持的 72CRM 模块、label、路径和中英文操作边界。", z.object({}).optional()],
9
+ ["crm_list_customer_pools", "查询当前账号有权限访问的客户公海,并统计每个公海下面有多少客户;只读,不领取、不分配、不流转。", z.object({ includeSamples: z.boolean().optional(), sampleLimit: z.number().optional() }).passthrough()],
10
+ ["crm_get_module_schema", "获取模块字段结构和列表头,供本地 AI 判断字段怎么填。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]).optional() }).passthrough()],
11
+ ["crm_validate_field", "调用固定字段校验接口,校验字段值或联系人查重。", passthroughSchema],
12
+ ["crm_search_records", "查询模块分页列表;当传入 keyword/query/q/phone/mobile/name 等明显搜索语义时,会自动转换为 72CRM 高级筛选 searchList。", z.object({ module: moduleSchema, page: z.number().optional(), limit: z.number().optional() }).passthrough()],
13
+ ["crm_get_record", "按模块和 ID 查询单条 CRM 记录详情。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]) }).passthrough()],
14
+ ["crm_get_record_information", "查询详情页字段展示数据,包含字段中文名和值。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]) }).passthrough()],
15
+ ["crm_get_related_records", "查询固定白名单内的关联数据,例如商机产品、联系人商机、合同回款计划。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]), relation: z.string() }).passthrough()],
16
+ ["crm_get_record_timeline", "查询某条记录关联的跟进/活动时间线。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]) }).passthrough()],
17
+ ["crm_get_action_records", "查询某条记录的操作记录。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]) }).passthrough()],
18
+ ["crm_list_files", "只读查询附件元数据,不上传、不删除、不代理下载流。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]) }).passthrough()],
19
+ ["crm_list_users", "查询员工列表。", passthroughSchema],
20
+ ["crm_find_user_id", "按登录名或真实姓名查询员工 ID。", z.object({ userName: z.string().optional(), name: z.string().optional(), mode: z.enum(["username", "realname"]).optional() }).passthrough()],
21
+ ["crm_list_departments", "查询部门树。", passthroughSchema],
22
+ ["crm_find_dept_id", "按部门名查询部门 ID。", z.object({ deptName: z.string().optional(), name: z.string().optional() }).passthrough()],
23
+ ["crm_preview_write", "写入前预览和校验,不调用 72CRM 写接口。", passthroughSchema],
24
+ ["crm_create_record", "新增线索、客户、联系人、商机;必须 confirm=true 才会写入。", z.object({ module: moduleSchema, confirm: z.boolean().optional() }).passthrough()],
25
+ ["crm_update_customer", "按客户 ID 或手机号/客户名唯一匹配后更新客户字段;会自动补全字段结构并写后校验,必须 confirm=true 才会写入。", z.object({ confirm: z.boolean().optional() }).passthrough()],
26
+ ["crm_update_record_fields", "更新线索、客户、联系人、商机基础字段;必须 confirm=true 才会写入。", z.object({ module: moduleSchema, id: z.union([z.string(), z.number()]), confirm: z.boolean().optional() }).passthrough()],
27
+ ["crm_add_followup", "新增跟进记录;必须 confirm=true 才会写入。", z.object({ confirm: z.boolean().optional() }).passthrough()],
28
+ ["crm_update_followup", "更新跟进记录;必须 confirm=true 才会写入。", z.object({ id: z.union([z.string(), z.number()]).optional(), confirm: z.boolean().optional() }).passthrough()]
29
+ ];
30
+ export function createWukongMcpServer(config = {}) {
31
+ const server = new McpServer({
32
+ name: "@wukongcrm/mcp-server",
33
+ version: "0.1.3"
34
+ });
35
+ const handlers = createToolHandlers(config);
36
+ for (const [name, description, schema] of toolDefinitions) {
37
+ server.registerTool(name, {
38
+ title: name,
39
+ description,
40
+ inputSchema: schema
41
+ }, async (args) => {
42
+ try {
43
+ const result = await handlers[name](args ?? {});
44
+ return toToolText(result);
45
+ }
46
+ catch (error) {
47
+ return {
48
+ isError: true,
49
+ content: [
50
+ {
51
+ type: "text",
52
+ text: sanitizeError(error)
53
+ }
54
+ ]
55
+ };
56
+ }
57
+ });
58
+ }
59
+ return server;
60
+ }
61
+ function toToolText(result) {
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: JSON.stringify(result, null, 2)
67
+ }
68
+ ]
69
+ };
70
+ }
71
+ function sanitizeError(error) {
72
+ let message = error instanceof Error ? error.message : String(error);
73
+ const apiKey = process.env.CRM_API_KEY;
74
+ if (apiKey && apiKey.length > 4) {
75
+ message = message.replaceAll(apiKey, "***");
76
+ }
77
+ return message;
78
+ }
@@ -0,0 +1,8 @@
1
+ import { CrmClientConfig } from "./client.js";
2
+ type AnyArgs = Record<string, any>;
3
+ type Handler = (args: AnyArgs) => Promise<any> | any;
4
+ export interface ToolHandlers {
5
+ [name: string]: Handler;
6
+ }
7
+ export declare function createToolHandlers(config?: CrmClientConfig): ToolHandlers;
8
+ export {};