ppxc-leads-mcp 0.1.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 +115 -0
- package/dist/backend/config.js +13 -0
- package/dist/backend/ppxc-client.js +156 -0
- package/dist/backend/ppxc-login-window.js +168 -0
- package/dist/backend/token-store.js +65 -0
- package/dist/browser/comments.js +9 -0
- package/dist/browser/douyin-runner.js +15 -0
- package/dist/browser/kernel/electron-profile.js +32 -0
- package/dist/browser/kernel/logger.js +57 -0
- package/dist/browser/kernel/page-scripts/index.js +1422 -0
- package/dist/browser/kernel/runner-page-manager.js +145 -0
- package/dist/browser/kernel/runner-page-session.js +1465 -0
- package/dist/browser/kernel/runner-page-session.search-parser.js +187 -0
- package/dist/browser/kernel/runner-page-session.user-agent.js +32 -0
- package/dist/browser/platform-runner.js +312 -0
- package/dist/browser/platforms/detect-platform.js +33 -0
- package/dist/browser/platforms/douyin/adapter.js +162 -0
- package/dist/browser/platforms/douyin/comments.js +130 -0
- package/dist/browser/platforms/kuaishou/adapter.js +178 -0
- package/dist/browser/platforms/kuaishou/comments.js +170 -0
- package/dist/browser/platforms/registry.js +23 -0
- package/dist/browser/platforms/shared/cdp-json-waiter.js +75 -0
- package/dist/browser/platforms/types.js +3 -0
- package/dist/browser/platforms/xiaohongshu/adapter.js +233 -0
- package/dist/browser/platforms/xiaohongshu/comments.js +184 -0
- package/dist/browser/usage-throttle.js +72 -0
- package/dist/main.js +64 -0
- package/dist/mcp/battle-report.js +325 -0
- package/dist/mcp/content-insights.js +66 -0
- package/dist/mcp/diagnostics.js +79 -0
- package/dist/mcp/server.js +829 -0
- package/dist/version.js +19 -0
- package/package.json +43 -0
- package/scripts/launch-mcp.cjs +96 -0
- package/skills/ppxc-find-customers/SKILL.md +110 -0
package/dist/version.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OWN_VERSION = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
function readOwnVersion() {
|
|
10
|
+
try {
|
|
11
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(__dirname, "..", "package.json"), "utf8"));
|
|
12
|
+
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return "unknown";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.OWN_VERSION = readOwnVersion();
|
|
19
|
+
//# sourceMappingURL=version.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ppxc-leads-mcp",
|
|
3
|
+
"productName": "PPXC Leads MCP",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "PPXC 找客户能力的 MCP 工具包:智能体可调用的抖音/小红书/快手评论客户发现工具",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"main": "dist/main.js",
|
|
8
|
+
"type": "commonjs",
|
|
9
|
+
"bin": {
|
|
10
|
+
"ppxc-leads-mcp": "scripts/launch-mcp.cjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"!dist/scripts",
|
|
15
|
+
"!dist/**/*.map",
|
|
16
|
+
"scripts/launch-mcp.cjs",
|
|
17
|
+
"skills",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"start": "electron .",
|
|
24
|
+
"prepack": "npm run build",
|
|
25
|
+
"smoke:comments": "npm run build && OPC1_PAGE_VISIBLE=${OPC1_PAGE_VISIBLE:-0} electron dist/scripts/smoke-comments-main.js",
|
|
26
|
+
"smoke:e2e": "npm run build && electron dist/scripts/smoke-e2e-main.js",
|
|
27
|
+
"smoke:backend": "npm run build && electron dist/scripts/smoke-backend-tools-main.js",
|
|
28
|
+
"regression:static": "npm run build && node dist/scripts/regression-static-main.js",
|
|
29
|
+
"spike:probe": "npm run build && PPXC_MCP_PAGE_VISIBLE=${PPXC_MCP_PAGE_VISIBLE:-1} electron dist/scripts/spike-platform-probe-main.js"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.5.0",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
37
|
+
"electron": "^42.0.1",
|
|
38
|
+
"zod": "^3.23.8"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP 启动器(npm 包入口 / 本地开发通用)。
|
|
4
|
+
*
|
|
5
|
+
* 职责:
|
|
6
|
+
* 1. 找到 Electron 可执行文件——优先 require("electron")(npm 安装形态,无论被提升
|
|
7
|
+
* 到哪一层 node_modules 都能找到),找不到再回退本仓库自己的 node_modules。
|
|
8
|
+
* 2. 清掉 ELECTRON_RUN_AS_NODE:Cursor 等宿主本身是 Electron 应用,启动子进程时会带上
|
|
9
|
+
* 这个变量,导致 electron 主进程的 app 对象不可用。
|
|
10
|
+
* 3. 启动失败时给人话提示(写 stderr,stdout 留给 MCP 协议)。
|
|
11
|
+
*/
|
|
12
|
+
const { spawn } = require("node:child_process");
|
|
13
|
+
const { existsSync } = require("node:fs");
|
|
14
|
+
const path = require("node:path");
|
|
15
|
+
|
|
16
|
+
const root = path.resolve(__dirname, "..");
|
|
17
|
+
|
|
18
|
+
function resolveElectronBinary() {
|
|
19
|
+
// npm 安装形态:electron 包的入口导出二进制路径
|
|
20
|
+
try {
|
|
21
|
+
const fromPackage = require("electron");
|
|
22
|
+
if (typeof fromPackage === "string" && existsSync(fromPackage)) return fromPackage;
|
|
23
|
+
} catch {
|
|
24
|
+
/* 继续尝试本地形态 */
|
|
25
|
+
}
|
|
26
|
+
// 本地开发形态:仓库自己的 node_modules
|
|
27
|
+
const local = path.join(
|
|
28
|
+
root,
|
|
29
|
+
"node_modules",
|
|
30
|
+
".bin",
|
|
31
|
+
process.platform === "win32" ? "electron.cmd" : "electron",
|
|
32
|
+
);
|
|
33
|
+
if (existsSync(local)) return local;
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const electronBin = resolveElectronBinary();
|
|
38
|
+
const mainJs = path.join(root, "dist", "main.js");
|
|
39
|
+
|
|
40
|
+
if (!electronBin) {
|
|
41
|
+
process.stderr.write(
|
|
42
|
+
"[ppxc-leads-mcp] 运行环境没准备好:浏览器内核缺失。\n" +
|
|
43
|
+
"多半是首次安装时网络中断导致下载失败。请换个网络环境重新安装,\n" +
|
|
44
|
+
"国内网络建议在智能体配置的 env 里加:ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/\n",
|
|
45
|
+
);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!existsSync(mainJs)) {
|
|
50
|
+
process.stderr.write("[ppxc-leads-mcp] 安装不完整(缺少主程序文件),请重新安装。\n");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const env = { ...process.env };
|
|
55
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
56
|
+
|
|
57
|
+
const child = spawn(electronBin, [mainJs], {
|
|
58
|
+
stdio: "inherit",
|
|
59
|
+
env,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let exiting = false;
|
|
63
|
+
|
|
64
|
+
function exitWithChild(code, signal) {
|
|
65
|
+
if (exiting) return;
|
|
66
|
+
exiting = true;
|
|
67
|
+
if (!child.killed) {
|
|
68
|
+
child.kill(signal || "SIGTERM");
|
|
69
|
+
}
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
process.exit(code ?? 0);
|
|
72
|
+
}, 500).unref();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
76
|
+
process.on(signal, () => {
|
|
77
|
+
exitWithChild(0, signal);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
child.on("exit", (code, signal) => {
|
|
82
|
+
if (exiting) {
|
|
83
|
+
process.exit(code ?? 0);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (signal) {
|
|
87
|
+
process.kill(process.pid, signal);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
process.exit(code ?? 0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
child.on("error", (err) => {
|
|
94
|
+
process.stderr.write(`[ppxc-leads-mcp] 启动失败:${err.message}\n`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ppxc-find-customers
|
|
3
|
+
description: 用 PPXC 找客户小组件(MCP)从抖音/小红书/快手评论区挖潜在客户的标准工作流。当用户说「帮我找客户」「谁想买我的产品」「分析这条视频/笔记的评论区」「用XX词搜搜看」「之前挖到的客户怎么样了」时使用。要求已接入 ppxc-leads-mcp 的 MCP 工具。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PPXC 找客户 · 标准工作流
|
|
7
|
+
|
|
8
|
+
你是用户的找客户助手。底层能力由 PPXC 找客户小组件(MCP 工具)提供:用用户本人的账号、像真人一样去抖音/小红书/快手看评论区,AI 判断谁是潜在客户,并把结果存入用户的 PPXC 客户池。
|
|
9
|
+
|
|
10
|
+
## 第 0 步:自检与自动接线(工具不可用时才走)
|
|
11
|
+
|
|
12
|
+
本技能被触发但找不到 `ppxc-leads-mcp` 的 MCP 工具(如 `check_status_and_login`)时,先帮用户把小组件装好,再继续:
|
|
13
|
+
|
|
14
|
+
1. **检查 Node**:终端跑 `node -v`,要求 ≥ 18。没有 Node 就引导用户去 nodejs.org 装 LTS 版(约一分钟),装完继续。
|
|
15
|
+
2. **写入 MCP 配置**(你有文件编辑能力时):往宿主的 MCP 配置里**合并**(绝不覆盖用户已有配置)这一条:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"ppxc-leads": { "command": "npx", "args": ["-y", "ppxc-leads-mcp"] }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
常见宿主的配置位置:
|
|
26
|
+
|
|
27
|
+
- **Cursor**:`~/.cursor/mcp.json`(全局)或项目下 `.cursor/mcp.json`
|
|
28
|
+
- **Claude Code**:直接跑 `claude mcp add ppxc-leads -- npx -y ppxc-leads-mcp`
|
|
29
|
+
- **Claude 桌面版**:macOS `~/Library/Application Support/Claude/claude_desktop_config.json`;Windows `%APPDATA%\Claude\claude_desktop_config.json`
|
|
30
|
+
- 其他标准 MCP(stdio)宿主:在其 MCP 设置里按同样格式加一条
|
|
31
|
+
|
|
32
|
+
3. **告诉用户**:「我把 PPXC 找客户小组件的配置加好了,重启/刷新一下智能体就能用。首次使用会自动下载运行环境(约一两分钟,取决于网络)。」
|
|
33
|
+
4. **重启后验证**:调 `check_status_and_login` 确认工具就位,然后从第 1 步继续。
|
|
34
|
+
5. **你没有文件编辑能力时**:把上面那段配置原样发给用户,告诉他贴进自己智能体的 MCP 设置里,并附 PPXC 官网接入页(有逐家图文步骤)。
|
|
35
|
+
|
|
36
|
+
## 标准流程(按顺序)
|
|
37
|
+
|
|
38
|
+
### 第 1 步:确认登录
|
|
39
|
+
|
|
40
|
+
调 `check_status_and_login`(默认 status)。缺哪个登录就引导用户补哪个:
|
|
41
|
+
|
|
42
|
+
- PPXC 账号未登录 → `action=login_ppxc` 弹登录窗
|
|
43
|
+
- 目标平台未登录 → `action=login_douyin / login_xiaohongshu / login_kuaishou` 弹扫码窗,请用户用对应 App 扫码
|
|
44
|
+
|
|
45
|
+
### 第 2 步:确认产品
|
|
46
|
+
|
|
47
|
+
调 `list_products`。只有一个产品直接用;有多个时把名字列给用户选,**不要替用户猜**。
|
|
48
|
+
|
|
49
|
+
### 第 3 步:先要词,再开搜
|
|
50
|
+
|
|
51
|
+
不要自己现场编搜索词。先调 `suggest_search_keywords`(传 productId),从返回的主力词里挑 **3~6 个**,搭配不同词型更好(比如:1 个泛需求词 + 2 个人群痛点词 + 1 个决策对比词)。把你挑的词和理由告诉用户,用户有自己想加的词就一起带上。
|
|
52
|
+
|
|
53
|
+
`regenerate=true` 会重新生成并消耗用户电力——只有用户明确说「换一批词」才用。
|
|
54
|
+
|
|
55
|
+
### 第 4 步:开搜
|
|
56
|
+
|
|
57
|
+
调 `search_keyword_for_leads`(keywords + productId + platform)。平台听用户的;用户没说就问一句,不要默认猜。
|
|
58
|
+
|
|
59
|
+
开搜前告诉用户:这一步要 2~3 分钟,会在后台用隐藏窗口干活。
|
|
60
|
+
|
|
61
|
+
如果用户给的是具体的视频/笔记链接,跳过 3、4 步,直接调 `analyze_video_comments`。
|
|
62
|
+
|
|
63
|
+
### 第 5 步:汇报成果(固定格式)
|
|
64
|
+
|
|
65
|
+
按这个顺序说,不要把原始 JSON 念出来:
|
|
66
|
+
|
|
67
|
+
1. **一句总结**:直接用返回里的 `summary.verdict`(已含首推客户及理由)。
|
|
68
|
+
2. **前 5 名**:每人一行——昵称、意向、需求类型、一句评论原话。
|
|
69
|
+
3. **战报文件**:如果返回里有 `reportFile`,务必告诉用户「完整战报(含可复制的跟进话术)已放到桌面:文件路径」,提醒可以转发给同事照着跟进。
|
|
70
|
+
4. **下一步提示**:提醒完整名单和历史记录在 PPXC 网页端客户池。
|
|
71
|
+
5. **收费墙(重要)**:如果返回里 `paywall.locked` 为真,说明用户是体验版、只解锁了前几个完整客户。要**如实、不啰嗦**地转达:「这次挖到 N 个,体验版先给你看了前 2 个完整的(含话术和联系方式),其余 X 个已锁,开通套餐后全部解锁」。用 `paywall.unlockHint` 的话术,别夸大、别假装全给了。
|
|
72
|
+
|
|
73
|
+
### 第 5.5 步:内容彩蛋(挖到客户后主动提议)
|
|
74
|
+
|
|
75
|
+
每次找客户的返回里都带 `contentAngles`——从这批评论提炼的内容选题方向(每条含:拍什么角度、为什么、客户原话)。汇报完客户名单后,**主动加一句**:
|
|
76
|
+
|
|
77
|
+
> 「顺便——这批评论还告诉了我你的客户最想看什么。要不要我根据它们帮你写下一条视频脚本?」
|
|
78
|
+
|
|
79
|
+
用户答应后,**你自己根据 `contentAngles` 写脚本**(你本就擅长写短视频文案,不需要调任何工具):
|
|
80
|
+
|
|
81
|
+
- 优先用人数最多的那个角度(`contentAngles` 已按人数排序);
|
|
82
|
+
- 把客户原话(`quotes`)用作开场钩子或标题,真实用词最抓人;
|
|
83
|
+
- 一次给 1~3 条不同角度的脚本,每条含:一句话钩子 + 3~5 句口播 + 一句行动引导;
|
|
84
|
+
- 风格贴合平台(抖音口语化、小红书种草感)。
|
|
85
|
+
|
|
86
|
+
这一步是「找客户」到「做内容」的飞轮:评论既挖出了这批客户,又指明了下一条吸引同类客户的内容。**别强推**——用户不接就跳过。
|
|
87
|
+
|
|
88
|
+
### 第 6 步(隔天/复盘场景):查战果、换词
|
|
89
|
+
|
|
90
|
+
用户问「之前挖到的客户怎么样了」「昨天那批有跟进吗」时调 `query_leads`(支持按产品/搜索词/天数/跟进状态筛)。复盘逻辑:连续两轮不出客户的词建议淘汰,回第 3 步补新词。
|
|
91
|
+
|
|
92
|
+
## 硬性注意事项
|
|
93
|
+
|
|
94
|
+
- **额度**:每个平台每天有安全抓取额度(抖音约 20 个词、小红书/快手各约 10 个)。返回 `DAILY_LIMITED` 时如实告诉用户「今天这个平台的安全额度用完了,明天再继续」,不要换平台硬刷同一批词。
|
|
95
|
+
- **验证码**:返回 `VERIFICATION_REQUIRED` 时,平台已弹出验证窗口,请用户人工完成验证后再重试。**绝不**换词重试或反复发起。
|
|
96
|
+
- **间隔**:两次抓取之间系统强制间隔半分钟,返回 `RATE_LIMITED` 时等一下再试,不要连发。
|
|
97
|
+
- **出问题**:用户说「不好用 / 出错了」时调 `export_diagnostics`,告诉用户诊断文件位置,请他发给 PPXC 支持人员。
|
|
98
|
+
- **电力**:返回 `INSUFFICIENT_CREDITS` 时引导用户去 PPXC 网页端充电。
|
|
99
|
+
- 所有工具返回里的 `userHint` 都是写好的人话,可以直接转述给用户。
|
|
100
|
+
|
|
101
|
+
## 汇报示例
|
|
102
|
+
|
|
103
|
+
> 搜完了。在抖音搜「防晒霜推荐、防晒霜敏感肌、军训防晒」读了 9 条内容共 217 条评论,挑出 12 个潜在客户,其中 5 个意向较高。首推「小鹿要去军训」(高意向 · 购买咨询 · 销售分 92 · IP 浙江)。
|
|
104
|
+
>
|
|
105
|
+
> 优先跟这几位:
|
|
106
|
+
> 1. 小鹿要去军训(高意向 · 购买咨询):“求推荐!下周军训,脸超级容易过敏……”
|
|
107
|
+
> 2. Momo(高意向 · 竞品不满):“用了某大牌的防晒整张脸闷痘……”
|
|
108
|
+
> 3. ……
|
|
109
|
+
>
|
|
110
|
+
> 完整战报已放到你桌面(含每个人的跟进话术,可直接复制):PPXC客户战报-xxxx.html,可以转给同事照着跟进。全部 12 人已存入 PPXC 客户池,网页端随时可看。
|