线性MCP服务器
用于Linear的可流化HTTP MCP服务器——管理问题、项目、团队、周期和评论。
作者 过度
\[!警告\] 您自行负责将此服务器连接到MCP客户端。语言模型可能会出错、误解指令或执行意外操作。审查工具输出,验证更改(例如 list_issues),并且更喜欢小的增量写入。 HTTP/OAuth层是为开发过程中的便利性而设计的,而不是生产级的安全性。如果远程部署,请加强它:适当的令牌验证、安全存储、TLS终止、严格的CORS/源代码检查、速率限制、审计日志记录以及遵守Linear的条款。比较
下面是官方线性MCP(顶部)和此MCP(底部)之间的比较。
通知
此repo以两种方式工作:
- 作为一个 节点/HONO服务器 用于本地工作流
- 作为一个 Cloudflare工作人员 用于远程交互
有关Cloudflare的生产部署,请参阅 远程模型上下文协议服务器(MCP).
动机
我非常喜欢 线性 并每天使用。在撰写本文时,官方MCP服务器尚未完全针对语言模型进行优化。此服务器的构建考虑了以下关键目标:
- 让LLM在中查找团队ID、项目ID、状态ID或用户ID 单一动作 (
workspace_metadata)而不是多次调用工具 - 包括清晰的MCP说明和架构描述,以减少API术语
- 将API响应映射到 人类可读的反馈 --对LLM和用户都有用
- 为下一步提供提示和建议,以及从错误中恢复的提示
- 支持 批处理操作 (例如。,
create_issues而不是create_issue)因此LLM可以一次性执行多个步骤 - 预取相关值——返回问题的状态ID和实际状态名称
- 隐藏在给定团队设置中未启用的工具(如
list_cycles)降低噪音
简言之,它不是Linear的API的直接镜像——它是定制的,这样人工智能代理就知道如何有效地使用它。
特性
- ✅ 问题 --列表、搜索、创建、更新(状态、受让人、标签、优先级等)
- ✅ 项目 --列出、创建、更新项目
- ✅ 团队和用户 --发现工作空间结构
- ✅ 循环 --浏览冲刺/周期计划
- ✅ 评论 --列出问题并添加评论
- ✅ OAuth 2.1 --使用RS令牌映射保护PKCE流
- ✅ 双运行时 --Node.js/Bun或Cloudflare Workers
- ✅ 生产就绪 --加密令牌存储、速率限制、多用户支持
设计原则
- LLM友好:工具是简化和统一的,而不是1:1 API镜像
- 第一批:创建/更新操作接受数组以最小化工具调用
- 先发现:
workspace_metadata返回后续调用所需的所有ID - 清晰的反馈:每个响应都包含人类可读的摘要和差异
______________________________________________________________________
安装
跑步方式(选一种)
- 本地(API密钥) --最快启动
- 本地+OAuth --用于多用户或令牌刷新
- Cloudflare Worker(牧者开发) --本地工人测试
- Cloudflare Worker(部署) --远程生产
______________________________________________________________________
1.本地(API密钥)-快速启动
使用您的线性个人访问令牌运行服务器 设置→ 安全.
git clone
cd linear-mcp
bun install
cp env.example .env编辑 .env:
PORT=3000
AUTH_STRATEGY=bearer
BEARER_TOKEN=lin_api_xxxx # Your Linear API keybun dev
# MCP: http://127.0.0.1:3000/mcp连接到您的MCP客户端:
克劳德桌面/光标:
{
"mcpServers": {
"linear": {
"command": "bunx",
"args": [
"mcp-remote",
"http://localhost:3000/mcp",
"--header",
"Authorization: Bearer ${LINEAR_API_KEY}"
]
}
}
}______________________________________________________________________
2.本地+OAuth
更高级——需要在Linear中创建OAuth应用程序。
- 在以下位置创建OAuth应用程序 线性设置→ API → OAuth应用程序
- 设置重定向URI:
http://127.0.0.1:3001/oauth/callback
alice://oauth/callback- 复制客户端ID和密码
cp env.example .env编辑 .env:
PORT=3000
AUTH_ENABLED=true
PROVIDER_CLIENT_ID=your_client_id
PROVIDER_CLIENT_SECRET=your_client_secret
OAUTH_SCOPES=read write
OAUTH_REDIRECT_URI=alice://oauth/callback
OAUTH_REDIRECT_ALLOWLIST=alice://oauth/callback,http://127.0.0.1:3001/oauth/callbackbun dev
# MCP: http://127.0.0.1:3000/mcp
# OAuth: http://127.0.0.1:3001提示: 授权服务器在PORT+1上运行。
克劳德桌面:
{
"mcpServers": {
"linear": {
"command": "bunx",
"args": ["mcp-remote", "http://localhost:3000/mcp", "--transport", "http-only"],
"env": { "NO_PROXY": "127.0.0.1,localhost" }
}
}
}仅RS模式(建议用于远程)
启用这些标志以要求RS铸造的承载令牌:
AUTH_REQUIRE_RS=true
AUTH_ALLOW_DIRECT_BEARER=false启用后,请求没有 Authorization 或使用未映射的令牌接收 401 和 WWW-Authenticate 这样OAuth就可以启动了。
______________________________________________________________________
3.Cloudflare Worker(本地开发人员)
bun x wrangler dev --local | cat使用OAuth:
bun x wrangler secret put PROVIDER_CLIENT_ID
bun x wrangler secret put PROVIDER_CLIENT_SECRET
bun x wrangler dev --local | cat端点: http://127.0.0.1:8787/mcp
______________________________________________________________________
4.Cloudflare Worker(部署)
- 创建KV命名空间:
bun x wrangler kv:namespace create TOKENS- 更新
wrangler.toml具有KV命名空间ID
- 设置秘密:
bun x wrangler secret put PROVIDER_CLIENT_ID
bun x wrangler secret put PROVIDER_CLIENT_SECRET
# Generate encryption key (32-byte base64url):
openssl rand -base64 32 | tr -d '=' | tr '+/' '-_'
bun x wrangler secret put RS_TOKENS_ENC_KEY注: RS_TOKENS_ENC_KEY 加密存储在KV中的OAuth令牌(AES-256-GCM)。- 更新重定向URI并在中分配列表
wrangler.toml
- 将Workers URL添加到Linear OAuth应用程序的重定向URI中
- 部署:
bun x wrangler deploy端点: https://..workers.dev/mcp
______________________________________________________________________
客户端配置
MCP检查员(快速测试):
bunx @modelcontextprotocol/inspector
# Connect to: http://localhost:3000/mcp克劳德桌面/光标:
{
"mcpServers": {
"linear": {
"command": "bunx",
"args": ["mcp-remote", "http://127.0.0.1:3000/mcp", "--transport", "http-only"],
"env": { "NO_PROXY": "127.0.0.1,localhost" }
}
}
}对于Cloudflare,将URL替换为 https://..workers.dev/mcp.
______________________________________________________________________
工具
workspace_metadata
发现工作区实体和ID。 先叫这个 当你不知道身份证的时候。
// Input
{
include?: ("profile"|"teams"|"workflow_states"|"labels"|"projects"|"favorites")[];
teamIds?: string[];
project_limit?: number;
label_limit?: number;
}
// Output
{
viewer: { id, name, email, displayName, timezone };
teams: Array;
workflowStatesByTeam: Record>;
labelsByTeam: Record>;
projects: Array;
}list_issues
使用强大的GraphQL过滤功能搜索和过滤问题。
// Input
{
teamId?: string;
projectId?: string;
filter?: IssueFilter; // GraphQL-style: { state: { type: { eq: "started" } } }
q?: string; // Title search tokens
keywords?: string[]; // Alternative to q
includeArchived?: boolean;
orderBy?: "updatedAt" | "createdAt" | "priority";
limit?: number; // 1-100
cursor?: string; // Pagination
fullDescriptions?: boolean;
}
// Output
{
items: Array;
cursor?: string;
nextCursor?: string;
limit: number;
}create_issues
在一次通话中创建多个问题。
{
items: Array;
parallel?: boolean;
}update_issues
批量更新问题(状态、标签、受让人、元数据)。
{
items: Array;
parallel?: boolean;
}其他工具
get_issues--按ID提取问题(批处理)list_projects/create_projects/update_projects--管理项目list_teams/list_users--发现工作空间结构list_cycles--浏览团队周期(如果启用)list_comments/add_comments--发布评论
______________________________________________________________________
例子
1.列出我今天要处理的问题
// First, get viewer info
{ "name": "workspace_metadata", "arguments": { "include": ["profile"] } }
// Then list issues assigned to me
{
"name": "list_issues",
"arguments": {
"assignedToMe": true,
"filter": { "dueDate": { "eq": "2025-08-15" } },
"orderBy": "updatedAt",
"limit": 20
}
}答复:
Issues: 1 (limit 20). Preview:
- [OVE-142 — Publish release notes](https://linear.app/.../OVE-142) — state Done; due 2025-08-152.创建问题并将其添加到项目中
// Discover IDs first
{ "name": "workspace_metadata", "arguments": { "include": ["teams", "projects"] } }
// Create (assigneeId defaults to current viewer)
{
"name": "create_issues",
"arguments": {
"items": [{
"title": "Release Alice v3.8",
"teamId": "TEAM_ID",
"projectId": "PROJECT_ID",
"dueDate": "2025-08-18",
"priority": 2
}]
}
}答复:
Created issues: 1 / 1. OK: item[0].
Next: Use list_issues to verify details.3.批量更新:重新安排+标记为完成
// Resolve workflow states first
{ "name": "workspace_metadata", "arguments": { "include": ["workflow_states"], "teamIds": ["TEAM_ID"] } }
// Update both issues
{
"name": "update_issues",
"arguments": {
"items": [
{ "id": "RELEASE_UUID", "dueDate": "2025-08-16" },
{ "id": "MEETING_UUID", "stateId": "DONE_STATE_ID" }
]
}
}答复:
Updated issues: 2 / 2. OK: RELEASE_UUID, MEETING_UUID
- [OVE-231 — Release Alice v3.8] Due date: 2025-08-18 → 2025-08-16
- [OVE-224 — Team meeting] State: Current → Done______________________________________________________________________
HTTP端点
| 端点 | 方法 | 目的 |
|---|---|---|
/mcp | 发布 | MCP JSON-RPC 2.0 |
/mcp | GET | SSE流(仅限Node.js) |
/health | GET | 健康检查 |
/.well-known/oauth-authorization-server | GET | OAuth AS元数据 |
/.well-known/oauth-protected-resource | GET | OAuth RS元数据 |
OAuth(端口+1):
GET /authorize--启动OAuth流GET /oauth/callback--提供商回调POST /token--代币兑换POST /revoke--撤销代币
______________________________________________________________________
发展
bun dev # Start with hot reload
bun run typecheck # TypeScript check
bun run lint # Lint code
bun run build # Production build
bun start # Run production______________________________________________________________________
测试
该项目采用两层测试策略:
单元测试(模拟)
使用模拟线性API响应的快速测试。无需网络调用即可测试所有逻辑、验证和边缘情况。
bun test # Run all unit tests (~4 seconds)
bun run test:watch # Watch mode
bun run test:coverage # With coverage report集成测试(实时API)
真实的API测试验证实际的线性连接是否有效。在“测试”团队中创建问题,并在之后进行清理。
设置:
- 在您的线性工作区中创建一个名为“测试”的团队
- 将线性API键添加到
.env:
PROVIDER_API_KEY=lin_api_xxxx运行:
bun run test:integration # ~45 seconds测试内容:
| 类别 | 测试 | 目的 |
|---|---|---|
| CRUD | 5 | 创建、读取、更新、列出操作 |
| 筛选 | 3 | 优先级、标题搜索、工作流状态筛选器 |
| 分页 | 2 | 限制和光标行为 |
| 错误 | 3 | 不存在问题,筛选器无效 |
| 速率限制 | 2 | 快速请求、批处理操作 |
测试策略
| 层 | 速度 | 目的 |
|---|---|---|
| 单位/模型 | ⚡️ 快速 | 逻辑正确性、验证、边缘情况 |
| 整合 | 🐢 慢 | API合约,真实数据映射 |
| TypeScript | 🛡️ 构建 | SDK类型对齐 |
对每次更改运行单元测试。在发布之前或SDK升级之后运行集成测试。
______________________________________________________________________
建筑
src/
├── shared/
│ ├── tools/
│ │ └── linear/ # Tool definitions (work in Node + Workers)
│ │ ├── workspace-metadata.ts
│ │ ├── list-issues.ts
│ │ ├── create-issues.ts
│ │ ├── update-issues.ts
│ │ ├── projects.ts
│ │ ├── comments.ts
│ │ ├── cycles.ts
│ │ └── shared/ # Formatting, validation, snapshots
│ ├── oauth/ # OAuth flow (PKCE, discovery)
│ └── storage/ # Token storage (file, KV, memory)
├── services/
│ └── linear/
│ └── client.ts # LinearClient wrapper with auth
├── schemas/
│ ├── inputs.ts # Zod input schemas
│ └── outputs.ts # Zod output schemas
├── config/
│ └── metadata.ts # Server & tool descriptions
├── index.ts # Node.js entry
└── worker.ts # Workers entry______________________________________________________________________
故障排除
| 问题 | 解决方案 |
|---|---|
| “工作区不存在” | 验证您的OAuth应用程序是否在正确的线性工作区中。检查PROVIDER_CLIENT_ID |
| “未经授权” | 完成OAuth流程。令牌可能已过期。 |
| “未找到状态” | 使用 workspace_metadata 获取团队的有效状态ID。 |
| “速率限制” | Linear具有严格的速率限制。请稍候,然后重试。 |
| OAuth未启动(Worker) | curl -i -X POST https:///mcp 应返回 401 和 WWW-Authenticate. |
| Claude中的工具为空 | 确保Worker返回JSON模式 tools/list;使用 mcp-remote. |
______________________________________________________________________
许可证
麻省理工学院
