overleaf-multi-mcp
# overleaf-multi-mcp
A Model Context Protocol (MCP) server that spans **every project on your Overleaf
account**. It auto-discovers your project list, then reads and edits files across
any of them from Claude Code — with a review-before-push local-workspace flow.
Design rationale, trade-offs, and the ToS discussion live in
[`OVERLEAF_MCP_ARCHITECTURE.md`](./OVERLEAF_MCP_ARCHITECTURE.md). This README is
just setup + usage.
## How it works (two auth paths)
| Concern | Mechanism | Where |
|---|---|---|
| **Content I/O** (read/commit/push/history) | `olp_` git token over the sanctioned Git integration | `git.overleaf.com` |
| **Discovery** (listing your projects) | `overleaf_session2` session cookie → internal JSON | `overleaf.com/user/projects` |
The token does all file work. The cookie is used **only** to list projects — never
for content. See the architecture doc's §6 for the ToS caveat around the cookie call.
## Prerequisites
- Node.js ≥ 18 (uses global `fetch`)
- The `git` binary on `PATH`
## Install
```bash
cd /Users/longngo/IdeaProjects/overleaf-mcp
npm install
```
## Configure auth
All state lives in `~/.config/overleaf-mcp/` (override with `OVERLEAF_CONFIG_DIR`).
### 1. Git token (required — content)
Overleaf → **Account Settings → Git Integration** → generate a token (`olp_…`).
The same token works for every project you own.
```bash
mkdir -p ~/.config/overleaf-mcp
printf '%s' 'olp_your_token_here' > ~/.config/overleaf-mcp/token.txt
chmod 600 ~/.config/overleaf-mcp/token.txt
```
(Or set `OVERLEAF_TOKEN` in the environment.)
### 2. Session cookie (optional — discovery only)
Only needed for `sync_projects` / `list_projects`. In a logged-in browser:
DevTools → Application → Cookies → `https://www.overleaf.com` → copy the
`overleaf_session2` value.
```bash
printf '%s' 'overleaf_session2=s:...' > ~/.config/overleaf-mcp/session.txt
chmod 600 ~/.config/overleaf-mcp/session.txt
```
The file may hold either the full `overleaf_session2=s:…` string or just the value.
Cookies expire (~30 days) — when `sync_projects` reports an expiry, refresh this file.
(Or set `OVERLEAF_SESSION`.) Without a cookie the server still works for any project
you reference by ID or set up as a workspace; you just can't auto-list.
## Register with Claude Code
Add to your `.mcp.json` (kept alongside the old single-project entry during
transition, per the architecture doc):
```json
{
"mcpServers": {
"overleaf-multi": {
"command": "node",
"args": ["/Users/longngo/IdeaProjects/overleaf-mcp/src/server.js"],
"env": {
"OVERLEAF_WORKSPACE_ROOT": "/Users/longngo/IdeaProjects/Overleaf"
}
}
}
}
```
Then restart Claude Code. On start the server auto-syncs the project list if a
cookie is present (non-fatal if not).
## Environment variables
| Var | Default | Purpose |
|---|---|---|
| `OVERLEAF_TOKEN` | (reads `token.txt`) | Git token for content I/O |
| `OVERLEAF_SESSION` | (reads `session.txt`) | Session cookie for discovery |
| `OVERLEAF_WORKSPACE_ROOT` | `process.cwd()` | Where `setup_local` puts folders |
| `OVERLEAF_DEFAULT_PROJECT` | — | Name/ID used when `projectName` is omitted |
| `OVERLEAF_CONFIG_DIR` | `~/.config/overleaf-mcp` | State directory |
| `OVERLEAF_BASE_URL` | `https://www.overleaf.com` | Dashboard host (self-hosted CE) |
| `OVERLEAF_GIT_BASE` | `https://git.overleaf.com` | Git host (self-hosted CE) |
| `OVERLEAF_GIT_AUTHOR_NAME` / `_EMAIL` | `Overleaf MCP` / `overleaf-mcp@localhost` | Commit identity |
## Tools (17)
**Discovery** — `sync_projects`, `find_project`, `session_status`, `list_projects`
**Workspace** — `setup_local`, `pull_local`, `diff_local`, `push_local`,
`list_version_history`, `rollback_to_version`
**Content** (workspace-aware) — `list_files`, `read_file`, `get_sections`,
`get_section_content`, `status_summary`, `write_file`, `write_section`
### The core flow: review before push
1. `sync_projects` → `find_project "VCaiLuong"`
2. `setup_local "VCaiLuong"` → clones to `<workspace-root>/VCaiLuong/`
3. `write_section main.tex "Abstract" "…"` → **writes only, no push**
4. `diff_local "VCaiLuong"` (or your IDE Source Control) to review
5. `push_local "VCaiLuong" "Rewrite abstract"` → commits + pushes
Projects **without** a workspace fall back to legacy behavior: `write_file` /
`write_section` clone to a temp dir and commit + push immediately (a `commitMessage`
is required in that mode).
### Rollback
```
list_version_history "VCaiLuong" limit:10
rollback_to_version "VCaiLuong" commitSha:"def5678" paths:["main.tex"] mode:"restore"
# → uncommitted changes; review with diff_local, then push_local
```
`restore` = `git checkout <sha> -- <paths>`; `revert` = undo commits since `<sha>`.
Both leave changes **uncommitted** (nothing is force-pushed). Rollback refuses if the
workspace is dirty unless `force:true`.
## Security notes
- The git token is never placed in argv, in a workspace's `.git/config`, or in error
output. Remotes are stored clean; credentials are supplied per-command via an inline
credential helper reading the token from the child process env.
- Keep `token.txt` and `session.txt` at `chmod 600`.
## Layout
```
src/
├── server.js MCP entry: stdio transport, tool schemas, dispatch, content routing
├── config.js paths, auth, cache.json, workspaces.json, name/ID resolution
├── git.js child_process git wrappers with token masking
├── overleaf.js session-cookie discovery (the only network-JSON module)
└── latex.js \section{…} parsing + section splicing
```
TDQS
Scored across 17 tools
Each tool has a clearly distinct role: project sync/search/status, workspace setup and git operations, file and LaTeX section access, and version management. Even similar-sounding tools like sync_projects and list_projects are differentiated by description (refresh vs. view cached data).
Most tools follow a clear verb_noun snake_case pattern (sync_projects, list_files, write_section). Two status tools (session_status, status_summary) are noun_noun and setup_local is slightly awkward, but the overall style is consistent and readable.
At 17 tools, this is on the higher end but within reason given the server's dual focus on Overleaf project management and local git-synced workspaces. Each tool covers a distinct need, though a few could potentially be merged (e.g., status_summary and session_status) without significant loss.
The tool surface covers the essential lifecycle: project discovery, workspace setup, local editing, diff/push, version history/rollback, and LaTeX-aware reading/writing. Missing operations like project creation/deletion are likely outside the intended scope (session-based account sync), so the core workflows are well-supported.