Skip to main content
Glama
MoshPitLabs

MCP Linear.app Server

by MoshPitLabs
README.md
# MCP Linear.app Server

A Model Context Protocol (MCP) server that enables OpenCode and other MCP clients to interact with Linear.app's API for issue tracking, project management, and workflow automation.

## Features

- **Issue Management**: Create, update, list, search, and get detailed issue information
- **Project & Team Operations**: List projects and teams, access workflow states
- **Cycle Management**: Create and manage sprints/cycles
- **Label Management**: Create and organize labels
- **User Operations**: List users and assign issues
- **Advanced Filtering**: Filter issues by status, assignee, project, labels, and more
- **Type-Safe**: Built with TypeScript and Zod validation for robust error handling
- **Production-Ready**: Comprehensive error handling, logging, and rate limit awareness

## Installation

### Prerequisites

- Bun 1.0.0 or higher (or Node.js 18.0.0+)
- A Linear.app account and API key

### Setup

1. Clone this repository:

```bash
git clone <repository-url>
cd mcp-linearapp
```

2. Install dependencies:

```bash
bun install
```

3. Create a `.env` file with your Linear API key:

```bash
cp .env.example .env
```

4. Edit `.env` and add your Linear API key:

```
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

**How to get your Linear API key:**

1. Go to https://linear.app/settings/api
2. Click "Create new API key"
3. Give it a name and copy the key
4. Paste it into your `.env` file

5. Build the project:

```bash
bun run build
```

## Usage

### With OpenCode

Add this server to your OpenCode configuration:

**macOS**: `~/Library/Application Support/OpenCode/opencode_config.json`  
**Windows**: `%APPDATA%/OpenCode/opencode_config.json`  
**Linux**: `~/.config/OpenCode/opencode_config.json`

```json
{
  "mcpServers": {
    "linear": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-linearapp/dist/index.js"],
      "env": {
        "LINEAR_API_KEY": "lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

After adding the configuration, restart OpenCode.

### With Other MCP Clients

The server uses stdio transport and can be integrated with any MCP-compatible client:

```bash
bun run dist/index.js
# or with Node.js:
node dist/index.js
```

## Available Tools

### Issue Management

#### `linear_list_issues`

List Linear issues with optional filters.

**Parameters:**

- `teamId` (optional): Filter by team ID
- `projectId` (optional): Filter by project ID
- `assigneeId` (optional): Filter by assignee user ID
- `status` (optional): Filter by status (backlog, unstarted, started, completed, canceled, triage, in_progress, done)
- `priority` (optional): Filter by priority (0=None, 1=Urgent, 2=High, 3=Medium, 4=Low)
- `label` (optional): Filter by label name
- `limit` (optional): Maximum number of issues (1-100, default: 25)
- `includeArchived` (optional): Include archived issues (default: false)

**Example:**

```
List all high priority issues assigned to me
```

#### `linear_create_issue`

Create a new Linear issue.

**Parameters:**

- `title` (required): Issue title
- `teamId` (required): Team ID where the issue will be created
- `description` (optional): Issue description in markdown
- `projectId` (optional): Project ID to assign the issue to
- `assigneeId` (optional): User ID to assign the issue to
- `priority` (optional): Priority (0-4)
- `labelIds` (optional): Array of label IDs
- `stateId` (optional): Workflow state ID
- `estimate` (optional): Estimate in points
- `dueDate` (optional): Due date (YYYY-MM-DD)
- `parentId` (optional): Parent issue ID for sub-issues

**Example:**

```
Create an issue titled "Fix login bug" in the Engineering team with high priority
```

#### `linear_update_issue`

Update an existing Linear issue.

**Parameters:**

- `issueId` (required): Issue ID or identifier (e.g., "ENG-123")
- `title`, `description`, `assigneeId`, `priority`, `stateId`, `labelIds`, `estimate`, `dueDate`, `projectId` (all optional)

**Example:**

```
Update issue ENG-123 to change priority to urgent and assign to John
```

#### `linear_get_issue`

Get detailed information about a specific issue.

**Parameters:**

- `issueId` (required): Issue ID or identifier (e.g., "ENG-123")

**Example:**

```
Get details for issue ENG-123
```

#### `linear_search_issues`

Search issues by text query.

**Parameters:**

- `query` (required): Search query text
- `teamId` (optional): Limit search to specific team
- `limit` (optional): Maximum results (1-100, default: 25)
- `includeArchived` (optional): Include archived issues

**Example:**

```
Search for issues about authentication
```

#### `linear_assign_issue`

Assign an issue to a user.

**Parameters:**

- `issueId` (required): Issue ID or identifier
- `assigneeId` (required): User ID to assign to

**Example:**

```
Assign issue ENG-123 to user abc-123
```

#### `linear_add_comment`

Add a comment to an issue.

**Parameters:**

- `issueId` (required): Issue ID or identifier
- `body` (required): Comment body in markdown

**Example:**

```
Add a comment to ENG-123 saying "This is fixed in the latest build"
```

### Team & Workflow

#### `linear_list_teams`

List all teams in your workspace.

**Parameters:**

- `includeArchived` (optional): Include archived teams (default: false)

**Example:**

```
List all teams
```

#### `linear_list_workflow_states`

List workflow states for a team.

**Parameters:**

- `teamId` (required): Team ID

**Example:**

```
List workflow states for team abc-123
```

### Projects

#### `linear_list_projects`

List all projects.

**Parameters:**

- `teamId` (optional): Filter by team ID
- `includeArchived` (optional): Include archived projects (default: false)

**Example:**

```
List all projects for the Engineering team
```

### Cycles (Sprints)

#### `linear_create_cycle`

Create a new cycle/sprint.

**Parameters:**

- `teamId` (required): Team ID
- `name` (required): Cycle name
- `description` (optional): Cycle description
- `startsAt` (required): Start date (YYYY-MM-DD)
- `endsAt` (required): End date (YYYY-MM-DD)

**Example:**

```
Create a 2-week sprint starting today for the Engineering team
```

#### `linear_list_cycles`

List cycles for a team.

**Parameters:**

- `teamId` (required): Team ID
- `includeArchived` (optional): Include archived cycles

**Example:**

```
List all active cycles for team abc-123
```

### Labels

#### `linear_create_label`

Create a new label.

**Parameters:**

- `name` (required): Label name
- `teamId` (required): Team ID
- `color` (optional): Color in hex format (e.g., "#FF0000")
- `description` (optional): Label description

**Example:**

```
Create a label called "bug" with red color for the Engineering team
```

#### `linear_list_labels`

List all labels.

**Parameters:**

- `teamId` (optional): Filter by team ID

**Example:**

```
List all labels
```

### Users

#### `linear_list_users`

List all users in your workspace.

**Parameters:**

- `includeDisabled` (optional): Include disabled users (default: false)

**Example:**

```
List all active users
```

## Workflow Examples

### Creating an Issue with Full Context

1. First, list teams to get the team ID:

```
List all teams
```

2. Optionally, list users to assign the issue:

```
List all users
```

3. Create the issue:

```
Create an issue titled "Implement OAuth authentication" in team abc-123, assign to user xyz-456, with high priority and description "Need to add OAuth 2.0 support for Google and GitHub"
```

### Managing a Sprint

1. Create a new cycle:

```
Create a 2-week sprint called "Q1 Sprint 3" for team abc-123 starting 2024-02-01
```

2. List issues to find what to include:

```
List backlog issues for team abc-123
```

3. Update issues to add them to the sprint and assign:

```
Update issue ENG-45 to add to cycle cycle-123 and assign to user xyz-456
```

### Tracking Progress

1. Search for issues in a specific area:

```
Search for issues about "authentication"
```

2. Get detailed information:

```
Get details for issue ENG-123
```

3. Add progress updates:

```
Add comment to ENG-123: "Authentication flow is complete, working on tests"
```

## Development

### Scripts

- `bun run build` - Build the TypeScript project
- `bun run dev` - Watch mode for development
- `bun start` - Start the MCP server
- `bun run lint` - Run ESLint
- `bun run format` - Format code with Prettier
- `bun run typecheck` - Type check without emitting files

### Project Structure

```
mcp-linearapp/
├── src/
│   ├── index.ts              # Main MCP server entry point
│   ├── linear-client.ts      # Linear API client wrapper
│   ├── tools/                # MCP tool implementations
│   │   ├── issues.ts         # Issue-related tools
│   │   ├── projects.ts       # Project tools
│   │   ├── cycles.ts         # Cycle/sprint tools
│   │   ├── teams.ts          # Team tools
│   │   ├── labels.ts         # Label tools
│   │   └── users.ts          # User tools
│   └── schemas/              # Zod validation schemas
│       └── index.ts
├── dist/                     # Compiled JavaScript (generated)
├── package.json
├── tsconfig.json
└── README.md
```

### Architecture

The server is built with:

- **MCP SDK**: Handles the Model Context Protocol communication
- **Linear SDK**: Official Linear API client
- **Zod**: Runtime type validation and schema enforcement
- **TypeScript**: Type safety throughout the codebase

Key design decisions:

1. **Type Safety**: All inputs are validated with Zod schemas before reaching the Linear API
2. **Error Handling**: Comprehensive error handling with meaningful error messages
3. **Modular Design**: Tools are organized by domain (issues, projects, cycles, etc.)
4. **Client Wrapper**: LinearAPIClient provides a clean abstraction over the Linear SDK with consistent error handling and data formatting

## Error Handling

The server provides clear error messages for common issues:

- **Missing API Key**: "LINEAR_API_KEY environment variable is required"
- **Invalid Parameters**: Zod validation errors with specific field information
- **API Errors**: Linear API errors are caught and formatted with context
- **Not Found**: Clear messages when issues, teams, or other resources don't exist

## Rate Limiting

Linear's API has rate limits. The server doesn't implement client-side rate limiting, but:

- Uses the official Linear SDK which handles some retry logic
- Provides clear error messages when rate limits are hit
- Consider implementing delays between bulk operations

## Troubleshooting

### Server won't start

- Verify LINEAR_API_KEY is set in your environment
- Check that Bun version is 1.0.0 or higher (or Node.js 18.0.0+)
- Ensure `bun run build` completed successfully

### "Invalid API key" error

- Verify your API key is correct
- Check that the key hasn't been revoked in Linear settings
- Ensure there are no extra spaces in the .env file

### "Team not found" or similar errors

- Use `linear_list_teams` to get valid team IDs
- Use `linear_list_users` to get valid user IDs
- Use `linear_list_projects` to get valid project IDs
- Issue identifiers are case-sensitive (e.g., "ENG-123" not "eng-123")

### Changes not appearing in OpenCode

- Restart OpenCode after modifying the configuration
- Check OpenCode logs for connection errors
- Verify the absolute path in the configuration is correct

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Make your changes with proper TypeScript types
4. Add/update tests if applicable
5. Run `bun run lint` and `bun run typecheck`
6. Submit a pull request

## License

MIT

## Acknowledgments

- Built with the [Model Context Protocol SDK](https://github.com/modelcontextprotocol)
- Uses the [Linear SDK](https://github.com/linear/linear) for API access
- Inspired by the Linear community and MCP ecosystem

## Support

- Linear API Documentation: https://developers.linear.app/
- MCP Documentation: https://modelcontextprotocol.io/
- Report issues: [GitHub Issues](https://github.com/yourusername/mcp-linearapp/issues)