lcode-cli 0.3.0__tar.gz → 0.4.0__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.
Files changed (87) hide show
  1. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/ISSUE_TEMPLATE/model_request.yml +5 -0
  2. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/CHANGELOG.md +40 -1
  3. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/PKG-INFO +8 -4
  4. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/README.md +7 -3
  5. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/SECURITY.md +6 -0
  6. lcode_cli-0.4.0/docs/bench.md +172 -0
  7. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/configuration.md +4 -0
  8. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/how-it-works.md +2 -0
  9. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/index.md +7 -0
  10. lcode_cli-0.4.0/docs/mcp.md +216 -0
  11. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/models.md +2 -2
  12. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/quickstart.md +1 -1
  13. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/troubleshooting.md +6 -0
  14. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/usage.md +4 -0
  15. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/mkdocs.yml +2 -0
  16. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/__init__.py +1 -1
  17. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/agent.py +48 -3
  18. lcode_cli-0.4.0/src/lcode/bench.py +1084 -0
  19. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/cli.py +137 -3
  20. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/config.py +4 -0
  21. lcode_cli-0.4.0/src/lcode/mcp/__init__.py +5 -0
  22. lcode_cli-0.4.0/src/lcode/mcp/auth.py +392 -0
  23. lcode_cli-0.4.0/src/lcode/mcp/catalog.py +109 -0
  24. lcode_cli-0.4.0/src/lcode/mcp/catalog.toml +198 -0
  25. lcode_cli-0.4.0/src/lcode/mcp/client.py +165 -0
  26. lcode_cli-0.4.0/src/lcode/mcp/commands.py +403 -0
  27. lcode_cli-0.4.0/src/lcode/mcp/config.py +221 -0
  28. lcode_cli-0.4.0/src/lcode/mcp/http.py +161 -0
  29. lcode_cli-0.4.0/src/lcode/mcp/manager.py +360 -0
  30. lcode_cli-0.4.0/src/lcode/mcp/protocol.py +124 -0
  31. lcode_cli-0.4.0/src/lcode/mcp/stdio.py +153 -0
  32. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/ollama.py +4 -0
  33. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/permissions.py +3 -1
  34. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/repl.py +52 -1
  35. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/tools.py +27 -0
  36. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/conftest.py +6 -0
  37. lcode_cli-0.4.0/tests/fake_mcp_server.py +113 -0
  38. lcode_cli-0.4.0/tests/test_bench.py +287 -0
  39. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_cli.py +25 -0
  40. lcode_cli-0.4.0/tests/test_mcp.py +524 -0
  41. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.editorconfig +0 -0
  42. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/CODEOWNERS +0 -0
  43. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  44. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  45. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  46. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  47. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/dependabot.yml +0 -0
  48. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/workflows/ci.yml +0 -0
  49. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/workflows/docs.yml +0 -0
  50. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.github/workflows/release.yml +0 -0
  51. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.gitignore +0 -0
  52. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/.pre-commit-config.yaml +0 -0
  53. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/AGENTS.md +0 -0
  54. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  55. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/CONTRIBUTING.md +0 -0
  56. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/LICENSE +0 -0
  57. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/assets/demo.svg +0 -0
  58. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/assets/extra.css +0 -0
  59. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/assets/logo.svg +0 -0
  60. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/assets/social-preview.png +0 -0
  61. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/changelog.md +0 -0
  62. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/contributing.md +0 -0
  63. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/docs/installation.md +0 -0
  64. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/install.sh +0 -0
  65. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/overrides/main.html +0 -0
  66. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/pyproject.toml +0 -0
  67. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/scripts/record_demo.py +0 -0
  68. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/scripts/social-preview.html +0 -0
  69. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/__main__.py +0 -0
  70. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/catalog.py +0 -0
  71. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/checkpoints.py +0 -0
  72. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/hardware.py +0 -0
  73. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/limits.py +0 -0
  74. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/models.toml +0 -0
  75. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/render.py +0 -0
  76. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/sessions.py +0 -0
  77. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/src/lcode/web.py +0 -0
  78. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_agent.py +0 -0
  79. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_catalog.py +0 -0
  80. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_checkpoints.py +0 -0
  81. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_config.py +0 -0
  82. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_context_picker.py +0 -0
  83. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_permissions.py +0 -0
  84. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_sessions.py +0 -0
  85. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_tools.py +0 -0
  86. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/tests/test_web.py +0 -0
  87. {lcode_cli-0.3.0 → lcode_cli-0.4.0}/uv.lock +0 -0
@@ -35,6 +35,11 @@ body:
35
35
  description: Context size used, tokens/s, whether tool calls (reading, editing, running commands) worked reliably, and anything odd.
36
36
  validations:
37
37
  required: true
38
+ - type: textarea
39
+ id: bench
40
+ attributes:
41
+ label: Output of `lcode bench <model> --markdown`
42
+ description: Optional, but the most useful thing you can add. It takes a few minutes; see https://nasser1941.github.io/lcode/bench/
38
43
  - type: textarea
39
44
  id: doctor
40
45
  attributes:
