{
  "markdown": "# myopic\n\n[![PyPI version](https://img.shields.io/pypi/v/myopic.svg)](https://pypi.org/project/myopic/)\n[![Python](https://img.shields.io/pypi/pyversions/myopic.svg)](https://pypi.org/project/myopic/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![MCP Registry](https://img.shields.io/badge/MCP-Registry-7d6ad9.svg)](https://registry.modelcontextprotocol.io)\n\n**The code-review MCP with the most ironic name in the registry.** It's anything\nbut nearsighted — it reviews your merge request against the *whole* codebase, not\njust the diff in front of it.\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/SurajKGoyal/myopic/main/assets/demo.svg\" alt=\"A small diff changes formatPrice to return a string; a diff-only reviewer says it looks fine, but myopic checks the whole repo and finds 4 callers it breaks plus an existing duplicate — neither visible in the diff.\" width=\"720\">\n</p>\n\n> **Building in public.** Reviews **GitLab merge requests and GitHub pull\n> requests** — pass either URL. Reads the change, reviews it against the whole\n> codebase, and can post the review back as inline comments. Issues and PRs welcome.\n\n---\n\n## Why\n\nThe bugs that matter rarely live in the diff. They live in what it *doesn't* show:\nthe caller three files away that now breaks, the convention every sibling file\nfollows that this one quietly drops, the helper that already exists so this new\none is a duplicate. A reviewer that only reads the patch is **myopic**.\n\nmyopic is an open-source [MCP](https://modelcontextprotocol.io) server that gives\nthe AI client you already use (Claude, Cursor, …) the structured context to review\nlike someone who knows the codebase. It runs on your machine — your code never\nleaves it, there's no per-PR bill, and the review happens in your own agent with\nyour own standards:\n\n- **Read the change precisely** — the diff as line-numbered hunks or grouped by\n  function/class, **token-safe on any MR size** (a 10,000-line diff never\n  overflows the context window).\n- **Review it against the whole codebase** — who calls the changed code (blast\n  radius), the caller/callee graph, and — optionally — semantically similar code\n  so you catch broken conventions and duplication.\n\nIt pairs with [amnesic](https://github.com/SurajKGoyal/amnesic), my MCP server\nthat gives AI persistent memory of SQL databases.\n\n---\n\n## Tools\n\nEverything below **works today** unless marked planned.\n\n**Read the merge request (token-safe by construction):**\n\n| Tool | What it does |\n|------|--------------|\n| `mr_review_status` | MR metadata + every discussion thread + resolved/unresolved, in one call |\n| `mr_changed_files` | a content-free manifest of changed files (paths, stats, noise flags) — no diff content, so it stays small even on a huge MR |\n| `mr_diff_sections` | the diff grouped by function/class (AST-aware), budget-bounded |\n| `mr_diff_lines` | the diff as line-numbered hunks — exact positions for inline comments — budget-bounded |\n\nOn a large MR, the diff tools return a bounded page and list the rest under\n`omitted_files` / `truncated` instead of failing; lockfiles, generated code, and\nbinaries are listed but not expanded. Fetch the rest with `files_filter`.\n\n**Review against the whole codebase (point at a local clone):**\n\n| Tool | What it does |\n|------|--------------|\n| `dependency_impact` | everywhere a changed symbol is used — the blast radius (ripgrep + tree-sitter) |\n| `trace_call_chain` | the caller/callee graph of a symbol |\n| `mr_review_context` | **the headline** — for each changed symbol: its impact (always), plus semantically similar code when the optional layer is enabled |\n\n**Semantic layer** (built in — needs Ollama) — `index_repo`, `code_search`,\nand the semantic half of `mr_review_context`. See below.\n\n**Close the loop — verify, and (on request) comment:**\n\n| Tool | What it does |\n|------|--------------|\n| `mr_verify_review` | for each existing review thread, the diff changes near the commented line — did a follow-up commit address it? (read-only) |\n| `mr_post_comments` | **the one write** — post inline comments, one at a time from a queue with exponential backoff (no drafts, no bulk-publish), so partial progress survives and rate limits are respected |\n\nSee [ROADMAP.md](./ROADMAP.md) for what's next.\n\n---\n\n## Install\n\n[pipx](https://pipx.pypa.io) installs myopic isolated and on your PATH:\n\n```bash\npipx install myopic\n```\n\nPrefer a plain venv? `python3 -m venv ~/.venvs/myopic && ~/.venvs/myopic/bin/pip\ninstall myopic`, then use that binary where the examples say `myopic`.\n\n## Setup\n\nmyopic needs a personal access token with `api` (or `read_api`) scope. The wizard\nwalks you through it:\n\n```bash\nmyopic init     # prompts for URL + token, verifies, saves both\nmyopic test     # ✓ Authenticated to https://gitlab.com as <you>\nmyopic doctor   # health-check config + (if enabled) the semantic layer\n```\n\nThe token is saved to `~/.config/myopic/.env` (chmod 600) and referenced from the\nTOML as `${GITLAB_TOKEN}` — never in the config file itself. Rotate it with\n`myopic set-secret`, or hand-edit via `myopic init --template`.\n\n**GitHub PRs:** just pass a PR URL. Set a `GITHUB_TOKEN` (a PAT with\npull-request read access) in your environment or a `[github]` section in\n`config.toml`. For GitHub Enterprise, set `[github].url` to your host.\n\n## Add to your AI client\n\n**Claude Code** — one command, no config editing:\n\n```\n/plugin marketplace add https://github.com/SurajKGoyal/myopic-marketplace\n/plugin install myopic@myopic\n```\n\n**Any other MCP client** (Cursor, Claude Desktop, …) — point it at the `myopic`\ncommand:\n\n```json\n{\n  \"mcpServers\": {\n    \"myopic\": {\n      \"command\": \"myopic\"\n    }\n  }\n}\n```\n\nIf your client can't find it on PATH, use the absolute path (pipx installs to\n`~/.local/bin/myopic`).\n\n### Configure inline instead of `myopic init`\n\nPut the token in the `env` block and skip the config file — myopic reads\n`GITLAB_TOKEN` / `GITHUB_TOKEN` from the environment:\n\n```json\n{\n  \"mcpServers\": {\n    \"myopic\": {\n      \"command\": \"myopic\",\n      \"env\": { \"GITLAB_TOKEN\": \"glpat-…\", \"MYOPIC_AUTO_PULL\": \"1\" }\n    }\n  }\n}\n```\n\n`MYOPIC_AUTO_PULL=1` (optional) pulls a missing embedding model on first use\ninstead of erroring.\n\n## Use\n\nPoint your AI at a merge request:\n\n> \"Review this MR: https://gitlab.com/group/project/-/merge_requests/42\"\n\nA good flow the client can follow: `mr_changed_files` to see the shape →\n`mr_diff_sections` (large MRs) or `mr_diff_lines` to read the change → then, with\na local clone checked out, `dependency_impact` / `trace_call_chain` (or\n`mr_review_context`) on the risky changed symbols to review against everything\nthat depends on them.\n\nThe graph tools analyze whatever is checked out at `root`, so check out the MR's\nbranch first — otherwise you're reviewing the target branch, and the MR's new\ncode isn't there. `myopic worktree <mr-url> <repo>` checks out the MR head in a\nthrowaway worktree (your main checkout untouched) and prints the path to use as\n`root`. `mr_review_context` also warns when `root` doesn't hold the MR's head.\n\n---\n\n## Semantic search (built in — needs Ollama)\n\nFor \"is this consistent with the rest of the codebase?\" — duplication, convention\ndrift, similar patterns — the semantic layer covers it. It's bundled in the base\ninstall (lancedb + httpx); the only external requirement is a running Ollama.\n\nEmbeddings come from a [local Ollama](https://ollama.com) server **you** run —\nyour code never leaves your machine. myopic talks to Ollama over HTTP; it does\nnot bundle or launch it. The one-time prerequisites:\n\n1. Ollama running (default `localhost:11434`, or set `MYOPIC_OLLAMA_URL`).\n2. The embedding model pulled: `ollama pull unclemusclez/jina-embeddings-v2-base-code`.\n\n`myopic doctor` checks both and offers to pull the model for you.\n\nEmbeddings are stored in an embedded [LanceDB](https://lancedb.com) index with\nhybrid (vector + full-text) search, and `mr_review_context` enriches each changed\nsymbol with semantically similar code. **You don't run `index_repo` by hand** —\nit indexes the repo on the first review and refreshes when stale, automatically\n(disable with `MYOPIC_AUTO_INDEX=0`; the graph pass needs no index and always\nruns). `index_repo` / `myopic index` remain for explicit/cron use.\n\n**Indexing is incremental and freshness-aware.** The first `index_repo` is a full\nbuild; after that only files whose content changed are re-embedded, so refreshing\nis cheap. `index_status(root)` reports whether the index is fresh, `stale` (with\nhow many commits behind main), or built on a different model — freshness is\nmeasured against the repo's **main line**, not the current checkout, so reviewing\na feature branch never marks the index stale; only main actually moving does.\n`code_search` and\n`mr_review_context` carry that status so a stale index never silently degrades a\nreview; the AI is told to offer a refresh when it's stale.\n\nThe index is **per repository, not per checkout** — a `myopic worktree` at an MR's\nhead shares its clone's index, so reviewing a new branch never rebuilds it; only\nthe files that branch changed get re-embedded.\n\nA *separate clone* of the same repo does get its own index, and a repo you delete\nleaves one behind. Indexing drops such dead copies automatically; to review and\nreclaim them yourself:\n\n```bash\nmyopic prune            # dry-run: what's stale, and how much it's costing\nmyopic prune --apply    # delete them\n```\n\nA second clone you still use keeps its index — only unreachable ones are removed.\n\nmyopic is a stdio server (no background process), so there's no built-in\nscheduler — but `myopic index /path/to/repo` is the hook for one. Point cron or\nlaunchd at it to keep an index fresh out of band:\n\n```bash\n# refresh hourly (incremental — usually seconds)\n0 * * * * myopic index /path/to/repo\n```\n\nOverride the model/endpoint with `MYOPIC_EMBED_MODEL` / `MYOPIC_OLLAMA_URL`.\n\n---\n\n## Configuration reference\n\n| Source | Key | Notes |\n|--------|-----|-------|\n| `config.toml` | `[gitlab].url` | GitLab base URL (default `https://gitlab.com`) |\n| `config.toml` | `[gitlab].token` | use `${GITLAB_TOKEN}` — don't hardcode |\n| `.env` (next to config) | `GITLAB_TOKEN` | the actual token value (chmod 600) |\n| env var | `MYOPIC_GITLAB_URL` / `GITLAB_URL` | fallback if no TOML |\n| env var | `MYOPIC_GITLAB_TOKEN` / `GITLAB_TOKEN` | fallback if no TOML |\n| env var | `MYOPIC_CONFIG` / `MYOPIC_HOME` | override the config file / directory |\n| env var | `MYOPIC_EMBED_MODEL` / `MYOPIC_OLLAMA_URL` | semantic layer model + endpoint |\n| env var | `MYOPIC_AUTO_INDEX` | `0` to disable auto-indexing during review (default on) |\n| env var | `MYOPIC_AUTO_PULL` | `1` to auto-pull a missing embedding model on first use (default off) |\n\n## Security\n\n- **One explicit write, everything else read-only.** Only `mr_post_comments`\n  mutates a review, and only when you ask for it — every other tool just reads MR\n  and repo data. The write is never speculative.\n- **Your token stays local.** It lives in your `.env` / environment and is sent\n  only to your configured GitLab instance — never to any third party.\n- Auth errors are scrubbed so your token never leaks into error messages.\n- The semantic layer runs entirely locally (your Ollama, an on-disk\n  index) — your code is never sent to a third party.\n\n## Development\n\n```bash\npip install -e \".[dev]\"\npytest                           # hermetic — no network, Ollama, or lancedb needed\n```\n\n## License\n\nMIT © Suraj Goyal\n\n<!-- MCP Registry ownership marker — do not remove. -->\nmcp-name: io.github.SurajKGoyal/myopic\n",
  "bytes": 11607,
  "sha": "fa292d3f2ec05d10273cde40b795ff80d9a680f406064f3735d975a55934c4bd",
  "repo_slug": "surajkgoyal/myopic",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_surajkgoyal_myopic_f5198318/readme"
}