svc-mcp线性
带钥匙卡身份验证的线性MCP服务器。
此服务器使用Keycard SDK来处理OAuth身份验证,为每个用户提供对Linear API的安全访问。
建筑
┌─────────────┐ ┌─────────────┐
│ MCP Client │────▶│ This Server │────▶ Linear API
└─────────────┘ └─────────────┘
│
┌──────▼──────┐
│ Keycard │
│ (OAuth) │
└─────────────┘Keycard处理OAuth令牌交换。每个用户都通过Keycard进行身份验证,服务器通过 @auth_provider.grant() 装饰师。
工具
| 工具 | 类型 | 描述 |
|---|---|---|
my_issues | 查询 | 获取分配给经过身份验证的用户的问题 |
my_created_issues | 查询 | 获取已验证用户创建的问题(包括未分配/分类) |
issue | 查询 | 通过标识符获取特定问题的详细信息(例如,ENG-123) |
search | 查询 | 按文本查询搜索问题(搜索标题和描述) |
list_projects | 查询 | 列出项目,可选择按团队筛选 |
list_project_updates | 查询 | 获取项目的最新状态更新 |
create_issue | 突变 | 创建新问题(需要team_id和title,可选project_id) |
update_issue | 突变 | 更新问题字段(标题、描述、优先级等) |
update_status | 突变 | 更改问题工作流状态 |
create_project | 突变 | 创建新项目(需要名称和team_id) |
create_project_update | 突变 | 发布项目的状态更新 |
states | 查询 | 列出团队的可用工作流状态 |
工具详细信息
my_issues
返回分配给已验证用户的问题。
答复:
{
"success": true,
"issues": [
{
"id": "uuid",
"identifier": "ENG-123",
"title": "Fix login bug",
"description": "...",
"state": { "name": "In Progress" },
"priority": 2,
"project": { "name": "Backend" }
}
],
"count": 1
}my_created_issues
返回由经过身份验证的用户创建的问题。不像 my_issues,这包括 用户提交但未分配给自己的问题,例如,门票放在 团队的Triage收件箱。
答复:
{
"success": true,
"issues": [
{
"id": "uuid",
"identifier": "AGE-200",
"title": "New ticket in triage",
"state": { "name": "Triage", "type": "triage" },
"priority": 0,
"project": null,
"team": { "id": "team-uuid", "name": "Agent Dev" },
"assignee": null
}
],
"count": 1
}issue
获取特定问题的详细信息。
参数:
identifier(必填):问题标识符,如“ENG-123”
答复:
{
"success": true,
"issue": {
"id": "uuid",
"identifier": "ENG-123",
"title": "Fix login bug",
"description": "...",
"state": { "id": "state-uuid", "name": "In Progress" },
"priority": 2,
"labels": { "nodes": [{ "name": "bug" }] },
"assignee": { "name": "John Doe", "email": "john@example.com" },
"team": { "id": "team-uuid", "name": "Engineering" },
"comments": { "nodes": [...] }
}
}search
按文本查询搜索问题。
参数:
query(必填):搜索文本(不区分大小写,搜索标题和描述)
list_projects
列出线性项目。
参数:
team_id(可选):按以下方式筛选项目的团队UUID
答复:
{
"success": true,
"projects": [
{
"id": "project-uuid",
"name": "Backend Refactor",
"slugId": "backend-refactor",
"state": "started",
"teams": {
"nodes": [
{ "id": "team-uuid", "name": "Engineering" }
]
}
}
],
"count": 1
}list_project_updates
获取项目的最新状态更新。
参数:
project_id(必填):项目UUID(从list_projects获取)limit(可选):要返回的更新数(默认值10)
create_issue
创建新问题。
参数:
team_id(必填):团队UUIDtitle(必填):发行标题description(可选):问题描述(支持markdown)priority(可选):0=无,1=紧急,2=高,3=中,4=低state_id(可选):初始工作流状态UUIDassignee_id(可选):受让人用户UUIDproject_id(可选):要分配问题的项目UUID(从获取list_projects)
update_issue
更新现有问题。还支持将问题转移到其他团队。
参数:
issue_id(必填):问题UUID(来自问题查询,而不是标识符)title(可选):新标题description(可选):新描述priority(可选):新优先级state_id(可选):新工作流状态UUIDassignee_id(可选):新受让人UUIDteam_id(可选):目标团队UUID。设置后,将问题转移到该团队。Linear将状态映射到目标团队中的同一类型,如果未共享,则清除该项目--passstate_id和project_id控制这些。project_id(可选):要将问题分配给的项目UUID。传递一个空字符串以取消分配。
update_status
更改问题工作流状态。
参数:
issue_id(必填):发布UUIDstate_id(必需):目标工作流状态UUID(从获取states工具)
create_project
创建一个新的线性项目。
参数:
name(必填):项目名称team_id(必需):与项目关联的团队UUIDdescription(可选):项目描述state(可选):项目状态(计划、已开始、已暂停、已完成、已取消)
答复:
{
"success": true,
"project": {
"id": "project-uuid",
"name": "New Project",
"slugId": "new-project",
"url": "https://linear.app/team/project/new-project"
}
}create_project_update
发布项目的状态更新。
参数:
project_id(必填):项目UUID(从list_projects获取)body(必填):更新内容(支持markdown)health(可选):健康状况(在轨、有风险、脱轨)
states
获取可用的工作流状态。
参数:
team_id(可选):团队UUID。如果没有提供,则返回所有团队的状态。
回应(单团队):
{
"success": true,
"team": { "id": "team-uuid", "name": "Engineering" },
"states": [
{ "id": "state-1", "name": "Backlog", "type": "backlog" },
{ "id": "state-2", "name": "In Progress", "type": "started" },
{ "id": "state-3", "name": "Done", "type": "completed" }
]
}本地开发
先决条件
- Python 3.12+
- 紫外线 包管理器
- 钥匙卡应用凭据(zone_id、client_id、client_secret)
设置
- 克隆并输入目录:
cd svc-mcp-linear- 创建虚拟环境并安装依赖关系:
uv venv
source .venv/bin/activate
uv sync- 创建
.env例如:
cp .env.example .env- 在中配置钥匙卡凭据
.env:
KEYCARD_ZONE_ID=your_zone_id
KEYCARD_CLIENT_ID=your_client_id
KEYCARD_CLIENT_SECRET=your_client_secret
MCP_SERVER_URL=http://localhost:8000
PORT=8000从您的Keycard仪表板获取这些凭据:
- 在keycard.cloud上创建一个区域 - 添加Linear作为凭证提供者 - 注册应用程序并复制凭据
在本地运行
uv run python -m src.server服务器启动时间 http://localhost:8000/mcp
测试
服务器需要Keycard身份验证。要进行测试,请使用配置了指向服务器URL的Keycard身份验证的MCP客户端。
运行测试
uv run pytest覆盖范围:
uv run pytest --cov=src --cov-report=term-missing渲染部署
服务器部署在Render上 https://svc-mcp-linear.onrender.com/mcp.
配置
渲染所需的环境变量:
KEYCARD_ZONE_IDKEYCARD_CLIENT_IDKEYCARD_CLIENT_SECRETMCP_SERVER_URL(设置为渲染URL)PORT(渲染会自动提供此功能)
部署
- 将您的仓库连接到Render
- 设置启动命令:
uv run python -m src.server - 在Render仪表板中添加环境变量
手动部署
git push origin main # Auto-deploys if connected to Render错误处理
所有工具都返回一致的响应结构:
成功:
{
"success": true,
"issues": [...],
"count": 5
}错误:
{
"success": false,
"error": "Error message describing what went wrong",
"isError": true
}常见错误:
No authentication context-未配置钥匙卡身份验证Authentication errors: [...]-用户未通过身份验证或令牌已过期Linear API returned HTTP 401-令牌无效或已撤销Issue ENG-999 not found-问题不存在或无法访问
项目结构
svc-mcp-linear/
├── src/
│ ├── __init__.py
│ ├── auth.py # Keycard AuthProvider singleton
│ ├── server.py # FastMCP entry point
│ ├── client.py # Linear GraphQL client
│ └── tools/
│ ├── __init__.py
│ ├── issues.py # my_issues, issue, search, list_projects, list_project_updates
│ ├── mutations.py # create_issue, update_issue, update_status, create_project, create_project_update
│ └── states.py # states
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_client.py
│ └── test_tools.py
├── pyproject.toml
├── .env.example
└── README.md许可证
仅供内部使用。