@@ -6,6 +6,43 @@ All notable changes to lcode are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.0] - 2026-10-01
10
+
11
+ ### Added
12
+
13
+ - MCP (Model Context Protocol) servers: the model can use tools from Jira, GitHub, AWS, databases and
14
+ more, with your approval for every call.
15
+ - `lcode mcp add <name>` sets up a ready-made server and tests it: `atlassian`, `aws`,
16
+ `aws-knowledge`, `google-drive`, `grafana`, `gcp`, `github`, `playwright`, `context7`, `sentry`,
17
+ `postgres`, `kubernetes`, `linear` and `notion` (`lcode mcp catalog` lists them).
18
+ - Any other server works too, local (stdio) or remote (Streamable HTTP), configured in
19
+ `~/.config/lcode/mcp.json` in the standard `mcpServers` format, or per project in `.mcp.json`
20
+ (used only after you approve it).
21
+ - Browser sign-in (OAuth 2.1 with PKCE and dynamic client registration) with automatic token
22
+ refresh; `lcode mcp login/logout`.
23
+ - Speaks both the current MCP protocol (2026-07-28) and the earlier `initialize`-based versions.
24
+ - When the tool definitions would take more than 15% of the context window, the model finds tools
25
+ on demand instead (`mcp_tools` setting). `/mcp` shows servers, tools and their context cost;
26
+ `lcode --no-mcp` starts without them.
27
+
28
+ ### Fixed
29
+
30
+ - `lcode bench`: stopping a run with Ctrl+C no longer leaves the running task's temporary folder
31
+ behind, and the summary marks the model as stopped.
32
+ - `lcode bench` no longer lists the model it's about to benchmark as "already loaded".
33
+
34
+ ## [0.3.1] - 2026-09-30
35
+
36
+ ### Added
37
+
38
+ - `lcode bench` scores models on this machine with eight small coding tasks: fixing a bug, finding
39
+ code, writing a script from a spec, renaming across files, a one-line edit in a long file,
40
+ recovering from failing commands, fixing a function to match its spec and adding a feature across
41
+ files. Each task runs in a temporary folder and has an automatic check, some with hidden tests.
42
+ It reports tasks passed, time, generation and prompt speed, tool-call errors and memory use.
43
+ `lcode bench model-a model-b` compares models, `--json` saves the results (a documented, versioned
44
+ format) and `--markdown` prints a table for a model test report.
45
+
9
46
  ## [0.3.0] - 2026-09-30
10
47
 
11
48
  ### Added
@@ -128,7 +165,9 @@ First public release.
128
165
  - `AGENTS.md` project instructions and `/init` to generate them.
129
166
  - One-line installer for Linux and macOS.
130
167
 
131
- [Unreleased]: https://github.com/nasser1941/lcode/compare/v0.3.0...HEAD
168
+ [Unreleased]: https://github.com/nasser1941/lcode/compare/v0.4.0...HEAD
169
+ [0.4.0]: https://github.com/nasser1941/lcode/compare/v0.3.1...v0.4.0
170
+ [0.3.1]: https://github.com/nasser1941/lcode/compare/v0.3.0...v0.3.1
132
171
  [0.3.0]: https://github.com/nasser1941/lcode/compare/v0.2.2...v0.3.0
133
172
  [0.2.2]: https://github.com/nasser1941/lcode/compare/v0.2.1...v0.2.2
134
173
  [0.2.1]: https://github.com/nasser1941/lcode/compare/v0.2.0...v0.2.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lcode-cli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: A local-first terminal coding agent powered by open-weight models on your own GPU or Mac, via Ollama.
5
5
  Project-URL: Homepage, https://nasser1941.github.io/lcode/
6
6
  Project-URL: Documentation, https://nasser1941.github.io/lcode/
