内容
# Teamleader Focus MCP
一款封装 **Teamleader Focus CRM API** 的 [模型上下文协议(MCP)](https://modelcontextprotocol.io/) 服务器。赋予 AI 助手(Claude Code、Claude Desktop、Cursor 等)管理联系人、公司、交易、任务、事件、发票、时间跟踪和项目的能力,包括用于自动记录时间的智能任务解决工作流。
灵感来自 [globodai-group/mcp-teamleader](https://github.com/globodai-group/mcp-teamleader)。重写并扩展了完整的 API 覆盖、时间跟踪、项目 v2 和智能缓存优先任务解决。
---
## 功能
- **112 种工具**,涵盖完整的 Teamleader Focus API
- **联系人** — 完整的 CRUD + 标签/取消标签 + 公司链接管理
- **公司** — 完整的 CRUD + 标签/取消标签
- **交易** — 完整的 CRUD + 胜利/失败/移动 + 管道/阶段/来源管理
- **任务** — 独立任务:完整的 CRUD + 完成/重新打开/安排
- **事件** — 列表、获取、创建、更新、取消
- **会议** — 完整的 CRUD + 完成 + 报告
- **发票** — 完整的生命周期:草稿 → 预订 → 发送 → 付款 → 信用
- **工单** — 完整的 CRUD + 消息 + 回复/内部
- **时间跟踪** — 列表、添加、更新、删除 + 启动/停止/恢复计时器 + 时间表
- **项目 v2** — 完整的 CRUD + 组 + 任务 + 关系 + 生命周期
- **订阅** — 完整的 CRUD + 停用
- **报价** — 完整的 CRUD + 接受/发送/下载
- **物料** — 完整的 CRUD + 分配/取消分配/复制
- **文件** — 列表、获取、下载、删除、上传
- **笔记** — 列表、创建、更新
- **通话** — 列表、获取、添加、更新、完成
- **智能解决** — 缓存优先公司 > 项目 > 组 > 任务导航 + 时间记录
- **OAuth2** — 基于浏览器的登录流程 + 自动令牌刷新和轮换
---
## 先决条件
一个具有 API 访问权限的 **Teamleader Focus** 账户:
1. 访问 [开发者门户](https://developer.focus.teamleader.eu/)
2. 注册一个集成以获取您的 **客户端 ID** 和 **客户端密钥**
3. 完成 OAuth2 流程以获取 **刷新令牌**(参见 [QUICKSTART.md](QUICKSTART.md))
---
## 快速入门
### 选项 A — npx(推荐,无需安装)
将以下内容添加到 `%APPDATA%\Claude\claude_desktop_config.json`(Windows)或 `~/.claude.json`:
```json
{
"mcpServers": {
"teamleader": {
"command": "npx",
"args": ["-y", "@tailormade/teamleader-focus-mcp"],
"env": {
"TEAMLEADER_CLIENT_ID": "your_client_id",
"TEAMLEADER_CLIENT_SECRET": "your_client_secret",
"TEAMLEADER_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}
```
### 选项 B — 从源代码构建
```bash
git clone https://github.com/tailormade-eu/Tailormade.TeamleaderFocusMcp.git
cd Tailormade.TeamleaderFocusMcp
npm install
npm run build
```
将以下内容添加到您的 Claude 配置中:
```json
{
"mcpServers": {
"teamleader": {
"command": "node",
"args": ["C:\\ABSOLUTE\\PATH\\TO\\dist\\index.js"],
"env": {
"TEAMLEADER_CLIENT_ID": "your_client_id",
"TEAMLEADER_CLIENT_SECRET": "your_client_secret",
"TEAMLEADER_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}
```
---
## 配置
### 环境变量
| 变量 | 是否必需 | 描述 |
| --- | --- | --- |
| `TEAMLEADER_CLIENT_ID` | 是 | OAuth2 客户端 ID |
| `TEAMLEADER_CLIENT_SECRET` | 是 | OAuth2 客户端密钥 |
| `TEAMLEADER_REFRESH_TOKEN` | 否 | OAuth2 刷新令牌(自动轮换,持久化到 `~/.teamleader-tokens.json`)。如果省略,则仅 `teamleader_login` 可用 — 使用它通过浏览器获取令牌。 |
### 缓存文件
| 文件 | 用途 |
| --- | --- |
| `~/.teamleader-cache.json` | 实体缓存(公司、项目、组、任务、任务树) |
| `~/.teamleader-tasks-{slug}.yaml` | 由 `teamleader_load_tasks` 编写的完整任务树(包含所有 ID) |
| `~/.teamleader-tokens.json` | 持久化的 OAuth2 令牌(自动管理) |
---
## 可用工具
### 联系人
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_contacts` | 列出联系人,可选按术语、标签或 `updated_since` 过滤 |
| `teamleader_get_contact` | 获取特定联系人的完整详细信息,ID |
| `teamleader_create_contact` | 创建新联系人(名字,姓氏,电子邮件,电话,标签,语言) |
| `teamleader_update_contact` | 更新现有联系人 |
| `teamleader_delete_contact` | 删除联系人 |
| `teamleader_link_contact_to_company` | 将联系人链接到公司(可选职位/决策者) |
| `teamleader_unlink_contact_from_company` | 将联系人从公司取消链接 |
| `teamleader_update_contact_company_link` | 更新现有链接的职位或决策者 |
| `teamleader_tag_contact` | 向联系人添加标签 |
| `teamleader_untag_contact` | 从联系人中删除标签 |
### 公司
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_companies` | 列出公司,可选按术语、标签或增值税编号过滤 |
| `teamleader_get_company` | 获取特定公司的完整详细信息,ID |
| `teamleader_create_company` | 创建新公司(名称,电子邮件,电话,增值税,网站,标签) |
| `teamleader_update_company` | 更新现有公司 |
| `teamleader_delete_company` | 删除公司 |
| `teamleader_tag_company` | 向公司添加标签 |
| `teamleader_untag_company` | 从公司中删除标签 |
### 交易
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_deals` | 列出交易,可选按术语、阶段或负责人过滤 |
| `teamleader_get_deal` | 获取特定交易ID的完整详细信息 |
| `teamleader_create_deal` | 创建新交易(标题,客户,阶段,价值,概率) |
| `teamleader_update_deal` | 更新现有交易(标题,价值,日期,负责人) |
| `teamleader_delete_deal` | 删除交易 |
| `teamleader_lose_deal` | 将交易标记为失败(可选原因ID + 额外信息) |
| `teamleader_win_deal` | 将交易标记为已赢 |
| `teamleader_move_deal` | 将交易移动到不同阶段 |
| `teamleader_list_lost_reasons` | 列出可用的失败原因(用于交易失败) |
| `teamleader_list_deal_phases` | 列出交易阶段(用于交易创建/移动) |
| `teamleader_list_deal_sources` | 列出交易来源(用于交易创建) |
| `teamleader_list_deal_pipelines` | 列出交易管道 |
| `teamleader_create_deal_pipeline` | 创建交易管道 |
| `teamleader_update_deal_pipeline` | 更新交易管道 |
| `teamleader_delete_deal_pipeline` | 删除交易管道 |
| `teamleader_duplicate_deal_pipeline` | 复制交易管道 |
| `teamleader_mark_deal_pipeline_default` | 将管道标记为默认 |
| `teamleader_create_deal_phase` | 创建交易阶段 |
| `teamleader_update_deal_phase` | 更新交易阶段 |
| `teamleader_delete_deal_phase` | 删除交易阶段 |
| `teamleader_duplicate_deal_phase` | 复制交易阶段 |
| `teamleader_move_deal_phase` | 重新排序交易阶段 |
### 任务(独立)
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_tasks` | 列出任务,可选过滤和分页 |
| `teamleader_create_task` | 创建新任务 |
| `teamleader_get_task` | 获取特定任务ID的完整详细信息 |
| `teamleader_update_task` | 更新任务标题、描述、截止日期或分配者 |
| `teamleader_delete_task` | 删除任务 |
| `teamleader_complete_task` | 将任务标记为已完成 |
| `teamleader_reopen_task` | 重新打开已完成的任务 |
| `teamleader_schedule_task` | 将任务安排为日历事件 |
### 事件
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_events` | 列出日历事件,可选日期范围过滤 |
| `teamleader_get_event` | 获取特定事件ID的完整详细信息 |
| `teamleader_create_event` | 创建新的日历事件(标题,活动类型,开始/结束,参加者) |
| `teamleader_update_event` | 更新现有事件 |
| `teamleader_cancel_event` | 取消日历事件 |
### 会议
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_meetings` | 列出会议,可选按员工、日期范围或术语过滤 |
| `teamleader_get_meeting` | 获取特定会议的完整详细信息 |
| `teamleader_schedule_meeting` | 安排新会议,附带与会者和可选客户/交易 |
| `teamleader_update_meeting` | 更新会议详情 |
| `teamleader_complete_meeting` | 将会议标记为已完成 |
| `teamleader_delete_meeting` | 删除会议 |
| `teamleader_create_meeting_report` | 创建与联系人、公司或交易相关的报告 |
### 发票
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_invoices` | 列出发票,可选按状态、日期范围或部门过滤 |
| `teamleader_get_invoice` | 获取特定发票ID的完整详细信息 |
| `teamleader_create_invoice` | 创建新的草稿发票,附带项目 |
| `teamleader_book_invoice` | 预订草稿发票(→ 待处理) |
| `teamleader_send_invoice` | 通过电子邮件发送发票 |
| `teamleader_send_invoice_peppol` | 通过 Peppol 电子发票发送发票 |
| `teamleader_delete_invoice` | 删除草稿发票 |
| `teamleader_update_invoice` | 更新草稿发票 |
| `teamleader_update_booked_invoice` | 更新已预订发票的有限字段 |
| `teamleader_register_payment` | 在发票上注册付款 |
| `teamleader_remove_payments` | 从发票中删除所有付款 |
| `teamleader_copy_invoice` | 将发票复制到新的草稿中 |
| `teamleader_credit_invoice` | 创建完整的信用票 |
| `teamleader_credit_invoice_partially` | 创建部分信用票 |
| `teamleader_download_invoice` | 获取临时下载 URL(PDF/UBL) |
| `teamleader_list_mail_templates` | 列出邮件模板(用于发送发票) |
| `teamleader_list_payment_methods` | 列出付款方式(用于注册付款) |
### 工单
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_tickets` | 列出工单,可选按客户、项目或状态过滤 |
| `teamleader_get_ticket` | 获取特定工单的完整详细信息 |
| `teamleader_create_ticket` | 创建新工单(主题,客户,团队,分配者) |
| `teamleader_update_ticket` | 更新工单主题、描述、状态或分配者 |
| `teamleader_list_ticket_messages` | 列出工单上的消息(按类型或日期过滤) |
| `teamleader_get_ticket_message` | 获取单个消息ID |
| `teamleader_reply_ticket` | 添加客户可见的回复到工单 |
| `teamleader_internal_message_ticket` | 添加内部/私人消息到工单 |
| `teamleader_import_ticket_message` | 将原始消息导入工单 |
### 订阅
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_subscriptions` | 列出 recurring 发票,可选过滤 |
| `teamleader_get_subscription` | 获取订阅详情 |
| `teamleader_create_subscription` | 创建新的 recurring 发票 |
| `teamleader_update_subscription` | 更新订阅设置 |
| `teamleader_deactivate_subscription` | 停用订阅 |
### 报价
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_quotations` | 列出报价,可选过滤 |
| `teamleader_get_quotation` | 获取报价详情 |
| `teamleader_create_quotation` | 创建新报价 |
| `teamleader_update_quotation` | 更新现有报价 |
| `teamleader_delete_quotation` | 删除报价 |
| `teamleader_accept_quotation` | 接受报价 |
| `teamleader_send_quotation` | 通过电子邮件发送报价 |
| `teamleader_download_quotation` | 获取临时下载 URL |
### 信用票
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_credit_notes` | 列出信用票,可选过滤 |
| `teamleader_get_credit_note` | 获取信用票详情 |
| `teamleader_download_credit_note` | 获取临时下载 URL |
| `teamleader_send_credit_note_peppol` | 通过 Peppol 发送信用票 |
### 物料
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_materials` | 列出物料,可选过滤 |
| `teamleader_get_material` | 获取物料详情 |
| `teamleader_create_material` | 创建新物料 |
| `teamleader_update_material` | 更新物料 |
| `teamleader_delete_material` | 删除物料 |
| `teamleader_assign_material` | 将物料分配给项目任务 |
| `teamleader_unassign_material` | 将物料从任务取消分配 |
| `teamleader_duplicate_material` | 复制物料 |
### 通话
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_calls` | 列出通话,可选过滤 |
| `teamleader_get_call` | 获取通话详情 |
| `teamleader_add_call` | 添加新通话 |
| `teamleader_update_call` | 更新通话 |
| `teamleader_complete_call` | 将通话标记为已完成 |
### 订单
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_orders` | 列出订单,可选过滤 |
| `teamleader_get_order` | 获取订单详情 |
### 时间跟踪
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_timetracking` | 列出时间记录,可选按用户、日期范围或主题过滤 |
| `teamleader_get_timetracking` | 获取特定时间记录ID的详情 |
| `teamleader_add_timetracking` | 添加新的时间记录(用户,工作类型,开始/结束,主题) |
| `teamleader_update_timetracking` | 更新现有时间记录 |
| `teamleader_delete_timetracking` | 删除时间记录 |
| `teamleader_start_timer` | 启动正在运行的计时器(每个用户一个活动计时器) |
| `teamleader_stop_timer` | 停止当前正在运行的计时器 |
| `teamleader_get_current_timer` | 获取当前正在运行的计时器 |
| `teamleader_update_timer` | 更新正在运行的计时器(工作类型,主题,描述) |
| `teamleader_resume_timetracking` | 从现有时间记录开始新的计时器 |
| `teamleader_timesheet` | 每日时间表 — 某日期的所有记录,按项目/任务分组。格式:md,beauty,manictime |
### 项目 v2
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_projects_v2` | 列出项目,可选按状态、公司或搜索词过滤 |
| `teamleader_get_project_v2` | 获取特定项目ID的完整详细信息 |
| `teamleader_create_project_v2` | 创建新项目,附带客户、日期和负责人 |
| `teamleader_update_project_v2` | 更新现有项目 |
| `teamleader_close_project_v2` | 关闭项目 |
| `teamleader_reopen_project_v2` | 重新打开已关闭的项目 |
| `teamleader_delete_project_v2` | 删除项目 |
| `teamleader_duplicate_project_v2` | 复制项目到新的草稿 |
| `teamleader_add_project_customer` | 将客户(公司/联系人)添加到项目 |
| `teamleader_remove_project_customer` | 从项目中删除客户 |
| `teamleader_add_project_deal` | 将交易链接到项目 |
| `teamleader_remove_project_deal` | 将交易从项目取消链接 |
| `teamleader_add_project_owner` | 将所有者/成员添加到项目 |
| `teamleader_remove_project_owner` | 从项目中删除所有者/成员 |
| `teamleader_assign_project` | 将用户或团队分配给项目 |
| `teamleader_unassign_project` | 将用户或团队从项目取消分配 |
| `teamleader_list_project_groups` | 列出项目组(阶段/里程碑)用于项目 |
| `teamleader_create_project_group` | 在项目中创建新的组(阶段) |
| `teamleader_update_project_group` | 更新项目组标题、描述或日期 |
| `teamleader_list_project_tasks_v2` | 列出项目或项目组的任务 |
| `teamleader_create_project_task_v2` | 在项目或组中创建任务 |
| `teamleader_complete_project_task` | 将项目任务标记为已完成 |
| `teamleader_reopen_project_task` | 重新打开已完成的项目任务 |
| `teamleader_delete_project_task` | 删除项目任务 |
| `teamleader_remove_task_from_group` | 从组中删除任务 |
| `teamleader_add_project_line_to_group` | 将任务或物料添加到组 |
| `teamleader_list_project_lines` | 列出项目中的所有记录(任务+物料) |
| `teamleader_get_project_group` | 获取项目组详情 |
| `teamleader_duplicate_project_group` | 复制项目组 |
| `teamleader_assign_project_group` | 将用户/团队分配给项目组 |
| `teamleader_unassign_project_group` | 从项目组取消分配 |
| `teamleader_update_project_task` | 更新项目任务 |
| `teamleader_get_project_task` | 获取项目任务详情 |
| `teamleader_assign_project_task` | 将用户分配给项目任务 |
| `teamleader_unassign_project_task` | 从项目任务取消分配 |
| `teamleader_duplicate_project_task` | 复制项目任务 |
| `teamleader_add_project_quotation` | 将报价链接到项目 |
| `teamleader_remove_project_quotation` | 将报价从项目取消链接 |
### 用户
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_users` | 列出账户中的所有用户 |
| `teamleader_get_user` | 获取特定用户ID的完整详细信息 |
### 部门
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_departments` | 列出所有部门 |
| `teamleader_get_department` | 获取特定部门的完整详细信息 |
### 文件
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_files` | 列出附加到联系人、公司、交易、发票、项目或工单的文件 |
| `teamleader_get_file` | 获取文件元数据(名称、大小、MIME类型、上传者) |
| `teamleader_download_file` | 获取文件的临时下载 URL |
| `teamleader_delete_file` | 删除文件 |
| `teamleader_upload_file` | 将文件上传到实体(两步:获取 URL,然后上传) |
### 笔记
| 工具 | 描述 |
| --- | --- |
| `teamleader_list_notes` | 列出联系人、公司、交易或项目的笔记 |
| `teamleader_create_note` | 在联系人、公司、交易或项目上创建笔记 |
| `teamleader_update_note` | 更新现有笔记ID |
### 查找列表
| 工具 | 描述 |
|------|-------------|
| `teamleader_list_activity_types` | 列出活动类型(事件创建需要) |
| `teamleader_list_tax_rates` | 列出税率(发票项目需要) |
| `teamleader_list_payment_terms` | 列出付款条件(发票需要) |
| `teamleader_list_ticket_statuses` | 列出工单状态(工单更新需要) |
| `teamleader_list_products` | 列出产品(发票项目需要) |
| `teamleader_list_product_categories` | 列出产品类别 |
| `teamleader_list_work_types` | 列出工作类型(时间跟踪需要) |
| `teamleader_list_teams` | 列出团队(工单需要) |
| `teamleader_list_tags` | 列出账户中使用的所有标签 |
| `teamleader_list_expenses` | 列出费用条目,支持可选筛选 |
| `teamleader_list_business_types` | 列出商业类型 |
| `teamleader_list_call_outcomes` | 列出通话结果 |
| `teamleader_list_currencies` | 列出货币和汇率 |
| `teamleader_list_document_templates` | 列出文档模板 |
| `teamleader_list_commercial_discounts` | 列出商业折扣 |
| `teamleader_list_lost_reasons` | 列出丢失原因 |
| `teamleader_list_price_lists` | 列出价格列表 |
| `teamleader_list_units_of_measure` | 列出计量单位 |
| `teamleader_list_withholding_tax_rates` | 列出预扣税率 |
| `teamleader_list_bookkeeping_submissions` | 列出会计提交 |
| `teamleader_add_product` | 添加产品 |
| `teamleader_get_product` | 获取产品详情 |
| `teamleader_update_product` | 更新产品 |
| `teamleader_delete_product` | 删除产品 |
### 智能解析(缓存优先)
这些工具实现了推荐的时间记录工作流程。它们维护本地缓存以避免重复的 API 调用。
| 工具 | 描述 |
|------|-------------|
| `teamleader_find_task` | 交互式导航公司 > 项目 > 分组 > 任务层次结构。编号选择多个选项。如果未找到,任务会自动创建。 |
| `teamleader_log_time` | 为任务注册时间。从缓存中解析。支持重复数据删除和重叠检测。 |
| `teamleader_load_tasks` | 加载和显示公司项目 > 分组 > 任务树。缓存优先(30分钟 TTL)。写入包含所有 ID 的 YAML。 |
| `teamleader_task_action` | 任务维护操作:关闭、创建、移动时间条目或删除项目分组。 |
| `teamleader_cache_stats` | 显示缓存统计信息和所有缓存任务。 |
| `teamleader_clear_cache` | 清除整个本地缓存(强制下一次调用进行新的 API 查找)。 |
### 身份验证
| 工具 | 描述 |
|------|-------------|
| `teamleader_login` | 启动 OAuth 登录流程 — 打开浏览器进行 Teamleader 授权,在 localhost:19836 捕获回调,将代码兑换为令牌,持久化到 `~/.teamleader-tokens.json`。用于初始设置或刷新令牌恢复。 |
---
## 推荐工作流程:时间记录
### 选项 A — 交互式(首次使用或未知任务)
```
1. teamleader_find_task(company_name="Acme", group_name="Sprint 12", task_name="Bug fix login")
→ 解析公司 > 项目 > 分组 > 任务,缓存结果
2. teamleader_log_time(company_name="Acme", task_name="Bug fix login", started_on="09:00", ended_on="11:30")
→ 从缓存读取,记录时间条目,检查重复数据
```
### 选项 B — 先加载树(推荐用于多个日志条目的会话)
```
1. teamleader_load_tasks(company_name="Acme")
→ 获取完整树,写入 ~/.teamleader-tasks-acme.yaml,显示摘要
2. teamleader_load_tasks(company_name="Acme", visual=true)
→ 显示编号的 ASCII 树
公司:Acme Corp
=== 项目 Alpha ===
[Sprint 12]
1. Bug fix login (待处理)
2. Add unit tests (进行中)
3. teamleader_load_tasks(company_name="Acme", task_selection=1)
→ 缓存任务 #1 以直接使用
4. teamleader_log_time(company_name="Acme", task_name="Bug fix login", started_on="09:00", ended_on="11:30")
→ 从缓存解析,记录时间
```
### 选项 C — 直接 task_id(最快,当 ID 已知时)
```
teamleader_log_time(company_name="Acme", task_id="abc-123", started_on="09:00", ended_on="11:30")
```
---
## 智能解析:`teamleader_find_task` 参数
| 参数 | 是否必需 | 描述 |
|-----------|----------|-------------|
| `company_name` | 是 | 公司名称的部分匹配 |
| `group_name` | 是 | 分组/阶段名称的部分匹配(在所有项目中搜索) |
| `task_name` | 是 | 任务名称的部分匹配(如果未找到则自动创建) |
| `project_selection` | 自动 | 当找到多个项目时,按编号选择项目 |
| `task_selection` | 自动 | 从列出的选项中按编号选择任务 |
| `confirm_create_group` | 自动 | 确认创建新分组(需要 project_selection) |
| `confirm_create_project` | 自动 | 确认创建新项目 |
| `only_open` | 可选 | 仅显示开放任务 — 待处理,在进行中,暂停(默认:true) |
| `_company_id` | 内部 | 解析的公司 ID,在调用之间传递以避免重新解析 |
| `_project_id` | 内部 | 解析的项目 ID |
| `_group_id` | 内部 | 解析的分组 ID |
| `_group_title` | 内部 | 解析的分组标题 |
---
## 智能解析:`teamleader_log_time` 参数
| 参数 | 是否必需 | 描述 |
|-----------|----------|-------------|
| `company_name` | 是 | 公司名称的部分匹配 |
| `task_name` | 条件 | 任务名称(部分匹配,必须在缓存中)。如果未提供 task_id,则需要。 |
| `task_id` | 条件 | 直接任务 ID — 跳过缓存查找。当从 load_tasks 中已知 ID 时使用。 |
| `started_on` | 是 | 开始时间:ISO 8601,`YYYY-MM-DD HH:MM`,或 `HH:MM`(使用今天) |
| `ended_on` | 是 | 结束时间:与 started_on 相同的格式 |
| `description` | 可选 | 已完成工作描述 |
| `work_type_id` | 可选 | 覆盖默认工作类型 |
| `date` | 可选 | HH:MM 格式的日期(YYYY-MM-DD,默认:今天) |
| `force` | 可选 | 完全跳过重复数据删除和重叠检查 |
| `confirm_overlap` | 可选 | 当检测到与另一个任务重叠时,确认注册 |
---
## 重复数据删除规则(`teamleader_log_time`)
| 规则 | 条件 | 操作 |
|------|-----------|--------|
| 完全重复 | 相同的任务 ID,相同的开始时间(精确到秒) | 阻止并报错 |
| 重叠 | 与现有条目的时间范围重叠 | 警告,询问 `confirm_overlap=true` |
| 强制 | `force=true` | 跳过所有检查 |
---
## `teamleader_load_tasks` 参数
| 参数 | 描述 |
|-----------|-------------|
| `company_name` | 要加载的公司(部分匹配) |
| `project_filter` | 按名称筛选项目(部分匹配) |
| `group_filter` | 按名称筛选分组(部分匹配) |
| `only_open` | 仅包括开放任务(默认:true) |
| `visual` | 显示 ASCII 树和编号任务,而不是摘要 |
| `task_selection` | 缓存特定任务,按编号(从视觉输出) |
| `force_refresh` | 强制从 API 重新加载,绕过 30 分钟缓存 |
| `_company_id` | 内部:解析的公司 ID |
---
## 缓存 TTL
| 实体 | TTL |
|--------|-----|
| active_user | 无过期(仅手动清除) |
| work_types | 7 天 |
| companies | 24 小时 |
| projects | 2 小时 |
| groups | 1 小时 |
| tasks | 1 小时 |
| task_trees | 30 分钟 |
自动修剪:过期条目在每次缓存写入时被删除。
---
## Teamleader API 注意事项
这些对于未来的开发或调试至关重要。
### `projects-v2/projectLines.list`
- `project_id` 必须在请求体中为**顶级** — 而不是在 `filter` 中
- `project_group_id` 不是服务器端筛选器 — 必须在 `l.group?.id` 上进行客户端筛选
### `projects-v2/tasks.list`
- 按 `ids` 数组筛选在服务器端工作
- 状态不是服务器端筛选器 — 在状态字段上进行客户端筛选
### `projects-v2/tasks.create`
- 使用 `group_id`(而非 `project_group_id`)
- 使用 `tasks.create` 端点(而非 `projectLines.create`)
### `timeTracking.list`
- 返回 `subject.type: "todo"` — ID 与 `nextgenTask` ID 不同
- 必须按**开始时间**(精确到秒)匹配,而不是按主题 ID 进行重复数据删除
### `invoices.registerPayment`
- 使用 `paid_at`(而非 `payment_date`)
- 支付是一个嵌套对象:`{ payment: { amount: { amount, currency }, paid_at, payment_method_id } }`
### `invoices.creditPartially`
- 行项目税使用 `unit_price.tax: "excluding"`(不是货币字段)
### `tickets.list`
- 客户筛选使用 `relates_to: { type, id }`(而非 `customer_id`)
- 状态筛选使用 `exclude.status_ids` 数组(无直接状态筛选)
### `projects.close`
- 需要 `closing_strategy`: `"mark_tasks_and_materials_as_done"` 或 `"none"`
### `projects.delete`
- 需要 `delete_strategy`: `"unlink_tasks_and_time_trackings"` 或 `"delete_tasks_and_time_trackings"`
### `projects.assign` / `projects.addCustomer`
- `assign` 使用 `assignee: { type, id }` 对象
- `addCustomer` / `removeCustomer` 使用 `customer: { type, id }` 对象
### `projectGroups.update`
- 使用 `start_date` / `end_date`(而非 `starts_on` / `due_on`)
### `files.upload`
- 两步过程:调用 `files.upload` 获取预签名 URL,然后直接向该 URL 发送二进制数据(不需要身份验证)
### 一般
- 所有 API 调用均使用 **POST** 和 JSON 正文
- 基本 URL:`https://api.focus.teamleader.eu`
- 分页使用 `page.number` 和 `page.size`
---
## 文件结构
```
src/
api/
auth.ts — OAuth2 令牌管理(自动旋转,持久化到 ~/.teamleader-tokens.json)
client.ts — HTTP 客户端(所有 POST 请求)
cache.ts — 缓存类型,TTL 常量,CRUD 函数,任务树操作
tools/
resolve.ts — 智能工具:find_task, log_time, load_tasks, task_action, cache_stats, clear_cache
contacts.ts — 联系人 CRUD + 标签/链接
companies.ts — 公司 CRUD + 标签
deals.ts — 交易 CRUD + 管道/阶段/来源
tasks.ts — 独立任务
events.ts — 事件
meetings.ts — 会议 + 报告
invoices.ts — 发票 + 支付 + 信用
timetracking.ts — 时间跟踪 + 计时器 + 时间表
projects.ts — 项目 v2 + 分组 + 行 + 项目任务
tickets.ts — 工单 + 消息
subscriptions.ts — 订阅
quotations.ts — 报价
creditnotes.ts — 信用笔记
materials.ts — 材料
calls.ts — CRM 通话
orders.ts — 订单
files.ts — 文件
notes.ts — 注释
users.ts — 用户
departments.ts — 部门
lookups.ts — 所有参考数据列表
login.ts — OAuth 登录流程
index.ts — MCP 服务器入口点,工具注册
docs/
api/ — 完整的 Teamleader Focus API 文档(360 页,抓取 2026-03-05)
BusinessLogica/ — 每个领域的业务逻辑文档
```
---
## 开发
```bash
# 安装
npm install
# 构建(TypeScript → dist/)
npm run build
# 仅类型检查
npm run typecheck
# 开发模式(监视)
npm run dev
# 使用 MCP 检查器测试
npx @modelcontextprotocol/inspector node dist/index.js
```
---
## 参考
- [Teamleader Focus API](https://developer.focus.teamleader.eu/) — OAuth2 REST API(所有 POST,JSON 正文)
- [Model Context Protocol](https://modelcontextprotocol.io/) — MCP 规范
- [globodai-group/mcp-teamleader](https://github.com/globodai-group/mcp-teamleader) — 原始灵感
- 本地抓取的 API 文档:`docs/api/`(360 页,更新于 2026-03-05)
## API 参考
- 基本 URL:`https://api.focus.teamleader.eu`
- 所有端点均使用 POST 和 JSON 正文
- 身份验证:OAuth2,自动令牌刷新
---
## 许可证
[MIT](LICENSE)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器