通过自带的 Node CLI 读取与修改 Linear 的 issue、项目和评论。
集成
Linear
通过托管的 OAuth GraphQL 接口查询与管理 Linear 的 issue、项目、团队、周期、标签和评论。
它能做什么
通过 Maton 托管的 OAuth 端点接入 Linear,使用 GraphQL 读写 issue、项目、团队、周期、标签、工作流状态、用户和评论。文档给出了 CLI、Python 和 JavaScript 三种调用方式,覆盖 Maton API Key 认证、多 Linear 连接管理,以及列表、搜索、创建、更新等常见操作。CLI 自动处理基于游标的分页;类似 ABC-123 的标识符可直接替代 UUID 使用。所有写操作都需要先获得用户明确确认;部分变更操作可能依赖额外的 OAuth 权限,遇到权限错误需联系 Maton 申请扩展。
什么时候用它
- 按团队列出并筛选 Linear issue
- 按关键词全文搜索 issue
- 创建或更新 issue,并添加评论
- 管理多个 Linear OAuth 连接以对接不同工作区
技能文档
Linear
Access the Linear API with managed OAuth authentication. Query and manage issues, projects, teams, cycles, labels, and comments using GraphQL.
Quick Start
CLI:
maton linear issue list -c ABC -L 10
maton api '/linear/graphql'
Python:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'query': '{ viewer { id name email } }'}).encode()
req = urllib.request.Request('https://api.maton.ai/linear/graphql', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/linear/graphql
All requests use POST to the GraphQL endpoint. Maton proxies requests to api.linear.app and automatically injects your OAuth token.
Installation
NPM:
npm install -g @maton/cli
Homebrew:
brew install maton-ai/cli/maton
Authentication
CLI:
maton login # Opens browser for API key
maton login --interactive # Skip browser, paste API key directly
maton whoami # Show current auth state
Manual:
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
- Set your API key as
MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Connection Management
Manage your Linear OAuth connections at https://api.maton.ai.
List Connections
CLI:
maton connection list linear --status ACTIVE
maton api -X GET /connections -f app=linear -f status=ACTIVE
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=linear&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
CLI:
maton connection create linear
maton api /connections -f app=linear
Python:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'linear'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
CLI:
maton connection view {connection_id}
maton api /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2026-02-04T23:03:22.676001Z",
"last_updated_time": "2026-02-04T23:03:51.239577Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "linear",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
CLI:
maton connection delete {connection_id}
maton api -X DELETE /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Linear connections, specify which one to use:
CLI:
maton linear issue list -c ABC --connection {connection_id}
maton api /linear/graphql --connection {connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'query': '{ viewer { id name } }'}).encode()
req = urllib.request.Request('https://api.maton.ai/linear/graphql', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always specify the connection to ensure requests go to the intended account.
Security & Permissions
- Access is scoped to issues, projects, teams, cycles, and comments within the connected Linear account.
- All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
API Reference
Linear uses a GraphQL API. All operations are sent as POST requests with a JSON body containing the query field.
Viewer (Current User)
POST /linear/graphql
Content-Type: application/json
{"query": "{ viewer { id name email } }"}
Example:
maton linear whoami
Organization
POST /linear/graphql
Content-Type: application/json
{"query": "{ organization { id name urlKey } }"}
Example:
maton linear org view
Teams
List Teams
POST /linear/graphql
Content-Type: application/json
{"query": "{ teams { nodes { id name key } } }"}
Example:
maton linear team list
Get Team
POST /linear/graphql
Content-Type: application/json
{"query": "{ team(id: \"ABC\") { id name key issues { nodes { id identifier title } } } }"}
Example:
maton linear team view ABC
Issues
List Issues
POST /linear/graphql
Content-Type: application/json
{"query": "{ issues(first: 10, filter: { team: { key: { eq: \"ABC\" } } }) { nodes { id identifier title state { name } priority createdAt } pageInfo { hasNextPage endCursor } } }"}
Example:
maton linear issue list -c ABC -L 10
Get Issue by ID or Identifier
POST /linear/graphql
Content-Type: application/json
{"query": "{ issue(id: \"ABC-123\") { id identifier title description state { name } priority assignee { name } team { key name } createdAt updatedAt } }"}
Example:
maton linear issue view ABC-123
Filter Issues
Filter by state type:
POST /linear/graphql
Content-Type: application/json
{"query": "{ issues(first: 10, filter: { state: { type: { eq: \"started\" } } }) { nodes { id identifier title state { name type } } } }"}
Example:
maton linear issue list --state started -L 10
Filter by title:
POST /linear/graphql
Content-Type: application/json
{"query": "{ issues(first: 10, filter: { title: { containsIgnoreCase: \"bug\" } }) { nodes { id identifier title } } }"}
Example:
maton linear issue list --title bug -L 10
Search Issues
POST /linear/graphql
Content-Type: application/json
{"query": "{ searchIssues(first: 10, term: \"shopify\") { nodes { id identifier title } } }"}
Example:
maton linear issue search shopify -L 10
Create Issue
POST /linear/graphql
Content-Type: application/json
{"query": "mutation { issueCreate(input: { teamId: \"TEAM_ID\", title: \"New issue title\" }) { success issue { id identifier title state { name } } } }"}
Example:
maton linear issue create --team-id TEAM_ID -t 'New issue title'
Update Issue
POST /linear/graphql
Content-Type: application/json
{"query": "mutation { issueUpdate(id: \"ABC-123\", input: { title: \"Updated title\", priority: 2 }) { success issue { id identifier title priority } } }"}
Example:
maton linear issue update ABC-123 -t 'Updated title' --priority 2
Projects
List Projects
POST /linear/graphql
Content-Type: application/json
{"query": "{ projects(first: 10) { nodes { id name state createdAt } } }"}
Example:
maton linear project list
Cycles
List Cycles
POST /linear/graphql
Content-Type: application/json
{"query": "{ cycles(first: 10) { nodes { id name number startsAt endsAt } } }"}
Example:
maton linear cycle list
Labels
List Labels
POST /linear/graphql
Content-Type: application/json
{"query": "{ issueLabels(first: 20) { nodes { id name color } } }"}
Example:
maton linear label list
Workflow States
POST /linear/graphql
Content-Type: application/json
{"query": "{ workflowStates(first: 20) { nodes { id name type team { key } } } }"}
Example:
maton linear state list
Users
POST /linear/graphql
Content-Type: application/json
{"query": "{ users(first: 20) { nodes { id name email active } } }"}
Example:
maton linear user list
Comments
List Comments
POST /linear/graphql
Content-Type: application/json
{"query": "{ issue(id: \"ABC-123\") { comments(first: 10) { nodes { id body createdAt user { name } } } } }"}
Example:
maton linear comment list --issue ABC-123 -L 10
Create Comment
POST /linear/graphql
Content-Type: application/json
{"query": "mutation { commentCreate(input: { issueId: \"ABC-123\", body: \"Looking into this\" }) { success comment { id body } } }"}
Example:
maton linear comment create --issue ABC-123 -b 'Looking into this'
Pagination
Linear uses Relay-style cursor-based pagination. The CLI automatically paginates with '--paginate'.
Example:
maton linear issue list -c ABC --paginate
Code Examples
CLI
# List issues for a team
maton linear issue list -c ABC -L 10
# View a specific issue
maton linear issue view ABC-123
# Create a new issue
maton linear issue create --team-id TEAM_ID -t 'Fix login'
# Add a comment
maton linear comment create --issue ABC-123 -b 'Looking into this'
JavaScript
const response = await fetch('https://api.maton.ai/linear/graphql', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: `{ issues(first: 10) { nodes { id identifier title state { name } } } }`
})
});
const data = await response.json();
Python
import os
import requests
response = requests.post(
'https://api.maton.ai/linear/graphql',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'query': '{ issues(first: 10) { nodes { id identifier title state { name } } } }'
}
)
data = response.json()
Notes
- Linear uses GraphQL exclusively (no REST API)
- Issue identifiers like
ABC-123can be used in place of UUIDs for theidparameter - Priority values: 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low
- Workflow state types:
backlog,unstarted,started,completed,canceled - The GraphQL schema is introspectable at
https://api.linear.app/graphql - Use
searchIssues(term: "...")for full-text search across issues - Some mutations (delete, create labels/projects) may require additional OAuth scopes. If you receive a scope error, contact Maton support at [email protected] with the specific operations/APIs you need and your use-case
Error Handling
| Status | Meaning |
|---|---|
| 400 | Missing Linear connection or GraphQL validation error |
| 401 | Invalid or missing Maton API key |
| 403 | Insufficient OAuth scope for the operation |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Linear API |
GraphQL errors are returned in the errors array:
{
"errors": [
{
"message": "Invalid scope: `write` required",
"extensions": {
"type": "forbidden",
"code": "FORBIDDEN",
"statusCode": 403
}
}
]
}
Troubleshooting: API Key Issues
CLI:
- Check your auth state:
maton whoami
- Verify the API key is valid by listing connections:
maton connection list
Manual:
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
linear. For example:
- Correct:
https://api.maton.ai/linear/graphql - Incorrect:
https://api.maton.ai/graphql
Resources
常见问题
- 这个技能会调用 Linear 的 REST 接口吗?
- 不会。Linear 只提供 GraphQL API,技能通过 https://api.maton.ai/linear/graphql 发送带 JSON 查询体的 POST 请求,再由 Maton 转发到 api.linear.app。
- 认证流程是怎样的?
- 需要将 Maton API Key 设置为 MATON_API_KEY 环境变量。Linear 的 OAuth 令牌由 Maton 自动托管;当存在多个连接时,可通过 Maton-Connection 请求头或 CLI 的 --connection 参数指定目标连接。
- 能否创建或修改 issue?
- 可以。文档涵盖了 issueCreate、issueUpdate 以及 commentCreate 等变更操作。所有写操作在执行前都需要用户明确确认;部分变更可能依赖未默认授予的额外 OAuth 权限。
相关技能
通过托管 OAuth 代理对接 Asana API,统一处理任务、项目、空间、用户与 Webhook。
通过托管 OAuth 调用 LinkedIn REST API,覆盖发文、个人资料、广告账户与广告库。
通过托管 OAuth 连接 Google Tasks,统一 API 完成任务列表与任务的读写管理。
通过托管 OAuth 接入 GitHub REST API,覆盖仓库、Issue、PR、Commit、分支与用户等接口。
通过托管 OAuth 代理访问 Trello API,统一管理看板、列表、卡片、检查项、标签与成员。
byungkyu 的更多技能
浏览全部技能通过 Microsoft Graph 接入 Outlook,读取、发送、管理邮件、文件夹、日历事件和联系人,OAuth 由平台托管。
通过托管 OAuth 调用 Jira Cloud API,搜索并管理工单。
Google Slides API integration with managed OAuth. Create presentations, add slides, insert content, and manage slide formatting. Use this skill when users wa...
Google Meet API integration with managed OAuth. Create meeting spaces, list conference records, and manage meeting participants. Use this skill when users wa...
Google Contacts API integration with managed OAuth. Manage contacts, contact groups, and search your address book. Use this skill when users want to create,...
Pipedrive API integration with managed OAuth. Manage deals, persons, organizations, activities, and pipelines. Use this skill when users want to interact wit...