@@ -73,13 +73,17 @@ through [Ollama](https://ollama.com), and when it needs current information it c
73
73
  plans multi-step tasks with a visible todo list.
74
74
  - **Long context.** 256K tokens with the default model (1M with Nemotron). You choose the window.
75
75
  - **Hardware-aware.** Detects your NVIDIA GPU or Apple Silicon Mac and picks the best model and the
76
- largest context that fits: `lcode setup` does it in one step.
76
+ largest context that fits: `lcode setup` does it in one step. `lcode bench` compares models on
77
+ real coding tasks on your machine.
77
78
  - **Safe by default.** Every edit is shown as a diff and every command that isn't read-only needs
78
79
  your approval. `auto-edit` and `yolo` modes when you want speed.
79
80
  - **Undo.** lcode saves a checkpoint before the model changes files; `/undo` takes back the last
80
81
  request's edits, new files and shell-command changes, without touching your git history.
81
82
  - **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
82
83
  with tool calling.
84
+ - **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
85
+ Google Cloud, Sentry, Linear, Notion, Postgres, Kubernetes and more with one command
86
+ (`lcode mcp add atlassian`), or any other MCP server. Browser sign-in (OAuth) is built in.
83
87
  - **Web search when needed.** Looks up the latest versions, docs and error messages with Ollama web
84
88
  search, Brave, Tavily or your own SearXNG, and reads pages as clean text.
85
89
  - **Private.** The model runs on your machine, lcode never uploads your files and has no telemetry.
@@ -125,7 +129,9 @@ lcode
125
129
  | `lcode -c` / `lcode --resume` | continue the last session here / pick a saved session from a list |
126
130
  | `lcode --model qwen3.5-9b --context 128k` | pick a model and context window for this session |
127
131
  | `lcode models` / `lcode doctor` | what fits this machine / check the installation |
132
+ | `lcode bench qwen3.6-35b qwen3.5-9b` | compare models on small coding tasks on this machine |
128
133
  | `/undo`, `/rewind` | take back the last request's file changes, or go back further |
134
+ | `lcode mcp catalog` / `lcode mcp add github` | ready-made MCP servers / add one |
129
135
  | `/rename`, `/resume` | name the current session, resume a saved one |
130
136
  | `/model`, `/context`, `/compact`, `/help` | switch model, resize the context window (pick from a list), summarize, list commands |
131
137
 
@@ -170,8 +176,6 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
170
176
 
171
177
  See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
172
178
 
173
- - [`lcode bench`: score models on your own hardware](https://github.com/nasser1941/lcode/issues/5)
174
- - [MCP tool servers](https://github.com/nasser1941/lcode/issues/6)
175
179
  - [Homebrew formula](https://github.com/nasser1941/lcode/issues/8) and an [optional sandbox for shell commands](https://github.com/nasser1941/lcode/issues/9)
176
180
  - More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
177
181
 
@@ -40,13 +40,17 @@ through [Ollama](https://ollama.com), and when it needs current information it c
40
40
  plans multi-step tasks with a visible todo list.
41
41
  - **Long context.** 256K tokens with the default model (1M with Nemotron). You choose the window.
42
42
  - **Hardware-aware.** Detects your NVIDIA GPU or Apple Silicon Mac and picks the best model and the
43
- largest context that fits: `lcode setup` does it in one step.
43
+ largest context that fits: `lcode setup` does it in one step. `lcode bench` compares models on
44
+ real coding tasks on your machine.
44
45
  - **Safe by default.** Every edit is shown as a diff and every command that isn't read-only needs
45
46
  your approval. `auto-edit` and `yolo` modes when you want speed.
46
47
  - **Undo.** lcode saves a checkpoint before the model changes files; `/undo` takes back the last
47
48
  request's edits, new files and shell-command changes, without touching your git history.
48
49
  - **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
49
50
  with tool calling.
51
+ - **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
52
+ Google Cloud, Sentry, Linear, Notion, Postgres, Kubernetes and more with one command
53
+ (`lcode mcp add atlassian`), or any other MCP server. Browser sign-in (OAuth) is built in.
50
54
  - **Web search when needed.** Looks up the latest versions, docs and error messages with Ollama web
51
55
  search, Brave, Tavily or your own SearXNG, and reads pages as clean text.
52
56
  - **Private.** The model runs on your machine, lcode never uploads your files and has no telemetry.
@@ -92,7 +96,9 @@ lcode
92
96
  | `lcode -c` / `lcode --resume` | continue the last session here / pick a saved session from a list |
93
97
  | `lcode --model qwen3.5-9b --context 128k` | pick a model and context window for this session |
94
98
  | `lcode models` / `lcode doctor` | what fits this machine / check the installation |
99
+ | `lcode bench qwen3.6-35b qwen3.5-9b` | compare models on small coding tasks on this machine |
95
100
  | `/undo`, `/rewind` | take back the last request's file changes, or go back further |
101
+ | `lcode mcp catalog` / `lcode mcp add github` | ready-made MCP servers / add one |
96
102
  | `/rename`, `/resume` | name the current session, resume a saved one |
97
103
  | `/model`, `/context`, `/compact`, `/help` | switch model, resize the context window (pick from a list), summarize, list commands |
98
104
 
@@ -137,8 +143,6 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
137
143
 
138
144
  See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
139
145
 
140
- - [`lcode bench`: score models on your own hardware](https://github.com/nasser1941/lcode/issues/5)
141
- - [MCP tool servers](https://github.com/nasser1941/lcode/issues/6)
142
146
  - [Homebrew formula](https://github.com/nasser1941/lcode/issues/8) and an [optional sandbox for shell commands](https://github.com/nasser1941/lcode/issues/9)
143
147
  - More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
144
148
 
@@ -36,6 +36,12 @@ user, in your working directory**. It is not a sandbox. Keep in mind:
36
36
  pages are downloaded from their websites. The model writes the queries, so they can contain names or
37
37
  snippets from your code. Use `web = ask` to approve each search, or `web = off` / `--no-web` to
38
38
  keep everything local.
39
+ - MCP servers you add run as your user (local servers) or act on your accounts (remote servers).
40
+ Every MCP tool call needs your approval unless you're in `yolo` mode or listed the tool under
41
+ `allow`. A project's `.mcp.json` is only used after you approve it, and again after it changes.
42
+ MCP tool results can contain prompt injections, like web pages. Tokens you enter are stored in
43
+ `~/.config/lcode/mcp.json` and sign-in tokens in `~/.local/state/lcode/mcp-auth/`, both readable
44
+ only by you.
39
45
  - Sessions (including file contents the model read) are stored in `~/.local/state/lcode/sessions`.
40
46
  Checkpoints for `/undo` keep copies of your project's files (except ignored ones) in
41
47
  `~/.local/state/lcode/checkpoints` for 14 days; turn them off with `checkpoints = false`.
@@ -0,0 +1,172 @@
1
+ # Benchmarking models
2
+
3
+ `lcode bench` answers the most common question about local models: *which one works best for
4
+ coding on my machine?* It runs a fixed set of small coding tasks against one or more models and
5
+ reports how many they solved, how fast they ran and how much memory they used.
6
+
7
+ ```bash
8
+ lcode bench # the configured model
9
+ lcode bench qwen3.6-35b qwen3.5-9b # compare models
10
+ lcode bench --tasks fix-bug,rename # run some of the tasks
11
+ lcode bench --json results.json # also save machine-readable results
12
+ lcode bench --markdown # also print a table to paste into a test report
13
+ ```
14
+
15
+ ```text
16
+ lcode bench · NVIDIA GeForce RTX 4080 Laptop GPU (12 GB VRAM), 31 GB RAM · Ollama 0.32.15
17
+
18
+ lcode-qwen3.6-35b · 32K context · reasoning on · 8 tasks
19
+ Loaded in 16s · 22.3 GB, 45% on the GPU · reads prompts at 855 tok/s
20
+ ✓ fix-bug Fix a bug so the tests pass 22s the tests pass
21
+ ✓ find-code Answer with file:line 9s next_wait at backoff.py:13
22
+ ✓ write-script Write a script from a spec 13s correct output, also on data it hadn't seen
23
+ ✓ rename Rename a function across files 26s its tests and extra checks pass
24
+ ✓ precise-edit One-line edit in a long file 10s changed only service_087's timeout
25
+ ✓ recover Recover from failing commands 30s used --source and dropped the invalid line
26
+ ✓ spec-fix Fix a function to match its spec 55s follows the whole docstring
27
+ ✓ feature Add a feature across files 71s priorities work, including old todos
28
+ ```
29
+
30
+ At the end it prints a table comparing the models (see [results](#results-on-a-12-gb-laptop) below).
31
+
32
+ A model usually takes 4 to 12 minutes; each task stops after 5 minutes (`--timeout`).
33
+
34
+ ## The tasks
35
+
36
+ Every task runs in a new temporary folder, with every permission granted (`yolo` mode) and web
37
+ access off, and ends with an automatic check. The folders are deleted afterwards unless you pass
38
+ `--keep`, which also keeps each task's transcript (`lcode-bench.log`).
39
+
40
+ | Task | The model has to | Passes when |
41
+ |---|---|---|
42
+ | `fix-bug` | Find and fix a bug so the failing unit tests pass | The tests pass and the test file is unchanged |
43
+ | `find-code` | Answer a question about a small codebase | It names the right function and cites its `file:line` |
44
+ | `write-script` | Write a script from a spec and run it | The script prints the right output, also for data it never saw |
45
+ | `rename` | Rename a function across several files and tests | The old name is gone and extra hidden tests pass |
46
+ | `precise-edit` | Change one value in a 900-line file of near-identical entries | Exactly that one line changed |
47
+ | `recover` | Run a command that fails twice (a removed option, a bad input line) and work around it | The report is correct and only the bad line was dropped |
48
+ | `spec-fix` | Fix a function from a one-line bug report so it does everything its docstring says | Hidden tests of every rule in the docstring pass, edge cases included |
49
+ | `feature` | Add priorities to a small todo app (a new option, sorting, a marker in the output) | Its tests pass, and a scripted session gives the exact expected output, including for todos saved before the change |
50
+
51
+ The first six tasks are everyday work that good models get right; the last two need careful
52
+ reading and are where smaller models tend to slip. The checks are deterministic and can't be passed
53
+ by hard-coding: for example, `write-script` reruns the script on new data, and `rename`, `spec-fix`
54
+ and `feature` are checked with tests the model never saw.
55
+
56
+ ## What's measured
57
+
58
+ | | |
59
+ |---|---|
60
+ | **Passed** | Tasks solved within the time limit |
61
+ | **Time** | Total time for the tasks (loading the model is reported separately) |
62
+ | **Generation** | Output tokens per second, across all the model's responses |
63
+ | **Prompt reading** | Prompt tokens per second: how fast the model reads files and tool output. Measured per model with fresh 4,000-token prompts (the faster of two readings, since the first one after loading includes warm-up), because during the tasks Ollama serves most of each request from its prompt cache |
64
+ | **Tool-call errors** | Tool calls that failed (wrong arguments, editing without reading first, unmatched edits) or that the model wrote as invalid JSON |
65
+ | **Memory** | The model's memory use and how much of it is on the GPU, from Ollama |
66
+
67
+ Results depend on the context window, so `lcode bench` uses **32K** by default on every machine,
68
+ which makes results comparable. When comparing models, each one is unloaded before the next starts
69
+ so every model gets the whole GPU; lcode warns if other models are already loaded. Use `--context 128k` to measure a larger window, and `--no-think`
70
+ to measure a model without reasoning.
71
+
72
+ ## Results on a 12 GB laptop
73
+
74
+ RTX 4080 Laptop GPU (12 GB) with 31 GB of RAM, Ollama 0.32.15, 32K context, reasoning on:
75
+
76
+ | | `qwen3.6-35b` | `qwen3.5-9b` | `qwen3.5-4b` |
77
+ |---|---|---|---|
78
+ | fix-bug | ✓ 22s | ✓ 16s | ✓ 11s |
79
+ | find-code | ✓ 9s | ✓ 6s | ✓ 5s |
80
+ | write-script | ✓ 13s | ✓ 44s | ✗ 18s |
81
+ | rename | ✓ 26s | ✓ 28s | ✓ 30s |
82
+ | precise-edit | ✓ 10s | ✓ 12s | ✓ 8s |
83
+ | recover | ✓ 30s | ✗ 29s | ✓ 24s |
84
+ | spec-fix | ✓ 55s | ✓ 4m 40s | ✗ 2m 57s |
85
+ | feature | ✓ 1m 11s | ✗ 5m 00s | ✓ 47s |
86
+ | **Passed** | **8/8** | **6/8** | **6/8** |
87
+ | Time | 3m 57s | 11m 55s | 5m 20s |
88
+ | Generation | 71.4 tok/s | 60.1 tok/s | 91.3 tok/s |
89
+ | Prompt reading | 855 tok/s | 3,507 tok/s | 5,186 tok/s |
90
+ | Tool-call errors | 0 | 9 | 1 |
91
+ | Memory | 22.3 GB, 45% on GPU | 6.6 GB, 100% on GPU | 4.2 GB, 100% on GPU |
92
+
93
+ The small models fit entirely on the GPU and read prompts much faster, but the larger mixture-of-
94
+ experts model solves more and needs fewer attempts. The small models' failures were real mistakes:
95
+ copying `read_file`'s line numbers into a data file, ignoring negative numbers, missing an edge case
96
+ of the spec, and running out of time.
97
+
98
+ Models sample their answers, so a task near the edge of a model's ability can pass in one run and
99
+ fail in the next (`qwen3.6-35b` scored 7/8 in an earlier run). Compare totals rather than single
100
+ tasks, and run twice before drawing conclusions.
101
+
102
+ ## Sharing results
103
+
104
+ Results from other machines, especially Apple Silicon Macs and other GPUs, decide which models lcode
105
+ recommends. Run
106
+
107
+ ```bash
108
+ lcode bench qwen3.6-35b --markdown
109
+ ```
110
+
111
+ and paste the table into a
112
+ [model test report](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml).
113
+
114
+ ## JSON format
115
+
116
+ `--json FILE` writes one document per run. The schema is versioned: fields may be added, but
117
+ existing fields keep their meaning until `schema` changes.
118
+
119
+ ```json
120
+ {
121
+ "schema": 1,
122
+ "lcode": "0.3.1",
123
+ "ollama": "0.32.15",
124
+ "date": "2026-09-30T19:09:09+02:00",
125
+ "hardware": {
126
+ "os": "linux", "cpu": "13th Gen Intel(R) Core(TM) i9-13980HX", "ram_gib": 30.96,
127
+ "gpu": "NVIDIA GeForce RTX 4080 Laptop GPU", "vram_gib": 11.99, "unified": false,
128
+ "description": "NVIDIA GeForce RTX 4080 Laptop GPU (12 GB VRAM), 31 GB RAM"
129
+ },
130
+ "tasks": [{"id": "fix-bug", "title": "Fix a bug so the tests pass"}, …],
131
+ "runs": [
132
+ {
133
+ "model": "qwen3.6-35b",
134
+ "ollama_model": "lcode-qwen3.6-35b",
135
+ "context": 32768,
136
+ "num_batch": null,
137
+ "think": true,
138
+ "load_seconds": 16.2,
139
+ "prompt_tps": 854.6,
140
+ "memory_gb": 22.3,
141
+ "gpu_percent": 45,
142
+ "passed": 8,
143
+ "total": 8,
144
+ "seconds": 237.3,
145
+ "generation_tps": 71.4,
146
+ "tool_errors": 0,
147
+ "usage": {"requests": 56, "prompt_tokens": 221522, "prompt_ns": 73377987000,
148
+ "output_tokens": 11490, "output_ns": 161017657999},
149
+ "tasks": [
150
+ {"id": "fix-bug", "passed": true, "seconds": 21.9, "detail": "the tests pass",
151
+ "steps": 5, "tool_errors": 0, "error": null},
152
+ …
153
+ ],
154
+ "error": null,
155
+ "interrupted": false
156
+ }
157
+ ]
158
+ }
159
+ ```
160
+
161
+ | Field | Meaning |
162
+ |---|---|
163
+ | `runs[].model` | The name you gave (catalog key or Ollama tag); `ollama_model` is the model that ran |
164
+ | `runs[].context`, `num_batch`, `think` | The settings used. lcode lowers the batch size or context if the GPU runs out of memory, and reports what it ended up using |
165
+ | `runs[].memory_gb`, `gpu_percent` | From Ollama's `/api/ps`; `null` if unavailable |
166
+ | `runs[].generation_tps` | Output tokens per second across the tasks; `null` if Ollama reported no timings |
167
+ | `runs[].prompt_tps` | Prompt tokens per second for a fresh 4,000-token prompt (the faster of two readings); `null` if it couldn't be measured |
168
+ | `runs[].usage` | Totals over the tasks as Ollama reports them. `prompt_tokens` includes tokens served from the prompt cache |
169
+ | `runs[].tasks[].steps` | Model responses in the task |
170
+ | `runs[].tasks[].error` | Why the task stopped early (`timed out after 300s`, an Ollama error), otherwise `null` |
171
+ | `runs[].error` | Why the model didn't run at all (for example, not installed), otherwise `null` |
172
+ | `runs[].interrupted` | You pressed ++ctrl+c++; the results cover the tasks that finished |
@@ -25,6 +25,7 @@ lcode config path # print the file location
25
25
  | `web` | `on` | Web search and page fetching: `on`, `ask` (before each search/website) or `off` |
26
26
  | `search_backend` | `auto` | `auto`, `ollama`, `brave`, `tavily` or `searxng`; `auto` uses the first one configured |
27
27
  | `searxng_url` | | Your SearXNG instance, e.g. `http://localhost:8888` |
28
+ | `mcp_tools` | `auto` | How [MCP](mcp.md#context) tool definitions reach the model: `auto`, `direct` or `search` (on demand) |
28
29
  | `checkpoints` | `true` | Save a checkpoint before the model changes files, so [`/undo`](usage.md#undo-and-checkpoints) can restore them |
29
30
 
30
31
  Example file:
@@ -59,6 +60,9 @@ Environment variables override the file, which is useful for one-off runs and CI
59
60
  | `~/.config/lcode/config.toml` | Settings |
60
61
  | `~/.local/state/lcode/sessions/` | Saved conversations (for `lcode -c`) |
61
62
  | `~/.local/state/lcode/history` | Prompt history (++up++ in the prompt) |
63
+ | `~/.config/lcode/mcp.json` | [MCP servers](mcp.md) (readable only by you; may contain tokens) |
64
+ | `~/.local/state/lcode/mcp-auth/` | Sign-in tokens for remote MCP servers (readable only by you) |
65
+ | `~/.local/state/lcode/mcp-logs/` | Error output of local MCP servers |
62
66
  | `~/.local/state/lcode/checkpoints/` | Checkpoints for `/undo` (copies of your project's files; deleted after 14 days) |
63
67
  | `~/.local/state/lcode/limits.json` | Context sizes that ran out of GPU memory on this machine (safe to delete) |
64
68
 
@@ -75,6 +75,8 @@ the Ollama server you configure, it only contacts the web when the model searche
75
75
  | `agent.py` | System prompt, streaming, tool loop, compaction, sessions |
76
76
  | `tools.py` | Tool schemas and implementations |
77
77
  | `permissions.py` | Approval prompts and the read-only allowlist |
78
+ | `mcp/` | MCP client: stdio and HTTP transports, OAuth sign-in, server settings, the catalog, `lcode mcp` |
79
+ | `bench.py` | `lcode bench`: the benchmark tasks, their checks and the reports |
78
80
  | `checkpoints.py` | Snapshots before the model changes files, for `/undo` and `/rewind` |
79
81
  | `catalog.py`, `models.toml` | Model catalog and memory estimates |
80
82
  | `hardware.py` | NVIDIA / Apple Silicon detection |
@@ -69,6 +69,13 @@ until the task is done, asking before it changes anything.
69
69
  Every edit is shown as a diff and every non-read-only command needs your approval, unless you
70
70
  choose otherwise. `/undo` takes back a request's file changes.
71
71
 
72
+ - :material-connection:{ .lg .middle } **MCP servers**
73
+
74
+ ---
75
+
76
+ Jira, GitHub, AWS, Google Drive, Grafana and more, one command each:
77
+ [`lcode mcp add atlassian`](mcp.md). Browser sign-in is built in.
78
+
72
79
  - :material-swap-horizontal:{ .lg .middle } **Bring your own model**
73
80
 
74
81
  ---
@@ -0,0 +1,216 @@
1
+ # MCP servers
2
+
3
+ The [Model Context Protocol](https://modelcontextprotocol.io) (MCP) lets lcode use tools from other
4
+ systems: your issue tracker, GitHub, cloud accounts, databases, dashboards, a browser. Each MCP server
5
+ adds a set of tools that the model can call, just like reading files or running commands, and every
6
+ call is shown to you for approval first.
7
+
8
+ ```bash
9
+ lcode mcp catalog # ready-made servers
10
+ lcode mcp add atlassian # add one (signs you in through the browser)
11
+ lcode mcp list # check that your servers work
12
+ ```
13
+
14
+ Then start `lcode` as usual and ask, for example, *"Summarize the open bugs assigned to me in Jira
15
+ and find the code for the top one."*
16
+
17
+ ## Ready-made servers
18
+
19
+ `lcode mcp add <name>` sets these up, asks for anything they need and tests the connection:
20
+
21
+ | Name | What it gives the model | You need |
22
+ |---|---|---|
23
+ | `atlassian` | Jira, Confluence, Jira Service Management, Compass, Bitbucket | an Atlassian account (browser sign-in) |
24
+ | `aws` | AWS CLI commands on your account, read-only unless you change it | `uvx` and AWS credentials |
25
+ | `aws-knowledge` | Current AWS documentation, code samples, regional availability | nothing |
26
+ | `google-drive` | Search, read and create files in Google Drive | your own Google OAuth client ([below](#google-drive)) |
27
+ | `grafana` | Dashboards, Prometheus and Loki queries, alerts, incidents | `uvx`, a Grafana service account token |
28
+ | `gcp` | `gcloud` commands on your Google Cloud projects | `npx` and the `gcloud` CLI, signed in |
29
+ | `github` | Repositories, issues, pull requests, Actions | a GitHub token (or the GitHub CLI) |
30
+ | `playwright` | A real (headless) browser: open pages, click, fill forms | `npx` |
31
+ | `context7` | Up-to-date docs and examples for thousands of libraries | nothing (an API key is optional) |
32
+ | `sentry` | Errors, issues, traces and releases | a Sentry account (browser sign-in) |
33
+ | `postgres` | Schemas, read-only queries, query performance | `uvx`, a connection URL |
34
+ | `kubernetes` | Pods, deployments, logs and events, read-only | `npx` and a kubeconfig |
35
+ | `linear` | Issues, projects and cycles | a Linear account (browser sign-in) |
36
+ | `notion` | Pages and databases | a Notion account (browser sign-in) |
37
+
38
+ `npx` comes with [Node.js](https://nodejs.org) (18 or newer) and `uvx` with
39
+ [uv](https://docs.astral.sh/uv/getting-started/installation/). `lcode mcp catalog` shows what's missing
40
+ on your machine.
41
+
42
+ Servers that can change things start read-only where the server supports it (`aws`, `postgres`,
43
+ `kubernetes`); the setup note tells you which setting to change to allow writes.
44
+
45
+ ### Signing in
46
+
47
+ Atlassian, Sentry, Linear and Notion use OAuth: lcode opens your browser, you sign in and approve
48
+ access, and the browser hands a code back to lcode on `localhost`. lcode stores the tokens in
49
+ `~/.local/state/lcode/mcp-auth/` (readable only by you) and refreshes them automatically.
50
+
51
+ ```bash
52
+ lcode mcp login atlassian # sign in again, e.g. after revoking access
53
+ lcode mcp logout atlassian # forget the tokens
54
+ ```
55
+
56
+ In a session, `/mcp login <name>` does the same. On a machine without a browser, lcode prints the
57
+ sign-in URL; open it on any computer that can reach the machine's `localhost` (for example through an
58
+ SSH tunnel), or sign in on your own machine and copy `~/.local/state/lcode/mcp-auth/`.
59
+
60
+ Atlassian organizations can also allow API tokens instead; see
61
+ [Atlassian's guide](https://developer.atlassian.com/cloud/rovo-mcp/guides/configuring-authentication-via-api-token/)
62
+ and add the server [by hand](#adding-your-own-servers) with an `Authorization` header.
63
+
64
+ ### GitHub
65
+
66
+ `lcode mcp add github` offers the GitHub CLI's token if you use `gh`; otherwise create a
67
+ [fine-grained token](https://github.com/settings/personal-access-tokens/new) with access to the
68
+ repositories you want. Only the `repos`, `issues`, `pull_requests` and `actions` toolsets are on, to
69
+ keep the tool list short; change `X-MCP-Toolsets` in `mcp.json` for
70
+ [others](https://github.com/github/github-mcp-server#available-toolsets).
71
+
72
+ ### Google Drive
73
+
74
+ Google doesn't let apps register themselves, so the Drive server needs an OAuth client from your own
75
+ Google Cloud project:
76
+
77
+ 1. In a Google Cloud project, enable the **Google Drive API** and the **Google Drive MCP API**.
78
+ 2. Configure the OAuth consent screen (while it's in testing, add yourself as a test user).
79
+ 3. Create an **OAuth client ID** of type **Desktop app**, and copy its ID and secret.
80
+ 4. Run `lcode mcp add google-drive` and paste them; lcode then signs you in through the browser.
81
+
82
+ See [Google's guide](https://developers.google.com/workspace/guides/configure-mcp-servers) for
83
+ details.
84
+
85
+ ## Adding your own servers
86
+
87
+ Any MCP server works. For a remote server, give its URL; for a local one, the command that starts it:
88
+
89
+ ```bash
90
+ lcode mcp add tracker --url https://mcp.example.com/mcp
91
+ lcode mcp add tracker --url https://mcp.example.com/mcp --header "Authorization: Bearer \${TRACKER_TOKEN}"
92
+ lcode mcp add notes -- npx -y @modelcontextprotocol/server-filesystem /home/me/notes
93
+ lcode mcp add db --env DATABASE_URL=postgres://localhost/app -- uvx some-postgres-mcp
94
+ ```
95
+
96
+ Servers are saved in `~/.config/lcode/mcp.json` in the `mcpServers` format that most MCP servers
97
+ document, so you can also paste a server's example config into that file:
98
+
99
+ ```json
100
+ {
101
+ "mcpServers": {
102
+ "tracker": {
103
+ "type": "http",
104
+ "url": "https://mcp.example.com/mcp",
105
+ "headers": { "Authorization": "Bearer ${TRACKER_TOKEN}" }
106
+ },
107
+ "notes": {
108
+ "command": "npx",
109
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/me/notes"],
110
+ "tools": ["read_file", "search_files"],
111
+ "allow": ["read_file"]
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ | Key | Meaning |
118
+ |---|---|
119
+ | `command`, `args`, `env` | A local server, started by lcode and spoken to over stdin/stdout |
120
+ | `type: "http"`, `url`, `headers` | A remote server (Streamable HTTP). Without an `Authorization` header, lcode signs in with OAuth when the server asks for it |
121
+ | `tools` | Only offer these tools to the model (fewer tools save context and help smaller models) |
122
+ | `allow` | Tools that run without asking; `["*"]` for all of the server's tools |
123
+ | `timeout` | Seconds a tool call may take (default 300) |
124
+ | `disabled` | `true` to turn the server off (`lcode mcp disable <name>`) |
125
+ | `oauth` | For servers that need a pre-registered OAuth client: `client_id`, `client_secret`, `scopes`, `authorize_params` |
126
+
127
+ Values can use environment variables: `${NAME}`, or `${NAME:-default}`. Keep tokens in environment
128
+ variables if you prefer not to store them in the file; `mcp.json` is created readable only by you
129
+ either way.
130
+
131
+ Servers that only offer the old HTTP+SSE transport (URLs ending in `/sse`) aren't supported. Most of
132
+ them also have a Streamable HTTP endpoint (often `/mcp`); otherwise bridge one with
133
+ `npx -y mcp-remote <url>` as a local server.
134
+
135
+ ### Project servers
136
+
137
+ A repository can share servers with everyone who works on it in a `.mcp.json` at its root, in the same
138
+ format. Because those servers run programs or connect to services on your behalf, lcode asks before
139
+ using them the first time, and again whenever the file changes.
140
+
141
+ ## In a session
142
+
143
+ The banner lists your servers. They start in the background, and lcode waits for them (at most a
144
+ couple of minutes, the first time `npx` or `uvx` downloads a server) before your first request.
145
+
146
+ ```text
147
+ ❯ /mcp
148
+ MCP servers
149
+ ┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
150
+ ┃ Server ┃ Status ┃ Tools ┃ Details ┃
151
+ ┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
152
+ │ aws-knowledge │ ready │ 5 │ https://knowledge-mcp.global.api.aws │
153
+ │ everything │ ready │ 13 │ npx -y @modelcontextprotocol/server-everything │
154
+ │ context7 │ ready │ 2 │ https://mcp.context7.com/mcp │
155
+ └───────────────┴────────┴───────┴────────────────────────────────────────────────┘
156
+ Tool definitions: ~6.2K tokens · all sent with every request
157
+ ```
158
+
159
+ A server that can't start shows `failed` with the reason (for example, a missing environment
160
+ variable), and one that needs you to sign in shows `needs sign-in`; the others work normally.
161
+
162
+ | Command | |
163
+ |---|---|
164
+ | `/mcp` | Servers, their status and the context their tools take |
165
+ | `/mcp tools <name>` | A server's tools |
166
+ | `/mcp login <name>` | Sign in (or again) and reconnect |
167
+ | `/mcp restart <name>` | Restart a server, e.g. after changing its settings |
168
+
169
+ Start a session without MCP servers with `lcode --no-mcp`.
170
+
171
+ ### Approvals
172
+
173
+ Every MCP tool call shows the server, the tool and its arguments, and waits for your answer, in the
174
+ `ask` and `auto-edit` modes alike: answer ++y++ (once), ++a++ (always, for this tool, until you quit)
175
+ or ++n++ with an optional reason. Only `yolo` mode, or the server's `allow` list, skips the question.
176
+
177
+ ### Context
178
+
179
+ Every tool definition is sent to the model with every request. A few servers can add tens of
180
+ thousands of tokens, which leaves less room for your code and makes smaller models pick the wrong
181
+ tool. So when the definitions would take more than 15% of the context window, lcode doesn't send
182
+ them: the model sees the tool names, looks up the ones it needs with `mcp_find_tools` and calls them
183
+ with `mcp_call`. `/mcp` and `/context` show which way is used.
184
+
185
+ | `mcp_tools` setting | |
186
+ |---|---|
187
+ | `auto` (default) | Send the definitions if they fit in 15% of the context, otherwise on demand |
188
+ | `direct` | Always send them |
189
+ | `search` | Always on demand |
190
+
191
+ ```bash
192
+ lcode config set mcp_tools search
193
+ ```
194
+
195
+ Limiting a server's `tools` in `mcp.json` is the best fix for a crowded tool list. Some servers are
196
+ large: Grafana offers about 80 tools and Playwright about 25, while most have a handful.
197
+
198
+ ## Troubleshooting
199
+
200
+ - `lcode mcp list` connects to every server and shows what's wrong.
201
+ - A local server's error output is in `~/.local/state/lcode/mcp-logs/<name>.log`.
202
+ - **A `uvx` server fails with a Python error:** some servers don't work on the newest Python yet;
203
+ the ready-made ones pin Python 3.12 with `--python 3.12`, which you can add to your own. A
204
+ `No module named 'mcp.server.fastmcp'` error means the server needs version 1 of the MCP Python
205
+ SDK: add `"--with", "mcp<2"` before the package name in its `args`.
206
+ - **"needs sign-in":** run `lcode mcp login <name>`. If the sign-in page says the redirect URL isn't
207
+ allowed, the service needs a pre-registered client (see [Google Drive](#google-drive)).
208
+ - **Very slow first start:** `npx -y` and `uvx` download the server the first time.
209
+
210
+ ## Protocol support
211
+
212
+ lcode implements MCP tools over stdio and Streamable HTTP, for both the current protocol
213
+ (`2026-07-28`, stateless) and the earlier `initialize`-based versions (`2025-11-25` and before), and
214
+ the MCP authorization spec (OAuth 2.1 with PKCE, protected-resource discovery, dynamic client
215
+ registration and refresh tokens). MCP resources, prompts, sampling and elicitation aren't supported
216
+ yet.
@@ -17,8 +17,8 @@ size, and it works with any other Ollama model that supports tool calling.
17
17
  | `qwen3.5-4b` | Qwen3.5 4B | dense | 3.4 GB | 256K | tested |
18
18
 
19
19
  *Tested* means the model passed lcode's two acceptance tasks end to end (see
20
- [test results](#test-results)). Results on other hardware are very welcome: please
21
- [report how a model does](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml).
20
+ [test results](#test-results)). Results on other hardware are very welcome: run
21
+ [`lcode bench`](bench.md) and [report how a model does](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml).
22
22
 
23
23
  Run `lcode models` to see the same list with what fits on **your** machine:
24
24
 
@@ -12,7 +12,7 @@ lcode
12
12
 
13
13
  ```text
14
14
  ╭──────────────────────────────────────────────╮
15
- │ lcode v0.3.0 — local coding agent │
15
+ │ lcode v0.4.0 — local coding agent │
16
16
  │ │
17
17
  │ model lcode-qwen3.6-35b │
18
18
  │ context 256K tokens │
@@ -62,6 +62,12 @@ of the text-only variant, run `lcode setup <key>` once to create the variant.
62
62
  - Some sites block automated downloads or need JavaScript; with `OLLAMA_API_KEY` set, lcode retries
63
63
  those through Ollama's fetch service.
64
64
 
65
+ ### An MCP server doesn't work
66
+
67
+ Run `lcode mcp list`: it connects to every server and shows why one fails. A local server's error
68
+ output is in `~/.local/state/lcode/mcp-logs/<name>.log`. Remote servers that say *needs sign-in*
69
+ need `lcode mcp login <name>`. More in [MCP servers: Troubleshooting](mcp.md#troubleshooting).
70
+
65
71
  ### It's slow
66
72
 
67
73
  - The first request loads the model (10–45 s). lcode starts loading in the background as soon as it