{
  "markdown": "# linear-mcp\n\n<!-- mcp-name: io.github.adelaidasofia/linear-mcp -->\n\nMulti-workspace Linear MCP server with Personal API Key auth. Drop-in replacement for the official OAuth-only Linear MCP at `mcp.linear.app/mcp`.\n\n**Why this exists.** The official Linear MCP is OAuth-only and single-workspace per instance. PAT auth plus persistent token storage plus multi-workspace routing kills three failure modes:\n\n1. The OAuth flow is brittle across MCP client session boundaries — auth state expires when a session resumes mid-flow.\n2. The localhost callback fails in some setups, forcing fragile paste-back flows.\n3. One MCP instance per workspace doubles config + OAuth dances.\n\nThis server replaces both with one entry. One install, N workspaces, never an OAuth dance again.\n\n## Install\n\n### From PyPI\n\n```bash\npipx install adelaidasofia-linear-mcp\n```\n\n### From source\n\n```bash\ngit clone https://github.com/adelaidasofia/linear-mcp ~/.claude/linear-mcp\ncd ~/.claude/linear-mcp\npip install -e .\n```\n\n### Claude Desktop one-click\n\nDownload the latest `.mcpb` from [Releases](https://github.com/adelaidasofia/linear-mcp/releases) and double-click.\n\n## Configure\n\n1. Generate one **Personal API Key per workspace** at <https://linear.app/settings/account/security>. You must be logged into each workspace separately while generating the key for that workspace.\n\n2. Create `~/.claude/linear-mcp/admin.env` (chmod 600):\n\n```bash\nLINEAR_WORKSPACES=personal,work\nLINEAR_PRIMARY_WORKSPACE=personal\n\nLINEAR_PAT_PERSONAL=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxx\nLINEAR_PAT_WORK=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\nLINEAR_LABEL_PERSONAL=Personal\nLINEAR_LABEL_WORK=Work\n```\n\nAliases are arbitrary — name them whatever helps you route (`acme,beta`, `team1,team2`, `home,client`).\n\n```bash\nchmod 600 ~/.claude/linear-mcp/admin.env\n```\n\n3. Register in Claude Code (user scope, so it loads in every project):\n\n```bash\nclaude mcp add -s user linear-mcp python3 -m linear_mcp.server\n```\n\nOr, with `pipx` install:\n\n```bash\nclaude mcp add -s user linear-mcp linear-mcp\n```\n\n4. Restart Claude Code. `healthcheck` should return `ok: true` per workspace.\n\n## Substrate-layer enforcement (v0.3)\n\nThree server-side checks that protect issue quality without depending on any markdown rule file or client-side memory. Apply only to WRITE paths; reads stay unconstrained.\n\n| Layer | What it does | Bypass env var |\n|---|---|---|\n| `[source:]` first-line check | `save_issue` / `save_project` reject CREATE calls whose `description` (or project `content`) does not start with `[source: <canonical-key>]`. UPDATE calls (`id` passed) skip the check so legacy backfills remain unblocked. | `LINEAR_MCP_SKIP_SOURCE_CHECK=1` |\n| Idempotency check | Before any CREATE, the server runs `searchIssues` / `searchProjects` for `[source: <key>]` and refuses to create a duplicate. The error names the existing identifier + UUID so the caller can update in place. | `LINEAR_MCP_SKIP_IDEMPOTENCY=1` |\n| `auth_phrase` on `bulk_save_issues` | `bulk_save_issues` now requires `auth_phrase` ∈ {`\"go\"`, `\"yes do it\"`, `\"confirmed\"`, `\"execute\"`, `\"go cancel\"`, `\"go update\"`} (case-insensitive). Mass-modification surface stays explicit. | (no bypass — surface the phrase to the operator) |\n\nCanonical-key examples:\n\n- `[source: 🍄 Mycelium AI/📝 Meeting Notes/2026-05-22 - sync.md]`\n- `[source: ⚙️ Meta/Decisions/2026-05-23-merger-public-comms.md]`\n- `[source: linear-kickoff:sweep-myc-p1]`\n- `[source: ~/.claude/linear-mcp/BUILD_PROMPT_V03.md]`\n\n## Fast issue execution\n\n`linear-exec` is the short path for starting real work from a Linear issue.\nIt resolves the issue, checks blocking relations, scans same-project siblings\nfor obvious scope overlap, infers the repo when possible, and can create the\nstandard `claude-dev-worktree` branch.\n\nDry-run a specific issue:\n\n```bash\nlinear-exec execute MYC-150 --workspace mycelium\n```\n\nStart the work after reviewing the preflight:\n\n```bash\nlinear-exec execute MYC-150 --workspace mycelium --repo memory-runtime-pro --go\n```\n\nFind the next unblocked P1 issue in a workspace:\n\n```bash\nlinear-exec sweep mycelium p1\nlinear-exec sweep mycelium p1 --go --repo memory-runtime-pro\n```\n\nThe command refuses to proceed when an upstream `blocks` relation is still\nincomplete unless `--force` is passed. `--no-state-update` and `--no-worktree`\nlet agents use only the parts of the preflight they need.\n\n## Tool surface (v0.3 — 57 tools + 3 prompts)\n\nEvery tool takes an optional `workspace` parameter (the alias from `LINEAR_WORKSPACES`). Omit it to use `LINEAR_PRIMARY_WORKSPACE`.\n\n### Meta\n\n| Tool | Purpose |\n|---|---|\n| `list_workspaces` | Show configured workspaces and primary |\n| `healthcheck` | Verify each PAT + surface remaining rate-limit budget |\n\n### Core entities\n\n| Tool | Purpose |\n|---|---|\n| `list_teams` / `get_team` | Teams (with inline workflow states) |\n| `list_users` / `get_user` | Users (`me` resolves to PAT owner) |\n| `list_projects` / `get_project` / `save_project` | Projects (v0.3: `save_project` enforces `[source:]` on `content` + idempotency on CREATE) |\n| `list_initiatives` / `get_initiative` / `save_initiative` | Initiatives |\n| `list_issues` / `get_issue` / `save_issue` / `bulk_save_issues` | Issues (id or `ONDE-123`; bulk uses `issueBatchUpdate`; v0.3: `save_issue` enforces `[source:]` + idempotency on CREATE; `bulk_save_issues` requires `auth_phrase`) |\n| `list_cycles` | Cycles |\n| `list_milestones` / `get_milestone` / `save_milestone` | Project milestones |\n| `list_issue_statuses` / `get_issue_status` | Workflow states |\n| `list_issue_labels` / `create_issue_label` | Labels |\n| `list_comments` / `save_comment` | Comments |\n| `list_documents` / `get_document` / `save_document` | Documents |\n| `save_status_update` | Post a project status update |\n\n### Webhooks (v0.2)\n\n| Tool | Purpose |\n|---|---|\n| `list_webhooks` / `get_webhook` | Inspect subscriptions |\n| `create_webhook` / `update_webhook` | Manage subscriptions |\n| `delete_webhook` | Destructive — draft+confirm |\n\n### Notifications / inbox (v0.2)\n\n| Tool | Purpose |\n|---|---|\n| `list_notifications` / `get_notification` | Inbox read |\n| `notifications_unread_count` | Top-of-mind counter |\n| `mark_notification_read` / `mark_all_notifications_read` | Triage |\n| `archive_notification` | Sweep |\n\n### Attachments (v0.2)\n\n| Tool | Purpose |\n|---|---|\n| `list_attachments` / `get_attachment` | Per-issue reads |\n| `attachments_for_url` | Reverse lookup: which issues link to this URL? |\n| `link_url_to_issue` | Attach any URL to an issue |\n| `delete_attachment` | Destructive — draft+confirm |\n\n### Issue relations (v0.2)\n\n| Tool | Purpose |\n|---|---|\n| `list_issue_relations` | The blocks/duplicate/related graph |\n| `create_issue_relation` / `delete_issue_relation` | Manage the graph |\n\n### Agent sessions (v0.2)\n\n| Tool | Purpose |\n|---|---|\n| `list_agent_sessions` / `get_agent_session` | Linear's first-class agent surface |\n| `create_agent_session_on_issue` / `create_agent_session_on_comment` | Spawn |\n\n### Search (v0.2 — replaces v0.1's broken `search_documentation`)\n\n| Tool | Purpose |\n|---|---|\n| `search_issues` / `search_documents` / `search_projects` | Full-text per entity type |\n| `semantic_search` | Workspace-wide semantic across all entities |\n\n### MCP prompts (v0.2)\n\nAvailable as slash commands in MCP clients that surface prompts:\n\n- `/triage-issue` — full triage pass: classify, label, prioritize, assign, link duplicates\n- `/project-status` — draft a weekly status update from current Linear state\n- `/inbox-sweep` — sweep today's notifications, propose actions, archive what's handled\n\n## Multi-workspace usage\n\nSwitch workspaces inline:\n\n```\nlist_teams(workspace=\"work\")\nsave_issue(workspace=\"personal\", title=\"Ship\", team_id=\"...\")\n```\n\nWithout `workspace`, the primary is used.\n\n## Auth\n\nLinear PATs use header `Authorization: <key>` (no `Bearer` prefix). Each PAT is scoped to one workspace and grants access only to data the owning user can see. There is no shared org token.\n\nRate limit: 2500 requests/hour per token (verified against live API 2026-05-23). The server passes Linear's `Retry-After` header through on 429 and surfaces remaining budget via `healthcheck`.\n\n## Safety\n\nRead tools and routine writes (create/update issues, comments, labels, status updates) pass through. Destructive ops (`delete_webhook`, `delete_attachment`) use the **draft+confirm** pattern: the first call stages the change and returns a `draft_id` + preview of what will happen; the second call (with `confirm_draft_id`) commits. Drafts expire after 1 hour (override with `LINEAR_MCP_DRAFT_TTL_SECONDS`).\n\nEvery tool call appends one JSONL line to `~/.claude/linear-mcp/audit.log` (override with `LINEAR_MCP_AUDIT_LOG_PATH`, disable with `LINEAR_MCP_AUDIT_LOG=false`). Tokens are stripped from audit records.\n\n`healthcheck` surfaces each PAT's remaining rate-limit budget (`X-RateLimit-Requests-Remaining` + `X-Complexity-Remaining`) per workspace, so agents can self-throttle without making a separate observability call.\n\n## Related MCPs\n\n- [adelaidasofia/slack-mcp](https://github.com/adelaidasofia/slack-mcp) — multi-workspace Slack with draft+confirm\n- [adelaidasofia/whatsapp-mcp](https://github.com/adelaidasofia/whatsapp-mcp) — WhatsApp via whatsmeow + vault export\n- [adelaidasofia/imessage-mcp](https://github.com/adelaidasofia/imessage-mcp) — iMessage chat.db + vault export\n- [adelaidasofia/github-mcp](https://github.com/adelaidasofia/github-mcp) — GitHub PR/issue/release\n\n## License\n\nMIT.\n\n---\n\nBuilt by Adelaida Diaz-Roa. Full install or team version at [diazroa.com](https://diazroa.com).\n",
  "bytes": 9614,
  "sha": "02beee3a05a3fb4910733f2167cc82a7fd6627e64caa2fcf435f908fb4337224",
  "repo_slug": "adelaidasofia/linear-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_adelaidasofia_linear_mcp_f6462cb0/readme"
}