overleaf-forge 2.7.1
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.
- package/LICENSE +22 -0
- package/README.md +277 -0
- package/overleaf-mcp-server.js +1672 -0
- package/package.json +48 -0
- package/projects.example.json +22 -0
- package/templates/context-scaffold.md +34 -0
- package/templates/main.tex +169 -0
- package/writing-guidelines.md +245 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) mjyoo2 (original OverleafMCP, https://github.com/mjyoo2/OverleafMCP)
|
|
4
|
+
Copyright (c) 2026 Aeva (this fork)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# overleaf-forge
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/overleaf-forge) [](#license) 
|
|
4
|
+
|
|
5
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server that lets an AI assistant (Claude Code, Claude Desktop, or any MCP client) read, edit, compile, and verify an [Overleaf](https://www.overleaf.com) project over Overleaf's built-in **git** integration. The model edits a local clone with surgical, conflict-safe operations and pushes to Overleaf; nothing depends on scraping the web UI.
|
|
6
|
+
|
|
7
|
+
> **Acknowledgement.** Forked from [mjyoo2/OverleafMCP](https://github.com/mjyoo2/OverleafMCP), the original Overleaf MCP server. This fork adds conflict-safe editing, binary/figure upload, a clean-build PASS/FAIL gate, citation and voice linting, snapshots, a bootstrap for recurring structured documents, per-project contexts, and a hardened git layer (no-shell `execFile`, credential-helper auth, error redaction).
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
Editing a LaTeX project through an AI normally means one of two bad options: paste files back and forth by hand, or let the model overwrite whole files and hope it didn't clobber an edit you made in the browser. This server removes both. It treats Overleaf's git remote as the source of truth and gives the model **anchored edits** (replace an exact string, refuse if it moved), a **conflict gate** (a stale or concurrent change is detected, never silently overwritten), and a **build verdict** (compile from scratch, PASS only on zero errors and zero undefined references), so an editing session is safe to run unattended and provable when it's done.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Surgical, conflict-safe edits**: `edit_file` replaces an exact anchor and refuses if the region changed on Overleaf; non-overlapping concurrent edits auto-merge via git.
|
|
16
|
+
- **No silent clobbering**: full-file `write_file` requires a freshness token (`baseSha`) or an explicit `overwrite` to replace an existing file.
|
|
17
|
+
- **Binary / figure upload**: push PNG/PDF figures from disk (single or a whole set in one commit), byte-exact, path-confined to the project.
|
|
18
|
+
- **Build verification**: `verify_build` compiles from scratch with `latexmk` and returns PASS/FAIL on the real "done" bar (a PDF, zero errors, zero undefined references/citations) with the page count.
|
|
19
|
+
- **Citation tooling**: append BibTeX entries with duplicate-key protection; lint for undefined and unused citations.
|
|
20
|
+
- **Section-aware reading**: list sections and pull a single section's body by title.
|
|
21
|
+
- **Project grep**: `search_text` over tracked files.
|
|
22
|
+
- **Snapshots**: `checkpoint` a rollback point before a risky edit; `restore` it as a forward commit (no force-push, no history rewrite).
|
|
23
|
+
- **Recurring-document bootstrap**: one call to clone, register, and scaffold a new instance of a structured document (see [Bootstrap](#bootstrap-for-recurring-structured-documents)).
|
|
24
|
+
- **Per-project context**: durable notes and writing guidelines surfaced to the model at the start of a session.
|
|
25
|
+
- **Hardened git layer**: every subprocess runs through `execFile` (no shell), the token is supplied via an environment-backed credential helper and never appears in a command or an error, and tokenized URLs are redacted from any error returned.
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- Node.js ≥ 18 (ESM).
|
|
30
|
+
- `git` on `PATH`.
|
|
31
|
+
- A LaTeX distribution with `latexmk` (only for `compile_file` / `verify_build`; the rest works without it). The default engine is LuaLaTeX; `latexmk` is expected at `/Library/TeX/texbin` (MacTeX) or otherwise on `PATH`.
|
|
32
|
+
- An Overleaf account with **Git integration** enabled (a paid feature at time of writing).
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
For most clients the whole install is a few lines of JSON: point the client at the published npm package via `npx`, which fetches and runs it on demand with nothing to clone or update by hand.
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"overleaf": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "overleaf-forge"],
|
|
44
|
+
"env": {
|
|
45
|
+
"OVERLEAF_GIT_TOKEN": "olp_xxxxxxxxxxxxxxxxxxxxxxxx",
|
|
46
|
+
"OVERLEAF_PROJECT_ID": "0123456789abcdef01234567"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A token and a project id in that `env` block are the entire setup for a single project, with no config file. This is **env-only mode** (see Configuration for the multi-project path).
|
|
54
|
+
|
|
55
|
+
To hack on the server instead, run it from source:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/nomanfoundhere/overleaf-mcp.git
|
|
59
|
+
cd overleaf-mcp
|
|
60
|
+
npm install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then use `"command": "node", "args": ["/absolute/path/to/overleaf-mcp-server.js"]` in the client config in place of the `npx` form.
|
|
64
|
+
|
|
65
|
+
### Wiring into specific clients
|
|
66
|
+
|
|
67
|
+
The `mcpServers` schema is identical across clients; only the file location differs. Put the `npx` block above inside each.
|
|
68
|
+
|
|
69
|
+
| Client | Config file |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Claude Code | `~/.claude.json` |
|
|
72
|
+
| Claude Desktop | `claude_desktop_config.json` (Settings → Developer → Edit Config) |
|
|
73
|
+
| LM Studio | `~/.lmstudio/mcp.json` (or the app's *Edit mcp.json*) |
|
|
74
|
+
| Cursor and others on the Cursor `mcp.json` convention | their `mcp.json` |
|
|
75
|
+
|
|
76
|
+
Restart the client (or reload its MCP servers) after editing, so it spawns the server with the new config.
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
Two modes, smallest first.
|
|
81
|
+
|
|
82
|
+
### Env-only mode (one project, no files)
|
|
83
|
+
|
|
84
|
+
Set `OVERLEAF_GIT_TOKEN` and `OVERLEAF_PROJECT_ID` in the client's `env` block (as in Install). The server builds a single `default` project from them and lands clones under `~/.overleaf-mcp/repos/`. This covers the common single-project case completely.
|
|
85
|
+
|
|
86
|
+
| Env var | Meaning |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| `OVERLEAF_GIT_TOKEN` | Overleaf git token. Required, here or in `projects.json`. |
|
|
89
|
+
| `OVERLEAF_PROJECT_ID` | The id from `https://www.overleaf.com/project/<ID>`. Its presence triggers env-only mode. |
|
|
90
|
+
| `OVERLEAF_PROJECT_NAME` | Optional display name for the synthesized project. |
|
|
91
|
+
| `OVERLEAF_MCP_HOME` | Optional. Override the data home (default `~/.overleaf-mcp`). |
|
|
92
|
+
| `OVERLEAF_MCP_TEMPLATES` | Optional. Override the templates directory. |
|
|
93
|
+
| `OVERLEAF_VOICE_LINTER` | Optional. Prose-linter command for `voice_lint` (alternative to `settings.voiceLinter`). |
|
|
94
|
+
|
|
95
|
+
### Config-file mode (multiple projects, contexts, bootstrap)
|
|
96
|
+
|
|
97
|
+
For more than one project, per-project contexts, or the SSA bootstrap, use a `projects.json`. Scaffold it:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx overleaf-forge init
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That creates `~/.overleaf-mcp/projects.json` from the example and copies the editable templates into `~/.overleaf-mcp/templates/`. Then fill in the config:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"settings": {
|
|
108
|
+
"gitToken": "olp_xxxxxxxxxxxxxxxxxxxxxxxx",
|
|
109
|
+
"repoDir": "/Users/you/Overleaf"
|
|
110
|
+
},
|
|
111
|
+
"projects": {
|
|
112
|
+
"default": {
|
|
113
|
+
"name": "My Paper",
|
|
114
|
+
"projectId": "0123456789abcdef01234567",
|
|
115
|
+
"cwd": "/Users/you/path/where/you/run/the/client"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Setting | Meaning |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `settings.gitToken` | Overleaf git token, used by every project (or set `OVERLEAF_GIT_TOKEN`). A per-project `gitToken` overrides it. |
|
|
124
|
+
| `settings.repoDir` | Where project clones land by default (`repoDir/<name>`). A per-project `localPath` overrides it. |
|
|
125
|
+
| `settings.templatesDir` | Optional. Directory of scaffold templates, overriding the bundled defaults. |
|
|
126
|
+
| `settings.voiceLinter` | Optional. A prose-linter command (or set `OVERLEAF_VOICE_LINTER`) that `voice_lint` runs on a file. No default. |
|
|
127
|
+
| `projects.<key>.projectId` | The id from `https://www.overleaf.com/project/<ID>`. |
|
|
128
|
+
| `projects.<key>.cwd` | Directory you launch the client from for this project; used to auto-detect the active project. |
|
|
129
|
+
| `projects.<key>.localPath` | Explicit clone location (optional). |
|
|
130
|
+
|
|
131
|
+
`projects.json` is re-read on every call, so registering a project or rotating the token takes effect immediately, with no restart. (Code changes do need a restart; the server loads its `.js` once at startup.)
|
|
132
|
+
|
|
133
|
+
### Where files live
|
|
134
|
+
|
|
135
|
+
User state (the `projects.json`, per-project `contexts/`, customised `templates/`, and the git clones) lives in the **data home**, resolved as: `$OVERLEAF_MCP_HOME` if set, else the package directory when it already holds a `projects.json` (so an existing local clone keeps working untouched), else `~/.overleaf-mcp`. Bundled, read-only defaults (the templates and the stock writing-guidelines) ship inside the package; a copy you place in the data home overrides the bundled one.
|
|
136
|
+
|
|
137
|
+
### Getting Overleaf credentials
|
|
138
|
+
|
|
139
|
+
1. **Git token**: Overleaf → Account Settings → Git Integration → create a token. One token covers every project on the account.
|
|
140
|
+
2. **Project ID**: the id segment of the project URL: `https://www.overleaf.com/project/<ID>`.
|
|
141
|
+
|
|
142
|
+
### Per-project context (optional but recommended)
|
|
143
|
+
|
|
144
|
+
Assignment-specific notes (terminology, deadlines, structure constraints, pinned decisions) live in `contexts/<key>.md` under the data home, and shared writing rules in `writing-guidelines.md`. Both are re-read on every `get_context` call, so you can edit them mid-session. `get_context` is the intended first call of a writing session.
|
|
145
|
+
|
|
146
|
+
### Customising the templates
|
|
147
|
+
|
|
148
|
+
The SSA bootstrap scaffolds from two templates: `main.tex` (the document skeleton) and `context-scaffold.md` (the project-questions checklist). Defaults ship with the package. To change them, run `npx overleaf-forge init` (which copies both into `~/.overleaf-mcp/templates/`) and edit them in place, or point `settings.templatesDir` / `OVERLEAF_MCP_TEMPLATES` at your own directory. The tokens `__SSA_NAME__`, `__SSA_TITLE__`, `__SSA_DATE__`, and `__OVERLEAF_READ_URL__` are substituted at scaffold time. A missing template falls back to the built-in default, so a partial templates directory never breaks the bootstrap.
|
|
149
|
+
|
|
150
|
+
## Install via an AI agent
|
|
151
|
+
|
|
152
|
+
Hand this to an agent (Claude Code, Cursor, etc.) to set up the server in the current client:
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
Install the Overleaf MCP server (npm package: overleaf-forge).
|
|
156
|
+
1. Find this client's MCP config file (Claude Code ~/.claude.json, Claude Desktop's
|
|
157
|
+
claude_desktop_config.json, or LM Studio ~/.lmstudio/mcp.json).
|
|
158
|
+
2. Add an "overleaf" entry under mcpServers:
|
|
159
|
+
command: "npx", args: ["-y", "overleaf-forge"]
|
|
160
|
+
with an env block containing OVERLEAF_GIT_TOKEN and OVERLEAF_PROJECT_ID.
|
|
161
|
+
3. Ask me for my Overleaf git token (Account Settings → Git Integration) and the
|
|
162
|
+
project id from my project URL. Do not invent them.
|
|
163
|
+
4. For multiple projects or the SSA bootstrap, run `npx overleaf-forge init`
|
|
164
|
+
and edit ~/.overleaf-mcp/projects.json instead of the env block.
|
|
165
|
+
5. Tell me to restart or reload MCP servers in the client, then call status_summary
|
|
166
|
+
to confirm it connected.
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Quick start
|
|
170
|
+
|
|
171
|
+
A typical editing session, in the model's words:
|
|
172
|
+
|
|
173
|
+
1. *"Read the context for this project."* → `get_context`
|
|
174
|
+
2. *"Show me the sections in `Chapters/ch2.tex`."* → `get_sections`
|
|
175
|
+
3. *"In `Chapters/ch2.tex`, change `\section{Intro}` to `\section{Introduction}`."* → `edit_file` (anchored, conflict-safe)
|
|
176
|
+
4. *"Add a figure: upload `~/plots/fig1.png` to `figures/fig1.png`."* → `upload_file`
|
|
177
|
+
5. *"Verify the build."* → `verify_build` → `✓ PASS — 12 pages`
|
|
178
|
+
|
|
179
|
+
Every write commits and pushes to Overleaf; `verify_build` is the gate before calling the work done.
|
|
180
|
+
|
|
181
|
+
## Conflict safety
|
|
182
|
+
|
|
183
|
+
Edits never silently overwrite a concurrent Overleaf change.
|
|
184
|
+
|
|
185
|
+
- **`edit_file`** pulls the latest first (so a non-overlapping browser edit is absorbed), then replaces an exact anchor string. If the anchor is gone, the region changed since you read it, and the edit refuses rather than guessing. On the rare push race, git performs a real 3-way merge and the edit refuses only on a true overlap.
|
|
186
|
+
- **`write_file`** (full-file create or overwrite) creates a new file freely. To overwrite an existing file it requires either the `baseSha` you got from `read_file` (a stale one is refused) or an explicit `overwrite: true`. It never merges a wholesale replacement; a push race refuses and resets.
|
|
187
|
+
- **`upload_file`** uses the same gate for binaries, never merges, and confines every destination path inside the project clone.
|
|
188
|
+
- An explicit `projectName` that doesn't resolve is an **error**, never a silent fall-through to a different project, so a write cannot land in the wrong repo.
|
|
189
|
+
|
|
190
|
+
## Bootstrap for recurring structured documents
|
|
191
|
+
|
|
192
|
+
`bootstrap_ssa` automates the repetitive setup for documents you create on a recurring schedule, where each instance lives in a predictable folder and follows a naming convention. The built-in convention targets SSAs (the recurring coursework format this fork was built around), but the same shape fits lab notes, weekly reports, meeting minutes, or journal entries.
|
|
193
|
+
|
|
194
|
+
> Bootstrap `https://www.overleaf.com/project/abc123` as `Y1 ABC123 SSA 5`.
|
|
195
|
+
|
|
196
|
+
By the built-in convention this parses the name, locates the parent course folder under `settings.academicRoot/Year <year>/Q*/<COURSE>*`, creates `<parent>/<ssaSubdir>/<name>/`, clones the Overleaf repo into an `overleaf/` subfolder, registers the project, and scaffolds a context file with a question template. Pass `cleanAfterClone: true` when the project was duplicated from a previous instance to wipe the body (chapters, appendices, bib, figures) while keeping the preamble.
|
|
197
|
+
|
|
198
|
+
**Adapting it.** The parsing and folder rules are specific to the SSA scheme; to drive other recurring work, adjust `parseSsaName` / `findCourseFolder` and the `bootstrap_ssa` handler, or skip the bootstrap entirely and `register_project` each instance.
|
|
199
|
+
|
|
200
|
+
## Tools
|
|
201
|
+
|
|
202
|
+
**Project setup & context**
|
|
203
|
+
|
|
204
|
+
| Tool | Purpose |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| `get_context` | Read the writing guidelines + the active project's context. Intended first call of a session. |
|
|
207
|
+
| `list_projects` | List configured projects; mark which one auto-detects from the current directory. |
|
|
208
|
+
| `register_project` | Add or overwrite a project entry without hand-editing JSON. |
|
|
209
|
+
| `set_project_path` | Update a project's `localPath` and/or `cwd`. |
|
|
210
|
+
| `update_context` | Replace or append `contexts/<key>.md`. Takes effect immediately. |
|
|
211
|
+
| `bootstrap_ssa` | One-shot onboarding for a recurring structured document (see above). |
|
|
212
|
+
| `reset_ssa_content` | Empty chapters/appendices/`refs.bib`/figures and optionally rewrite the title block; commit + push. Preamble untouched. |
|
|
213
|
+
|
|
214
|
+
**Reading & search**
|
|
215
|
+
|
|
216
|
+
| Tool | Purpose |
|
|
217
|
+
| --- | --- |
|
|
218
|
+
| `read_file` | Read a file. The first line carries the file's `baseSha` (its git blob hash) for conflict-safe writes. |
|
|
219
|
+
| `list_files` | List files in the project, filtered by extension. |
|
|
220
|
+
| `get_sections` | List `\section` / `\subsection` / `\subsubsection` entries in a `.tex`. |
|
|
221
|
+
| `get_section_content` | Pull a single section's body by title (level-aware: a section keeps its subsections). |
|
|
222
|
+
| `search_text` | Grep tracked files. Regex by default; `fixed` for a literal, `ignoreCase`, `extension` to scope. Returns `file:line:match`. |
|
|
223
|
+
| `status_summary` | File count, main file, section count. |
|
|
224
|
+
|
|
225
|
+
**Editing & figures**
|
|
226
|
+
|
|
227
|
+
| Tool | Purpose |
|
|
228
|
+
| --- | --- |
|
|
229
|
+
| `edit_file` | Anchored `oldString` → `newString` edit + commit + push. Conflict-safe; auto-merges non-overlapping concurrent edits. Preferred for existing files. |
|
|
230
|
+
| `write_file` | Create a new file, or overwrite one wholesale. Existing-file overwrite needs `baseSha` or `overwrite: true`. |
|
|
231
|
+
| `upload_file` | Upload binary file(s) (figures) from a local path. Single or batch (one commit). Byte-exact, path-confined, same conflict gate. |
|
|
232
|
+
|
|
233
|
+
**Building & verification**
|
|
234
|
+
|
|
235
|
+
| Tool | Purpose |
|
|
236
|
+
| --- | --- |
|
|
237
|
+
| `compile_file` | Compile with `latexmk` from the repo root, so the project `.latexmkrc`, reruns, and bibliography all apply; reports errors, undefined refs, overfull boxes. |
|
|
238
|
+
| `verify_build` | Clean-from-scratch compile + PASS/FAIL verdict: PASS only with a PDF and zero errors / undefined references / undefined citations. Reports page count. The done-bar gate. |
|
|
239
|
+
|
|
240
|
+
**Citations, snapshots, voice**
|
|
241
|
+
|
|
242
|
+
| Tool | Purpose |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `add_citation` | Append a BibTeX entry to `refs.bib` (refuses a duplicate key) + push. |
|
|
245
|
+
| `cite_lint` | Report undefined (`\cite` with no entry) and unused (entry never cited) citations. Read-only. |
|
|
246
|
+
| `checkpoint` | Mark a local rollback point (a `mcp-snap/<label>` tag) before a risky edit. |
|
|
247
|
+
| `restore` | Roll back to a checkpoint via a forward commit + push (no force, no history rewrite). |
|
|
248
|
+
| `voice_lint` | Run a configured prose linter (`settings.voiceLinter`) on a `.tex`. Read-only, advisory. |
|
|
249
|
+
|
|
250
|
+
## How it works
|
|
251
|
+
|
|
252
|
+
Each project is a normal git clone of its Overleaf repo, kept under `repoDir` (or `localPath`). On every operation the server pulls the latest, performs the read/edit/build locally, and pushes. Git runs through `execFile` with argument arrays (no shell), so file paths, commit messages, and patterns can't inject commands. Authentication uses an inline git credential helper that reads the token from the process environment, so the token is never written into a remote URL, a command line, or an error message; the clone's `origin` stays token-free. `compile_file` and `verify_build` shell out to `latexmk` from the repo root so the project's own `.latexmkrc` governs the build.
|
|
253
|
+
|
|
254
|
+
## Testing & development
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
npm install
|
|
258
|
+
node --test # run the full suite
|
|
259
|
+
node --check overleaf-mcp-server.js
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Tests run the real client against a throwaway local bare repository that stands in for Overleaf, so the full edit/merge/conflict/upload/snapshot behaviour is exercised with no network and no real account. The `verify_build` log classifier is unit-tested on captured log strings; a single integration test compiles a trivial document and auto-skips when `latexmk` isn't installed, so the suite is green on any machine.
|
|
263
|
+
|
|
264
|
+
## Security
|
|
265
|
+
|
|
266
|
+
- `projects.json` is gitignored; never commit a real token.
|
|
267
|
+
- The token is supplied to git through an environment-backed credential helper and never appears in a command string, a remote URL, or an error. Any tokenized URL that could surface in an error is redacted before it is returned. Rotate by updating `settings.gitToken`; it applies on the next call.
|
|
268
|
+
- All subprocess calls use `execFile` (no shell), so paths, commit messages, and section titles cannot inject shell commands.
|
|
269
|
+
- `upload_file` destinations are resolved and confined inside the project clone (no `..` escape, no absolute paths, not the `.git` directory).
|
|
270
|
+
|
|
271
|
+
## Origin & credits
|
|
272
|
+
|
|
273
|
+
Forked from [mjyoo2/OverleafMCP](https://github.com/mjyoo2/OverleafMCP). The original established the git-integration approach and the base read/write/compile tools; this fork reworked the edit path for conflict safety, hardened the git layer, and added the verification, figure, citation, snapshot, voice, bootstrap, and context tooling.
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
MIT. See [LICENSE](LICENSE) if present, or treat this as MIT per the upstream project.
|