MCP Integration with Linear
MCPLinearTutorialProject Management
Build AI-powered project management workflows by integrating Linear MCP with your agents.
MCP Integration with Linear
Overview
Linear MCP enables AI agents to manage Linear issues, projects, and workflows. This tutorial shows you how to integrate Linear with your AI agents for automated project management.
Prerequisites
- Linear account with API access
- Node.js 18+
- Basic understanding of MCP
Installation
# Install Linear MCP server
npx -y @modelcontextprotocol/server-linear
# Or add to claude_desktop_config.json
{
"mcpServers": {
"linear": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-linear"]
}
}
}
Configuration
Get API Key
- Go to Linear Settings
- Navigate to API Keys
- Create a new API key
- Store securely:
export LINEAR_API_KEY=lin_...
Team Selection
# List available teams
npx -y @modelcontextprotocol/server-linear list-teams
# Note the team ID for subsequent operations
Core Operations
Create Issues
{
"action": "create_issue",
"title": "Implement user authentication",
"team_id": "team_123",
"description": "Add OAuth2 authentication with Google and GitHub providers",
"priority": 2,
"estimate": 5,
"labels": ["backend", "security"],
"assignee_id": "user_456"
}
Search Issues
{
"action": "search_issues",
"query": "authentication",
"team_id": "team_123",
"filter": {
"status": "in_progress",
"priority": [1, 2]
}
}
Update Issues
{
"action": "update_issue",
"issue_id": "issue_789",
"status": "completed",
"description": "Implementation complete. PR #123 merged."
}
Get Issue Details
{
"action": "get_issue",
"issue_id": "issue_789",
"include_comments": true,
"include_attachments": false
}
Building AI-Powered Workflows
Automated Issue Triage
# src/linear_triage.py
from mcp import ClientSession
import asyncio
async def triage_new_issue(issue_data: dict):
"""Automatically triage new Linear issues."""
# Analyze issue content
analysis = await analyze_with_llm(issue_data['description'])
# Suggest team assignment
suggested_team = map_to_team(analysis['domain'])
# Suggest priority
suggested_priority = determine_priority(analysis['urgency'])
# Update issue
await update_issue(
issue_data['id'],
team_id=suggested_team,
priority=suggested_priority,
labels=analysis['suggested_labels']
)
async def analyze_with_llm(description: str) -> dict:
"""Use AI to analyze issue description."""
# Call Claude via MCP or direct API
...
Sprint Planning Assistant
# src/sprint_planner.py
async def plan_sprint(team_id: str, capacity: int):
"""Plan next sprint based on team capacity."""
# Get backlog issues
backlog = await search_issues(
team_id=team_id,
filter={'status': 'backlog'}
)
# Rank by priority and estimate
ranked = sort_by_priority_value(backlog)
# Select issues fitting capacity
sprint_issues = select_by_capacity(ranked, capacity)
# Create sprint
sprint = await create_sprint(
team_id=team_id,
name=f"Sprint {get_next_sprint_number()}",
issue_ids=[i['id'] for i in sprint_issues]
)
return sprint
Automated Status Updates
# src/status_updates.py
async def sync_with_github(pr_data: dict):
"""Sync Linear issues with GitHub PR status."""
if pr_data['merged']:
await update_issue(
issue_id=map_to_linear_issue(pr_data['number']),
status='completed'
)
elif pr_data['closed']:
await update_issue(
issue_id=map_to_linear_issue(pr_data['number']),
status='cancelled'
)
Advanced Integrations
With GitHub MCP
// Combined MCP config
{
"mcpServers": {
"linear": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-linear"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
}
}
}
# src/github_linear_sync.py
async def sync_pr_to_linear(pr_url: str):
"""Sync GitHub PR to Linear issue."""
# Get PR details from GitHub
pr = await github.get_pull_request(pr_url)
# Find linked Linear issue
issue_id = extract_linear_id(pr['body'])
# Update Linear issue
await linear.update_issue(
issue_id,
status='in_review',
description=pr['body']
)
With Slack MCP
# src/notifications.py
async def notify_issue_created(issue: dict):
"""Send Slack notification for new issue."""
message = f"""
🎯 New Issue Created
*{issue['title']}*
Team: {issue['team_name']}
Priority: {issue['priority']}
<{issue['url']}|View in Linear>
"""
await slack.send_message(
channel='#engineering',
text=message
)
Best Practices
1. Error Handling
async def safe_create_issue(params: dict):
"""Create issue with error handling."""
try:
return await linear.create_issue(params)
except LinearAPIError as e:
if e.code == 'RATE_LIMIT':
await asyncio.sleep(60)
return await linear.create_issue(params)
raise
2. Batch Operations
async def bulk_create_issues(issues: list[dict]):
"""Create multiple issues efficiently."""
results = []
for issue in issues:
result = await linear.create_issue(issue)
results.append(result)
await asyncio.sleep(0.1) # Rate limit spacing
return results
3. Caching
from functools import lru_cache
@lru_cache(maxsize=100)
async def get_team(team_id: str):
"""Cache team data to reduce API calls."""
return await linear.get_team(team_id)
Troubleshooting
Common Issues
Authentication failed:
# Verify API key
export LINEAR_API_KEY=lin_your_key_here
# Test connection
npx -y @modelcontextprotocol/server-linear list-teams
Team not found:
# List all teams first
teams = await linear.list_teams()
print(teams) # Find correct team_id
Rate limit exceeded:
# Implement retry with backoff
async def with_retry(func, max_retries=3):
for attempt in range(max_retries):
try:
return await func()
except RateLimitError:
await asyncio.sleep(2 ** attempt)
raise
Resources
- Linear API Docs: https://docs.linear.app/
- MCP Linear Server: https://github.com/modelcontextprotocol/servers/tree/main/src/linear
- Linear Webhooks: https://docs.linear.app/webhooks
Last updated: May 2026
