myopic 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myopic-0.0.1/.github/workflows/ci.yml +29 -0
- myopic-0.0.1/.github/workflows/publish.yml +105 -0
- myopic-0.0.1/.gitignore +24 -0
- myopic-0.0.1/LICENSE +21 -0
- myopic-0.0.1/PKG-INFO +182 -0
- myopic-0.0.1/README.md +146 -0
- myopic-0.0.1/ROADMAP.md +83 -0
- myopic-0.0.1/myopic/__init__.py +9 -0
- myopic-0.0.1/myopic/_wizard.py +144 -0
- myopic-0.0.1/myopic/ast_chunker.py +264 -0
- myopic-0.0.1/myopic/cli.py +148 -0
- myopic-0.0.1/myopic/config.py +145 -0
- myopic-0.0.1/myopic/diff.py +203 -0
- myopic-0.0.1/myopic/embeddings.py +54 -0
- myopic-0.0.1/myopic/platforms/__init__.py +1 -0
- myopic-0.0.1/myopic/platforms/base.py +134 -0
- myopic-0.0.1/myopic/platforms/gitlab.py +207 -0
- myopic-0.0.1/myopic/semantic/__init__.py +1 -0
- myopic-0.0.1/myopic/semantic/indexer.py +98 -0
- myopic-0.0.1/myopic/semantic/store.py +72 -0
- myopic-0.0.1/myopic/server.py +366 -0
- myopic-0.0.1/myopic/symbol_patterns.py +55 -0
- myopic-0.0.1/myopic/tools/__init__.py +6 -0
- myopic-0.0.1/myopic/tools/changed_files.py +89 -0
- myopic-0.0.1/myopic/tools/code_search.py +70 -0
- myopic-0.0.1/myopic/tools/dependency_impact.py +316 -0
- myopic-0.0.1/myopic/tools/diff_lines.py +167 -0
- myopic-0.0.1/myopic/tools/diff_sections.py +424 -0
- myopic-0.0.1/myopic/tools/index_repo.py +38 -0
- myopic-0.0.1/myopic/tools/review_context.py +183 -0
- myopic-0.0.1/myopic/tools/review_status.py +104 -0
- myopic-0.0.1/myopic/tools/trace_call_chain.py +329 -0
- myopic-0.0.1/pyproject.toml +54 -0
- myopic-0.0.1/server.json +23 -0
- myopic-0.0.1/tests/test_diff.py +147 -0
- myopic-0.0.1/tests/test_diff_sections.py +158 -0
- myopic-0.0.1/tests/test_diff_tools.py +132 -0
- myopic-0.0.1/tests/test_graph_tools.py +136 -0
- myopic-0.0.1/tests/test_semantic.py +327 -0
- myopic-0.0.1/tests/test_wizard.py +62 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Python ${{ matrix.python-version }}
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: pip install -e .[dev]
|
|
27
|
+
|
|
28
|
+
- name: Run tests
|
|
29
|
+
run: pytest tests/ -v
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: Release (PyPI + GitHub Release + MCP Registry)
|
|
2
|
+
|
|
3
|
+
# One tag push publishes everywhere, in the correct order:
|
|
4
|
+
# 1. Guard — every version source must match the tag, or the release fails loudly.
|
|
5
|
+
# 2. PyPI — build + publish (OIDC Trusted Publishing, no token).
|
|
6
|
+
# 3. GitHub — create the Release with auto-generated notes.
|
|
7
|
+
# 4. Wait — until the new version is live on PyPI (the registry verifies
|
|
8
|
+
# ownership by reading the package's PyPI description).
|
|
9
|
+
# 5. Registry — publish server.json via GitHub OIDC (no token).
|
|
10
|
+
#
|
|
11
|
+
# To cut a release: bump pyproject.toml, myopic/__init__.py, and BOTH version
|
|
12
|
+
# fields in server.json to the same value, commit, then:
|
|
13
|
+
# git tag vX.Y.Z && git push origin vX.Y.Z
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
tags:
|
|
18
|
+
- "v*"
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
release:
|
|
22
|
+
name: Build and publish everywhere
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
permissions:
|
|
26
|
+
id-token: write # OIDC — used by BOTH PyPI Trusted Publishing and the MCP Registry
|
|
27
|
+
contents: write # required for `gh release create`
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
# 1. Guard: tag must equal every version source. Prevents the
|
|
33
|
+
# "server.json left stale" desync from ever shipping silently.
|
|
34
|
+
- name: Verify version consistency
|
|
35
|
+
run: |
|
|
36
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
37
|
+
echo "Tag version: $TAG"
|
|
38
|
+
|
|
39
|
+
PYPROJECT=$(grep -m1 '^version' pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
|
|
40
|
+
INIT=$(grep '__version__' myopic/__init__.py | sed -E 's/.*"([^"]+)".*/\1/')
|
|
41
|
+
SJ_TOP=$(python -c "import json;print(json.load(open('server.json'))['version'])")
|
|
42
|
+
SJ_PKG=$(python -c "import json;print(json.load(open('server.json'))['packages'][0]['version'])")
|
|
43
|
+
|
|
44
|
+
echo "pyproject.toml: $PYPROJECT"
|
|
45
|
+
echo "__init__.py: $INIT"
|
|
46
|
+
echo "server.json (top): $SJ_TOP"
|
|
47
|
+
echo "server.json (pkg): $SJ_PKG"
|
|
48
|
+
|
|
49
|
+
fail=0
|
|
50
|
+
for v in "$PYPROJECT" "$INIT" "$SJ_TOP" "$SJ_PKG"; do
|
|
51
|
+
if [ "$v" != "$TAG" ]; then fail=1; fi
|
|
52
|
+
done
|
|
53
|
+
if [ "$fail" -eq 1 ]; then
|
|
54
|
+
echo "::error::Version mismatch — every source must equal the tag ($TAG). Bump them and re-tag."
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
echo "All version sources match $TAG."
|
|
58
|
+
|
|
59
|
+
- name: Set up Python
|
|
60
|
+
uses: actions/setup-python@v5
|
|
61
|
+
with:
|
|
62
|
+
python-version: "3.11"
|
|
63
|
+
|
|
64
|
+
- name: Build distribution
|
|
65
|
+
run: pip install build && python -m build
|
|
66
|
+
|
|
67
|
+
# 2. PyPI — OIDC Trusted Publishing (configured once at
|
|
68
|
+
# https://pypi.org/manage/account/publishing/). No token.
|
|
69
|
+
- name: Publish to PyPI
|
|
70
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
71
|
+
|
|
72
|
+
# 3. GitHub Release with auto-generated notes from the commits.
|
|
73
|
+
- name: Create GitHub Release
|
|
74
|
+
env:
|
|
75
|
+
GH_TOKEN: ${{ github.token }}
|
|
76
|
+
run: gh release create "${GITHUB_REF#refs/tags/}" --generate-notes --title "${GITHUB_REF#refs/tags/}"
|
|
77
|
+
|
|
78
|
+
# 4. Wait until the version is queryable on PyPI — the registry fetches the
|
|
79
|
+
# package's PyPI description to verify the mcp-name ownership marker.
|
|
80
|
+
- name: Wait for PyPI to serve the new version
|
|
81
|
+
run: |
|
|
82
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
83
|
+
for i in $(seq 1 30); do
|
|
84
|
+
if curl -fsSL "https://pypi.org/pypi/myopic/$TAG/json" >/dev/null 2>&1; then
|
|
85
|
+
echo "myopic $TAG is live on PyPI."
|
|
86
|
+
exit 0
|
|
87
|
+
fi
|
|
88
|
+
echo "Attempt $i: not live yet, waiting 10s..."
|
|
89
|
+
sleep 10
|
|
90
|
+
done
|
|
91
|
+
echo "::error::myopic $TAG did not appear on PyPI within 5 minutes."
|
|
92
|
+
exit 1
|
|
93
|
+
|
|
94
|
+
# 5. Install the registry CLI and publish via GitHub OIDC.
|
|
95
|
+
# The io.github.SurajKGoyal/* namespace is auto-authorized for OIDC
|
|
96
|
+
# tokens from this repo — no allowlist step needed.
|
|
97
|
+
- name: Install mcp-publisher
|
|
98
|
+
run: |
|
|
99
|
+
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
|
|
100
|
+
|
|
101
|
+
- name: Authenticate to MCP Registry (GitHub OIDC)
|
|
102
|
+
run: ./mcp-publisher login github-oidc
|
|
103
|
+
|
|
104
|
+
- name: Publish to MCP Registry
|
|
105
|
+
run: ./mcp-publisher publish
|
myopic-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
|
|
11
|
+
# Virtual envs
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# Secrets / local config
|
|
17
|
+
.env
|
|
18
|
+
*.env
|
|
19
|
+
config.toml
|
|
20
|
+
|
|
21
|
+
# Editors / OS
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
.DS_Store
|
myopic-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Suraj Goyal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
myopic-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: myopic
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: The code-review MCP that reviews your merge request against the whole codebase, not just the diff
|
|
5
|
+
Project-URL: Homepage, https://github.com/SurajKGoyal/myopic
|
|
6
|
+
Project-URL: Repository, https://github.com/SurajKGoyal/myopic
|
|
7
|
+
Project-URL: Issues, https://github.com/SurajKGoyal/myopic/issues
|
|
8
|
+
Author-email: Suraj Goyal <sgoyal275@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-tools,claude,code-review,gitlab,llm,mcp,merge-request
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: click>=8.0
|
|
20
|
+
Requires-Dist: mcp[cli]>=1.0.0
|
|
21
|
+
Requires-Dist: python-gitlab>=4.0
|
|
22
|
+
Requires-Dist: rich>=13.0
|
|
23
|
+
Requires-Dist: tree-sitter-go>=0.23.0
|
|
24
|
+
Requires-Dist: tree-sitter-java>=0.23.0
|
|
25
|
+
Requires-Dist: tree-sitter-javascript>=0.23.0
|
|
26
|
+
Requires-Dist: tree-sitter-python>=0.23.0
|
|
27
|
+
Requires-Dist: tree-sitter-rust>=0.23.0
|
|
28
|
+
Requires-Dist: tree-sitter-typescript>=0.23.0
|
|
29
|
+
Requires-Dist: tree-sitter>=0.24.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Provides-Extra: semantic
|
|
33
|
+
Requires-Dist: httpx>=0.27; extra == 'semantic'
|
|
34
|
+
Requires-Dist: lancedb>=0.15; extra == 'semantic'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# myopic
|
|
38
|
+
|
|
39
|
+
**The code-review MCP with the most ironic name in the registry.** It's anything
|
|
40
|
+
but nearsighted — the goal is to review your merge request against the *whole*
|
|
41
|
+
codebase, not just the diff in front of it.
|
|
42
|
+
|
|
43
|
+
> ⚠️ **Alpha / building in public.** myopic is under active development and
|
|
44
|
+
> currently supports **GitLab merge requests only** — GitHub pull requests are
|
|
45
|
+
> on the roadmap (the platform layer is already abstracted for them). The
|
|
46
|
+
> roadmap below is public on purpose: follow along, open issues, and pitch in.
|
|
47
|
+
> What's checked off works today; the rest is coming. Don't depend on it in a
|
|
48
|
+
> critical workflow yet.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Why
|
|
53
|
+
|
|
54
|
+
Most AI code review looks at the diff in isolation. But the bugs that matter
|
|
55
|
+
live in what the diff *doesn't* show: the caller three files away that now
|
|
56
|
+
breaks, the convention every sibling file follows that this one quietly drops,
|
|
57
|
+
the helper that already exists so this new one is a duplicate, the file nobody
|
|
58
|
+
imports. A reviewer that only reads the patch is **myopic**.
|
|
59
|
+
|
|
60
|
+
myopic is an [MCP](https://modelcontextprotocol.io) server that feeds your AI
|
|
61
|
+
client (Claude, Cursor, etc.) the structured context to review like someone who
|
|
62
|
+
actually knows the codebase — starting with precise, line-numbered access to the
|
|
63
|
+
merge request itself, and growing toward full codebase-aware review (see the
|
|
64
|
+
roadmap).
|
|
65
|
+
|
|
66
|
+
It pairs with [amnesic](https://github.com/SurajKGoyal/amnesic), my MCP server
|
|
67
|
+
that gives AI persistent memory of SQL databases.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Status & roadmap
|
|
72
|
+
|
|
73
|
+
| Tool | What it does | Status |
|
|
74
|
+
|------|--------------|--------|
|
|
75
|
+
| `mr_review_status` | MR metadata + every discussion thread + resolved/unresolved state, in one call | ✅ alpha |
|
|
76
|
+
| `mr_diff_lines` | MR diff as structured, line-numbered hunks — exact positions for inline comments | ✅ alpha |
|
|
77
|
+
| `mr_diff_sections` | AST-grouped diff (by function/class) so large MRs don't blow the token budget | 🔜 planned |
|
|
78
|
+
| `review_with_context` | RAG-augmented review: callers of changed symbols + conventions sibling files follow + duplication + unwired-file detection | 🔜 planned |
|
|
79
|
+
| `mr_post_comments` | bulk-post inline review comments at exact diff positions | 🔜 planned |
|
|
80
|
+
| GitHub pull requests | same tools, GitHub PRs (the platform layer is already abstracted for this) | 🔜 planned |
|
|
81
|
+
|
|
82
|
+
Full details and design notes: [ROADMAP.md](./ROADMAP.md). Ideas and issues
|
|
83
|
+
welcome — that's the point of building this in the open.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Install
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uvx myopic # run directly (recommended)
|
|
91
|
+
# or
|
|
92
|
+
pip install myopic
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Setup
|
|
96
|
+
|
|
97
|
+
myopic needs a GitLab URL and a personal access token with `api` (or `read_api`)
|
|
98
|
+
scope.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
myopic init # writes a config template + prints next steps
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then put your token in `~/.config/myopic/.env`:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Edit `~/.config/myopic/config.toml` if your GitLab is self-hosted (defaults to
|
|
111
|
+
`https://gitlab.com`). Verify it:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
myopic test # ✓ Authenticated to https://gitlab.com as <you>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The token never lives in the TOML — it's referenced as `${GITLAB_TOKEN}` and
|
|
118
|
+
read from the `.env` file (or your environment).
|
|
119
|
+
|
|
120
|
+
## Add to your AI client
|
|
121
|
+
|
|
122
|
+
**Claude Code** (`~/.claude/mcp.json` or project `.mcp.json`):
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"mcpServers": {
|
|
127
|
+
"myopic": {
|
|
128
|
+
"command": "uvx",
|
|
129
|
+
"args": ["myopic"]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The same `command`/`args` work for Claude Desktop, Cursor, and other
|
|
136
|
+
MCP-compatible clients — consult your client's MCP config docs for where the
|
|
137
|
+
file lives.
|
|
138
|
+
|
|
139
|
+
## Use
|
|
140
|
+
|
|
141
|
+
Point your AI at a merge request:
|
|
142
|
+
|
|
143
|
+
> "Review this MR: https://gitlab.com/group/project/-/merge_requests/42"
|
|
144
|
+
|
|
145
|
+
Your client will call `mr_review_status` to orient, then `mr_diff_lines` to read
|
|
146
|
+
exactly what changed with precise line numbers — and review from there.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Configuration reference
|
|
151
|
+
|
|
152
|
+
| Source | Key | Notes |
|
|
153
|
+
|--------|-----|-------|
|
|
154
|
+
| `config.toml` | `[gitlab].url` | GitLab base URL (default `https://gitlab.com`) |
|
|
155
|
+
| `config.toml` | `[gitlab].token` | use `${GITLAB_TOKEN}` — don't hardcode |
|
|
156
|
+
| `.env` (next to config) | `GITLAB_TOKEN` | the actual token value |
|
|
157
|
+
| env var | `MYOPIC_GITLAB_URL` / `GITLAB_URL` | fallback if no TOML |
|
|
158
|
+
| env var | `MYOPIC_GITLAB_TOKEN` / `GITLAB_TOKEN` | fallback if no TOML |
|
|
159
|
+
| env var | `MYOPIC_CONFIG` | override the config file path |
|
|
160
|
+
| env var | `MYOPIC_HOME` | override the config directory |
|
|
161
|
+
|
|
162
|
+
## Security
|
|
163
|
+
|
|
164
|
+
- **Read-oriented today.** The shipped tools only *read* MR data; nothing posts
|
|
165
|
+
or mutates. (Comment-posting on the roadmap will be explicit and opt-in.)
|
|
166
|
+
- **Your token stays local.** It lives in your `.env` / environment and is sent
|
|
167
|
+
only to your configured GitLab instance — never to any third party.
|
|
168
|
+
- Auth errors are scrubbed so your token never leaks into error messages.
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
pip install -e ".[dev]"
|
|
174
|
+
pytest # diff-parser unit tests, no network needed
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT © Suraj Goyal
|
|
180
|
+
|
|
181
|
+
<!-- MCP Registry ownership marker — do not remove. -->
|
|
182
|
+
mcp-name: io.github.SurajKGoyal/myopic
|
myopic-0.0.1/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# myopic
|
|
2
|
+
|
|
3
|
+
**The code-review MCP with the most ironic name in the registry.** It's anything
|
|
4
|
+
but nearsighted — the goal is to review your merge request against the *whole*
|
|
5
|
+
codebase, not just the diff in front of it.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Alpha / building in public.** myopic is under active development and
|
|
8
|
+
> currently supports **GitLab merge requests only** — GitHub pull requests are
|
|
9
|
+
> on the roadmap (the platform layer is already abstracted for them). The
|
|
10
|
+
> roadmap below is public on purpose: follow along, open issues, and pitch in.
|
|
11
|
+
> What's checked off works today; the rest is coming. Don't depend on it in a
|
|
12
|
+
> critical workflow yet.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why
|
|
17
|
+
|
|
18
|
+
Most AI code review looks at the diff in isolation. But the bugs that matter
|
|
19
|
+
live in what the diff *doesn't* show: the caller three files away that now
|
|
20
|
+
breaks, the convention every sibling file follows that this one quietly drops,
|
|
21
|
+
the helper that already exists so this new one is a duplicate, the file nobody
|
|
22
|
+
imports. A reviewer that only reads the patch is **myopic**.
|
|
23
|
+
|
|
24
|
+
myopic is an [MCP](https://modelcontextprotocol.io) server that feeds your AI
|
|
25
|
+
client (Claude, Cursor, etc.) the structured context to review like someone who
|
|
26
|
+
actually knows the codebase — starting with precise, line-numbered access to the
|
|
27
|
+
merge request itself, and growing toward full codebase-aware review (see the
|
|
28
|
+
roadmap).
|
|
29
|
+
|
|
30
|
+
It pairs with [amnesic](https://github.com/SurajKGoyal/amnesic), my MCP server
|
|
31
|
+
that gives AI persistent memory of SQL databases.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Status & roadmap
|
|
36
|
+
|
|
37
|
+
| Tool | What it does | Status |
|
|
38
|
+
|------|--------------|--------|
|
|
39
|
+
| `mr_review_status` | MR metadata + every discussion thread + resolved/unresolved state, in one call | ✅ alpha |
|
|
40
|
+
| `mr_diff_lines` | MR diff as structured, line-numbered hunks — exact positions for inline comments | ✅ alpha |
|
|
41
|
+
| `mr_diff_sections` | AST-grouped diff (by function/class) so large MRs don't blow the token budget | 🔜 planned |
|
|
42
|
+
| `review_with_context` | RAG-augmented review: callers of changed symbols + conventions sibling files follow + duplication + unwired-file detection | 🔜 planned |
|
|
43
|
+
| `mr_post_comments` | bulk-post inline review comments at exact diff positions | 🔜 planned |
|
|
44
|
+
| GitHub pull requests | same tools, GitHub PRs (the platform layer is already abstracted for this) | 🔜 planned |
|
|
45
|
+
|
|
46
|
+
Full details and design notes: [ROADMAP.md](./ROADMAP.md). Ideas and issues
|
|
47
|
+
welcome — that's the point of building this in the open.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uvx myopic # run directly (recommended)
|
|
55
|
+
# or
|
|
56
|
+
pip install myopic
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Setup
|
|
60
|
+
|
|
61
|
+
myopic needs a GitLab URL and a personal access token with `api` (or `read_api`)
|
|
62
|
+
scope.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
myopic init # writes a config template + prints next steps
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then put your token in `~/.config/myopic/.env`:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Edit `~/.config/myopic/config.toml` if your GitLab is self-hosted (defaults to
|
|
75
|
+
`https://gitlab.com`). Verify it:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
myopic test # ✓ Authenticated to https://gitlab.com as <you>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The token never lives in the TOML — it's referenced as `${GITLAB_TOKEN}` and
|
|
82
|
+
read from the `.env` file (or your environment).
|
|
83
|
+
|
|
84
|
+
## Add to your AI client
|
|
85
|
+
|
|
86
|
+
**Claude Code** (`~/.claude/mcp.json` or project `.mcp.json`):
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"myopic": {
|
|
92
|
+
"command": "uvx",
|
|
93
|
+
"args": ["myopic"]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The same `command`/`args` work for Claude Desktop, Cursor, and other
|
|
100
|
+
MCP-compatible clients — consult your client's MCP config docs for where the
|
|
101
|
+
file lives.
|
|
102
|
+
|
|
103
|
+
## Use
|
|
104
|
+
|
|
105
|
+
Point your AI at a merge request:
|
|
106
|
+
|
|
107
|
+
> "Review this MR: https://gitlab.com/group/project/-/merge_requests/42"
|
|
108
|
+
|
|
109
|
+
Your client will call `mr_review_status` to orient, then `mr_diff_lines` to read
|
|
110
|
+
exactly what changed with precise line numbers — and review from there.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Configuration reference
|
|
115
|
+
|
|
116
|
+
| Source | Key | Notes |
|
|
117
|
+
|--------|-----|-------|
|
|
118
|
+
| `config.toml` | `[gitlab].url` | GitLab base URL (default `https://gitlab.com`) |
|
|
119
|
+
| `config.toml` | `[gitlab].token` | use `${GITLAB_TOKEN}` — don't hardcode |
|
|
120
|
+
| `.env` (next to config) | `GITLAB_TOKEN` | the actual token value |
|
|
121
|
+
| env var | `MYOPIC_GITLAB_URL` / `GITLAB_URL` | fallback if no TOML |
|
|
122
|
+
| env var | `MYOPIC_GITLAB_TOKEN` / `GITLAB_TOKEN` | fallback if no TOML |
|
|
123
|
+
| env var | `MYOPIC_CONFIG` | override the config file path |
|
|
124
|
+
| env var | `MYOPIC_HOME` | override the config directory |
|
|
125
|
+
|
|
126
|
+
## Security
|
|
127
|
+
|
|
128
|
+
- **Read-oriented today.** The shipped tools only *read* MR data; nothing posts
|
|
129
|
+
or mutates. (Comment-posting on the roadmap will be explicit and opt-in.)
|
|
130
|
+
- **Your token stays local.** It lives in your `.env` / environment and is sent
|
|
131
|
+
only to your configured GitLab instance — never to any third party.
|
|
132
|
+
- Auth errors are scrubbed so your token never leaks into error messages.
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pip install -e ".[dev]"
|
|
138
|
+
pytest # diff-parser unit tests, no network needed
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT © Suraj Goyal
|
|
144
|
+
|
|
145
|
+
<!-- MCP Registry ownership marker — do not remove. -->
|
|
146
|
+
mcp-name: io.github.SurajKGoyal/myopic
|
myopic-0.0.1/ROADMAP.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# myopic roadmap
|
|
2
|
+
|
|
3
|
+
myopic is built in the open and shipped in small increments. This file is the
|
|
4
|
+
honest source of truth for what works, what's next, and why. If something here
|
|
5
|
+
interests you, open an issue or a PR — design discussion is welcome.
|
|
6
|
+
|
|
7
|
+
The north star: **review a change against the whole codebase, not just the
|
|
8
|
+
diff.** Everything below ladders up to that.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## ✅ Shipped (alpha)
|
|
13
|
+
|
|
14
|
+
### `mr_review_status(url)`
|
|
15
|
+
One snapshot of where a review stands: MR metadata, every discussion thread,
|
|
16
|
+
which are resolved vs open, general comments, and a lightweight file-change
|
|
17
|
+
summary. Replaces 5-6 separate GitLab API calls.
|
|
18
|
+
|
|
19
|
+
### `mr_diff_lines(url, files_filter?, lines_filter?)`
|
|
20
|
+
The merge request diff as structured, line-numbered hunks — every line tagged
|
|
21
|
+
add/del/context with exact old and new line numbers. This is the foundation for
|
|
22
|
+
precise inline comments: `lines_filter` translates "comment on source line N"
|
|
23
|
+
into the exact diff position the API needs. `files_filter` keeps large reviews
|
|
24
|
+
under token limits.
|
|
25
|
+
|
|
26
|
+
### Platform-abstraction seam
|
|
27
|
+
All tools talk to a normalized `Review` interface, never to a platform SDK
|
|
28
|
+
directly. GitLab is the first implementation; GitHub is a new implementation,
|
|
29
|
+
not a rewrite (see below).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🔜 Next
|
|
34
|
+
|
|
35
|
+
### `mr_diff_sections(url)` — AST-grouped diffs
|
|
36
|
+
Group changed lines by the function/class they belong to (via tree-sitter) so a
|
|
37
|
+
1,000-line MR can be reviewed structurally instead of overflowing the context
|
|
38
|
+
window. All changed lines preserved; context optional.
|
|
39
|
+
|
|
40
|
+
### `review_with_context(url, repo_path)` — the actual point
|
|
41
|
+
This is myopic's reason to exist. For each changed symbol, surface:
|
|
42
|
+
- **Callers** of modified public symbols (what might break).
|
|
43
|
+
- **Conventions** sibling/similar files follow that this change drops
|
|
44
|
+
(missing imports, hooks, error handling).
|
|
45
|
+
- **Intra-MR duplication** — near-identical new files copy-pasted within the MR.
|
|
46
|
+
- **Unwired files** — new files nothing imports or references (dead on arrival).
|
|
47
|
+
|
|
48
|
+
Pure structured context, no LLM judgment — the calling agent reviews; myopic
|
|
49
|
+
makes sure it isn't reviewing blind. This depends on a codebase index; the
|
|
50
|
+
indexing approach (and how to keep setup friction near zero) is the main open
|
|
51
|
+
design question. **Ideas welcome.**
|
|
52
|
+
|
|
53
|
+
### `mr_post_comments(url, comments[])` — explicit, opt-in writes
|
|
54
|
+
Bulk-post inline review comments at exact diff positions (resolved via
|
|
55
|
+
`mr_diff_lines`), rate-limited for self-hosted GitLab. Writes will always be
|
|
56
|
+
explicit and clearly separated from the read-only tools.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🔭 Later
|
|
61
|
+
|
|
62
|
+
### GitHub pull requests
|
|
63
|
+
The platform layer is already abstracted (`myopic/platforms/base.py`). GitHub
|
|
64
|
+
support is a `GitHubPlatform` + `GitHubReview` implementing the same interface —
|
|
65
|
+
the tools don't change. This is why the project isn't named `gitlab-*`.
|
|
66
|
+
|
|
67
|
+
### Other ideas on the table
|
|
68
|
+
- CI/pipeline status + failed-job logs alongside the review.
|
|
69
|
+
- Review-thread verification: did a later commit actually address each comment?
|
|
70
|
+
- Configurable review "lenses" (security-only, performance-only, conventions-only).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Design principles
|
|
75
|
+
|
|
76
|
+
1. **Tools return data, not opinions.** myopic gathers context; the agent reviews.
|
|
77
|
+
2. **Read and write are separate and obvious.** No tool silently mutates.
|
|
78
|
+
3. **Setup friction approaches zero.** If a feature needs heavy local infra, that
|
|
79
|
+
friction is itself a design problem to solve, not a given.
|
|
80
|
+
4. **Platform-neutral core.** Diffs and reviews are abstracted; GitLab is just the
|
|
81
|
+
first backend.
|
|
82
|
+
|
|
83
|
+
Have a better idea for any of these? Open an issue.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
myopic — the code-review MCP server with the most ironic name in the registry.
|
|
3
|
+
|
|
4
|
+
It's anything but nearsighted. It reviews your merge request against the *whole*
|
|
5
|
+
codebase — callers, conventions, duplication, dead code — not just the diff in
|
|
6
|
+
front of it.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.0.1"
|