连接Claude Desktop与Spark.re房地产CRM API的Model Context Protocol服务器,支持自然语言查询及写操作,实现完整的销售工作流程自动化。
目的: 使Claude能够通过对话界面直接查询、创建、更新和分析Spark.re CRM数据 开发: 在Claude Code中构建,在Claude Desktop中测试 状态: 已准备好生产使用,具备完整的读取/写入/分析功能
关键特性:
spark-mcp/
├── docs/ # Spark.re API文档(参考材料)
├── src/
│ ├── index.ts # MCP服务器入口点
│ ├── tools/ # 按类别分类的工具处理器
│ │ ├── contacts.ts # 联系人搜索和管理
│ │ ├── projects.ts # 项目列表和详细信息
│ │ ├── interactions.ts # 互动历史
│ │ └── reports.ts # 分析和报告
│ ├── api/
│ │ ├── client.ts # 带有认证的Spark.re API客户端
│ │ └── types.ts # API响应的TypeScript类型
│ └── utils/
│ ├── formatting.ts # 为了可读性而格式化的响应
│ └── errors.ts # 错误处理实用程序
├── dist/ # 编译的JavaScript(生成)
├── package.json
├── tsconfig.json
├── .env # API凭证(git忽略)
├── .env.example # 凭证模板
├── PATTERNS.md # 实现模式和示例
└── README.md # 此文件
# 克隆仓库
git clone <repo-url> spark-mcp
cd spark-mcp
# 安装依赖
npm install
# 创建环境文件
cp .env.example .env
# 编辑.env并添加你的SPARK_API_KEY
# 构建项目
npm run build
# 验证构建
ls dist/ # 应该看到index.js和其他编译文件
npm init -y
npm install @modelcontextprotocol/sdk dotenv
npm install -D typescript @types/node
创建tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
更新package.json:
{
"type": "module",
"scripts": {
"build": "tsc",
"watch": "tsc --watch",
"start": "node dist/index.js"
}
}
创建.env:
SPARK_API_KEY=your_api_key_here
SPARK_API_BASE_URL=https://api.spark.re/v1
创建.env.example(用于git):
SPARK_API_KEY=your_api_key_here
SPARK_API_BASE_URL=https://api.spark.re/v1
API客户端 (src/api/client.ts)
服务器设置 (src/index.ts)
类型 (src/api/types.ts)
/docs/api/中的字段定义按价值顺序实现这些工具:
每个工具需要:
ListToolsRequestSchema处理器中/tools/*.ts文件中的处理器函数/utils/formatting.ts中的响应格式化/utils/errors.ts进行错误处理参见PATTERNS.md中的每个组件的完整示例。
响应格式化 (src/utils/formatting.ts)
错误处理 (src/utils/errors.ts)
完整的Spark.re API文档位于/docs/api/和/docs/knowledge-base/。
需实现的关键端点:
GET /contacts - 联系人搜索GET /contacts/:id - 联系人详情GET /projects - 项目列表GET /projects/:id/analytics - 项目统计数据GET /interactions - 互动历史参考文档以了解:
关键发现: Spark API根据使用的端点返回不同深度的数据:
GET /contacts)返回优化性能的“轻量级”联系人数据:
id、first_name、last_name、email、phone、created_atratings、projects、notes、team_members、自定义字段GET /contacts/{id})返回包含所有嵌套关系的完整联系人数据:
ratings数组、projects、notes、team_members[{id, value, color, position}]问题: 如果你需要多个联系人的评分,列表端点不会包含它们。
解决方案1 - 单独获取(用于get_sales_funnel):
// 分批次获取联系人
const batchSize = 10; // 并发请求
for (let i = 0; i < contactIds.length; i += batchSize) {
const batch = contactIds.slice(i, i + batchSize);
const batchPromises = batch.map(id =>
sparkApi.get(`/contacts/${id}`)
);
const results = await Promise.all(batchPromises);
}
解决方案2 - 互动为基础的工作方法:
// 通过互动获取活跃联系人
const interactions = await sparkApi.get('/interactions?project_id=2855');
const contactIds = [...new Set(interactions.map(i => i.contact_id))];
// 然后获取单个联系人的完整数据
访问评分:
// ❌ 错误 - 评分不是一个直接属性
const rating = contact.rating;
// ✅ 正确 - 评分是一个数组
const rating = contact.ratings?.[0]?.value;
此行为在我们的代码中有记录:
formatContactsResponse()handleGetContactDetails()handleGetSalesFunnel()批量获取所有请求都需要Bearer token:
headers: {
'Authorization': `Bearer ${process.env.SPARK_API_KEY}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
使用清晰、行动导向的名称:
search_contacts、get_project_analytics、list_projectscontacts、getData、fetch始终为可读性格式化响应:
坏: 返回原始JSON 好: 格式化为带上下文的结构化文本
参见PATTERNS.md中的格式化示例。
返回有用的错误消息:
处理常见情况:
# 编译TypeScript
npm run build
# 测试服务器
node dist/index.js
编辑Claude Desktop配置:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"spark-re": {
"command": "node",
"args": ["/Users/dannybreckenridge/spark-mcp/dist/index.js"],
"env": {
"SPARK_API_KEY": "your_api_key_here"
}
}
}
}
如果工具不起作用:
npm run build是否无错误完成当构建这个项目时:
新潜在客户
↓
[create_update_contact] ──→ 联系人创建(ID:123)
↓
初次通话/会议
↓
[log_interaction] ──→ 活动记录
↓
跟进笔记
↓
[add_contact_note] ──→ 笔记添加
↓
[search_contacts] ──→ 查看联系人历史
↓
[get_contact_details] ──→ 包含所有笔记和互动的完整概况
销售代理在开放日遇到潜在买家,并希望将其添加到CRM中:
用户:“我在Mira Mar开放日遇到了Sarah Johnson。她的电子邮件是sarah.j@email.com,
电话是941-555-1234。她对两居室单元感兴趣,并通过我们的网站找到我们。你能把她加到系统里吗?”
Claude使用create_update_contact:
- 创建具有姓名、电子邮件、电话的联系人
- 设置项目ID为Mira Mar(2855)
- 设置营销来源为“网站”
- 返回联系人ID:8103687
用户:“很好!我刚刚与她进行了30分钟的电话讨论了平面图。你能记录下来吗?”
Claude使用log_interaction:
- contact_id:8103687
- project_id:2855
- interaction_type_id:1(电话)
- 备注:“30