OhMyLinearMCP - unified Linear MCP (local-fast reads + official fallback/writes) on macOS
Project description
oh-my-linear
Ask your AI agent to list Linear issues. Watch 37,000 tokens vanish into a single response full of avatar URLs, custom field schemas, and nested workspace metadata nobody asked for. Congratulations -- your context window is now half gone before the real work begins.
This is what happens when every list_issues call goes through the official Linear MCP. The responses are accurate. They're also enormous.
oh-my-linear reads directly from Linear.app's local IndexedDB cache instead. No API call. No network round-trip. Just the fields you actually care about.
"Give me the issues for team Frontend"
Official MCP: ~37,500 tokens (nested GraphQL, full user objects, attachment metadata, ...)
oh-my-linear: ~2,500 tokens (identifier, title, priority, state, assignee, dueDate)
Same question. 15x less context.
How It Works
Linear.app is an Electron app. Every time you open it, it syncs your workspace into a local IndexedDB (LevelDB on disk). oh-my-linear cracks open that database, parses the binary Chromium storage format, and serves the data as MCP tool responses.
Linear.app (Electron)
-> syncs workspace to local IndexedDB
-> oh-my-linear reads it directly
-> reads: local cache (no API call, <10ms)
-> writes: proxied to official Linear MCP
-> after a write: 30s remote-first window to avoid stale reads
Writes still go through the official MCP -- this isn't trying to replace it. It's a read accelerator that sits in front of it.
The Store Detection Trick
Linear uses hash-based IndexedDB store names that change between app versions. Something like fbaa32a232c2_issues today might be a1b2c3d4e5f6_issues tomorrow. Instead of hardcoding these, oh-my-linear samples the first record from each store and matches the shape -- "has teamId, stateId, title? That's the issues store." Survives Linear updates without code changes.
Setup
One server handles both reads and writes. Replace your existing Linear MCP with this.
Claude Code
# Project scope (default — only this project)
claude mcp add oh-my-linear -- uvx oh-my-linear
# User scope (all projects for this user)
claude mcp add --scope user oh-my-linear -- uvx oh-my-linear
From local checkout:
claude mcp add oh-my-linear -- uvx --from /path/to/oh-my-linear oh-my-linear
Claude Desktop / Cursor / VS Code / Windsurf
{
"mcpServers": {
"oh-my-linear": {
"command": "uvx",
"args": ["oh-my-linear"]
}
}
}
Codex
Use CLI (recommended):
codex mcp add oh-my-linear -- uvx oh-my-linear
codex mcp list
codex mcp get oh-my-linear
Manual config (~/.codex/config.toml):
[mcp_servers.oh-my-linear]
command = "uvx"
args = ["oh-my-linear"]
Scope Guide
| Client | Default scope | How to change |
|---|---|---|
| Claude Code | Project (.mcp.json) |
Add --scope user for user-wide |
| Claude Desktop | Per-app config | N/A |
| Cursor / VS Code | Per-app config | N/A |
| Codex | Global (~/.codex/config.toml) |
N/A |
Requirements
- macOS (Linear.app cache path is macOS-specific)
- Linear.app installed and opened at least once
- Node.js/npm (
npx) for official MCP bridge (mcp-remote) - Network access for writes and fallback reads
Read/Write Policy
| Operation | What happens |
|---|---|
| Read | Local cache first. If local data is missing or degraded, falls back to official MCP. |
| Write | Always goes to official MCP. |
| Read after write | 30-second remote-first window to avoid reading your own stale data. |
Available Tools
Local Read Tools (cache-first, fast)
list_issues / get_issue / list_teams / get_team / list_projects / get_project / list_users / get_user / list_issue_statuses / get_issue_status / list_comments / list_issue_labels / list_initiatives / get_initiative / list_cycles / list_documents / get_document / list_milestones / get_milestone / list_project_updates / get_status_updates
Bridge Tools
official_call_tool-- call any official Linear MCP tool (writes, unsupported reads, etc.)list_official_tools-- discover what the official MCP exposesrefresh_cache-- force reload from local IndexedDBget_cache_health-- check local + official backend status
Write Example
list_official_tools()
official_call_tool(name="create_issue", args={...})
official_call_tool(name="update_issue", args={...})
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
LINEAR_OFFICIAL_MCP_TRANSPORT |
stdio |
stdio or http |
LINEAR_OFFICIAL_MCP_COMMAND |
npx |
Command for stdio transport |
LINEAR_OFFICIAL_MCP_ARGS |
-y mcp-remote https://mcp.linear.app/mcp |
Args for stdio transport |
LINEAR_OFFICIAL_MCP_ENV |
JSON object, env for stdio child process | |
LINEAR_OFFICIAL_MCP_CWD |
Working directory for stdio child process | |
LINEAR_OFFICIAL_MCP_URL |
https://mcp.linear.app/mcp |
URL for http transport |
LINEAR_OFFICIAL_MCP_HEADERS |
JSON headers for http transport | |
LINEAR_FAST_COHERENCE_WINDOW_SECONDS |
30 |
Remote-first window after writes |
LINEAR_FAST_IDLE_REFRESH_SECONDS |
60 |
Idle gap (seconds) before auto-refreshing cache on next tool call |
LINEAR_FAST_PRECONNECT_OFFICIAL |
0 |
1 enables startup preconnect to official MCP (can trigger OAuth prompt at startup) |
LINEAR_FAST_ACCOUNT_EMAILS |
Comma-separated; filter cache to these orgs | |
LINEAR_FAST_USER_ACCOUNT_IDS |
Comma-separated; direct account-id scope |
Auto-Refresh
When no tool call has been made for 60 seconds (configurable via LINEAR_FAST_IDLE_REFRESH_SECONDS), the next call triggers a cache reload so you always get fresh data without manually calling refresh_cache.
Troubleshooting
npx: command not found -- Install Node.js, or set LINEAR_OFFICIAL_MCP_TRANSPORT=http.
Official calls unauthorized -- Official MCP uses mcp-remote for OAuth. Re-run npx -y mcp-remote https://mcp.linear.app/mcp to re-authenticate.
Local data seems stale -- Open Linear.app to trigger a sync, or call refresh_cache.
Linear local DB not found -- Check that it exists:
ls ~/Library/Application\ Support/Linear/IndexedDB/
Server is installed but not visible in Codex app -- Verify with codex mcp list. If listed there, fully restart Codex (quit and relaunch the app).
OAuth prompts appear repeatedly -- Keep LINEAR_FAST_PRECONNECT_OFFICIAL unset (or 0) so official MCP connects only when needed. Use reauth() only when you intentionally want a fresh OAuth login.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file oh_my_linear-0.5.2.tar.gz.
File metadata
- Download URL: oh_my_linear-0.5.2.tar.gz
- Upload date:
- Size: 126.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4aa2c16cb00c2310646ceed6c39551f49daa6c95ba1801f31d2cf24e95adeec
|
|
| MD5 |
f60aa4d64be3fd82d901e61c568376ec
|
|
| BLAKE2b-256 |
92b5d431c9787c273322aa0e9d2004d5ab4c650537b3b2cade7c84a5ac69daa9
|
File details
Details for the file oh_my_linear-0.5.2-py3-none-any.whl.
File metadata
- Download URL: oh_my_linear-0.5.2-py3-none-any.whl
- Upload date:
- Size: 128.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68a2a3a4fa22b1c7d221d688afe3dd9cbaf1166bf0eef554efa8bbba7541a36d
|
|
| MD5 |
b7359ca348906a5d62e0bab20aad8b5d
|
|
| BLAKE2b-256 |
1ebd7d24d9ce44369e7c1cd5f40c7627360db769e1c078e274a3f639aad77064
|