overleaf-web-mcp
v0.1.2
Published
Unofficial MCP server for browsing, tracked writing, organizing, compiling, reviewing, and monitoring version history in Overleaf projects through an authenticated web session.
Downloads
83
Maintainers
Readme
| Connect | Organize | Write | Compile | Review | History | | :---: | :---: | :---: | :---: | :---: | :---: | | Dedicated Chrome-family profile and saved session | Browse projects and manage files, folders, uploads, and downloads | Revision-checked whole-file and section edits, optionally tracked | Build a selected root document and stop active compiles | List, anchor, reply, resolve, and reopen comments | Poll recent project updates with a version cursor |
Overleaf Web MCP is an independent Node.js Model Context Protocol server for complete Overleaf project workflows. It uses browser-facing private REST endpoints plus Socket.IO/OT through a saved web session, without requiring Overleaf Git integration.
[!CAUTION] This is an unofficial client for unsupported private APIs. Overleaf may change these interfaces without notice, and automating
www.overleaf.commay carry Terms-of-Service and account risk. Start with a disposable project, keep live-test volume low, and review Overleaf's current terms before using an important account.
Quick start
Requirements:
- Node.js 20 or newer
- Google Chrome, Chromium, Brave, or Microsoft Edge for browser-assisted login
- An Overleaf account with access to the target projects
Capture and verify a session:
npx overleaf-web-mcp loginConfigure an MCP client to start the package over stdio:
{
"mcpServers": {
"overleaf": {
"command": "npx",
"args": ["-y", "overleaf-web-mcp", "serve"]
}
}
}The serve command is the default and can be omitted.
From the repository root:
npm install
npm run build
npm run login
npm startnpm run login opens a dedicated browser window. Complete the normal Overleaf sign-in flow, including SSO or two-factor authentication when required. The window closes after authentication is detected, and the package saves only cookies applicable to the configured Overleaf origin.
Use the same origin for login and the MCP server:
OVERLEAF_BASE_URL=https://overleaf.example.org npx overleaf-web-mcp login{
"mcpServers": {
"overleaf": {
"command": "npx",
"args": ["-y", "overleaf-web-mcp", "serve"],
"env": {
"OVERLEAF_BASE_URL": "https://overleaf.example.org"
}
}
}
}Private API and feature availability varies by Overleaf deployment and edition.
Tools
The server registers 19 tools. Expand only the areas you need.
| Tool | Purpose |
| --- | --- |
| auth_status | Verify the saved web session without exposing cookies |
| list_projects | List projects available to the authenticated account |
| Tool | Purpose |
| --- | --- |
| get_project_tree | Return the current file and folder tree with paths and entity IDs |
| read_file | Read LF-normalized text and its opaque revision |
| write_file | Replace text through a minimal verified OT update; optionally use tracked changes |
| create_file | Create a text document and optionally track non-empty initial content |
| manage_entity | Create folders and rename, move, or confirmed-delete entities |
| upload_file | Upload a local binary file to a project folder |
| download_file | Download a document or binary file to an explicit local path |
write_file and non-empty create_file content accept writeMode: "untracked" | "tracked". The default is "untracked" for backward compatibility. Tracked file creation requires non-empty initial content; creating the file entity itself remains a normal project-tree operation.
| Tool | Purpose |
| --- | --- |
| get_sections | Parse section headings in one LaTeX file |
| get_section_content | Read one parsed section body |
| write_section | Replace one section body with a revision-checked tracked or untracked write |
Section parsing is single-file only. It recognizes starred headings and optional titles, ignores % comments and common verbatim-like environments, and never follows \input or \include.
| Tool | Purpose |
| --- | --- |
| compile_project | Compile a project using a selected root document |
| stop_compile | Stop the active compile for a project |
| Tool | Purpose |
| --- | --- |
| list_comments | List and filter threads with lazy source-range resolution |
| reply_to_comment | Reply to an existing thread with timeout deduplication |
| add_comment | Create and verify a thread anchored to exact source text |
| set_comment_status | Resolve or reopen a thread and verify the resulting state |
add_comment uses 1-based line and UTF-16 column positions. The normalized live selection must exactly equal expectedText.
| Tool | Purpose |
| --- | --- |
| monitor_project_history | Poll one recent update window and return entries newer than an optional version cursor |
This is stateless client-driven polling, not a background watcher. Results include currentVersion, nextSinceVersion, hasEarlierHistory, and gapDetected, plus normalized update groups with authors, paths, file-tree operations, labels, and origin metadata. Author emails and raw private response fields are omitted.
Key safety contracts:
- Reads normalize CRLF and lone CR to LF and report
newline: "LF". - Revisions are opaque concurrency tokens containing project and document identity, OT protocol, version, and a SHA-256 content hash. Callers should retain but never construct them.
- Content writes use minimal OT edits and are verified against a freshly joined document. Ambiguous writes are observed during a bounded recovery window and are never retried automatically.
- Explicit tracked writes never silently fall back to untracked writes. They require an authenticated user ID, while
trackChangesActiveseparately reports the project state observed at connection time. manage_entitydeletion requiresconfirmPathto exactly equalpath.
Common workflows
- Call
list_projects, thenget_project_tree. - Use
create_filefor text, ormanage_entityto create folders and rename, move, or confirmed-delete entities. - Use
upload_filefor local binaries anddownload_fileto save documents or binaries to explicit local paths.
- Call
read_fileand retain itsrevision. - Modify the LF-normalized content.
- Call
write_filewith the unchanged revision, complete replacement content, and the desired mode:
{
"projectId": "0123456789abcdef01234567",
"filePath": "main.tex",
"revision": "opaque-revision-from-read-file",
"content": "\\section{Introduction}\nRevised text.\n",
"writeMode": "tracked"
}- If
REVISION_CONFLICTis returned, read again and reconcile against the new content; never reuse the stale revision.
create_file and write_section accept the same writeMode choice and return the resulting revision. A no-op write returns successfully but creates no tracked record.
Call monitor_project_history without a cursor to establish the current window:
{
"projectId": "0123456789abcdef01234567"
}On the next poll, pass the previous nextSinceVersion as sinceVersion. Only update groups whose toVersion is newer are returned. If gapDetected is true, the cursor predates the single returned window; the tool deliberately does not page backward or calculate diffs.
- Call
compile_projectwith the selected root document. - Use
stop_compileto stop an active compile.
- Call
list_comments; it defaults to open threads and accepts file, status, and author filters. - Use
reply_to_commentfor an existing thread. - To anchor a new thread, call
read_file, select an exact range, then pass its revision, UTF-16 positions,expectedText, and message toadd_comment. - Pass the latest revision to
set_comment_statuswhen resolving or reopening an anchored thread.
All review-panel threads include available author metadata. Overleaf does not expose a reliable separate reviewer classification. Review comments and tracked changes require an Overleaf deployment and account entitlement that supports them.
Configuration, authentication, and security
The cookie jar is local, never returned by a tool, and protected with restrictive permissions where the filesystem supports them. The server reserves stdout for MCP protocol messages and does not log cookies, filenames, document content, diffs, quoted context, or review-message bodies.
| Variable | Default | Purpose |
| --- | ---: | --- |
| OVERLEAF_COOKIE_JAR_FILE | Platform configuration directory | Saved-session path override |
| OVERLEAF_BASE_URL | https://www.overleaf.com | Target Overleaf origin |
| OVERLEAF_BROWSER_PATH | Auto-detected | Chrome-family executable used by login |
| OVERLEAF_BROWSER_PROFILE_DIR | Platform configuration directory | Dedicated login profile |
| OVERLEAF_LOGIN_TIMEOUT_MS | 300000 | Browser sign-in deadline, capped at 15 minutes |
| OVERLEAF_PROTOCOL_VERSIONS | 2 | Comma-separated accepted collaboration protocol versions |
| OVERLEAF_MAX_DOC_LENGTH | 2097152 | Fallback maximum UTF-16 document length |
| OVERLEAF_MAX_UPDATE_CHARS | 7340032 | Conservative serialized OT update limit |
| OVERLEAF_SOCKET_CACHE_SIZE | 2 | Maximum cached project sockets |
| OVERLEAF_SOCKET_IDLE_TTL_MS | 90000 | Idle project-socket lifetime |
| OVERLEAF_REQUEST_TIMEOUT_MS | 30000 | REST and collaboration-call timeout |
| OVERLEAF_APPLY_TIMEOUT_MS | 30000 | OT acknowledgement and application timeout |
| OVERLEAF_RECOVERY_TIMEOUT_MS | 30000 | Ambiguous-mutation observation window |
| OVERLEAF_COMPILE_TIMEOUT_MS | 120000 | Default compile wait, capped at 15 minutes |
An advertised ol-maxDocLength value takes precedence over the fallback. Target content at or above the limit returns DOC_TOO_LARGE; an oversized serialized update returns UPDATE_TOO_LARGE and must be split into smaller independently revisioned writes.
compile_project.timeoutMs accepts 1 second through 15 minutes. It changes only how long the MCP call waits, not the account's server-side compile allowance.
The login command uses a separate browser profile and does not inspect the normal Chrome profile. Session files are stored under overleaf-web-mcp in the platform configuration directory:
- Linux:
${XDG_CONFIG_HOME:-~/.config}/overleaf-web-mcp - macOS:
~/Library/Application Support/overleaf-web-mcp - Windows:
%APPDATA%\overleaf-web-mcp
Only cookies applicable to OVERLEAF_BASE_URL are saved. On POSIX systems, the configuration directory uses mode 0700 and the cookie jar mode 0600; group- or world-readable jars are rejected. Filesystems without meaningful POSIX modes continue with a permissionsUnchecked warning.
Cookie refreshes are merged under an advisory lock and written through a protected temporary file followed by atomic replacement. If the session expires, run npx overleaf-web-mcp login again.
Technical details and ecosystem
The entries below are representative rather than exhaustive, and their capabilities may change over time.
| Implementation | Connection model | Focus |
| --- | --- | --- |
| This project | Browser-assisted saved session plus private REST and Socket.IO/OT | Project/file management, tracked writing, compilation, review/replies, and recent history monitoring |
| @netique/overleaf-mcp | Browser session plus private REST and Socket.IO/OT | A close web/OT peer with review comments and tracked-change workflows |
| overleaf-mcp-rt | Session authentication plus native OT | Real-time file and compile tooling focused on self-hosted Community Edition |
| Git-based projects: OverleafMCP, overleaf-mcp-server, and vibeTeX | Primarily the Overleaf Git bridge | Git-backed synchronization, editing, and history workflows |
Review-range investigation was informed by Overleaf Comment Exporter. Real-time protocol behavior was informed by Overleaf Workshop.
- The collaboration adapter implements the Socket.IO 0.9 wire format used by the targeted Overleaf client family. Project bootstrap rejects unsupported protocol versions.
- ShareJS text OT and history-OT are normalized behind one document interface. Tracked ShareJS writes carry the authenticated author in update metadata; tracked history-OT writes carry author and timestamp metadata on inserted and retained-deletion components.
- Visible history-OT offsets account for tracked deletions retained in the raw snapshot.
- At most two project sockets are cached by default. Active sockets are never evicted, and idle sockets disconnect after 90 seconds. While a project socket remains open, the account may appear online to collaborators.
- All document sessions and tree mutations share a project-wide FIFO because Overleaf's join/leave epoch is socket-wide. Documents are joined for one queued operation and then left.
- A write succeeds only after acknowledgement, matching
otUpdateApplied, leave/rejoin, and content-hash verification. - If a write times out, the intended hash means success, the unchanged original revision means timeout, and any third observable state means conflict. The write is never submitted again automatically.
- A comment is created as a REST thread and then attached through OT. Timed-out attachment recovery checks the new thread ID and exact range; orphan cleanup occurs only after the unchanged document proves attachment did not apply.
- A timed-out reply is accepted only when current author, exact normalized content, and the request-time window identify the refreshed message.
- ShareJS comment status uses the dedicated REST action. History-OT comment status is part of the document operation and snapshot.
- History monitoring reads one 25-group update window, strips email fields, and keeps no cursor or background state on the server.
Protocol fixtures under test/fixtures/protocol are sanitized: cookies, user data, project and document IDs, and document content are removed.
Thread messages, authors, and resolution state come from /project/:id/threads. When the deployment exposes /project/:id/ranges, that project-wide index identifies the documents containing filtered threads. Only those documents are joined to calculate line and column positions and quoted context.
If a usable project-wide range index is unavailable, a project-wide call returns threads with positionsUnavailable: true; it never scans every document silently. Supplying filePath joins only that document and resolves its ShareJS ranges or history-OT comment state. Threads without a document range are returned as unlocated.
The discussion record and source range are separate Overleaf objects. The thread endpoint provides messages, while live document state provides attachment and status metadata.
Development
npm run check
npm run lint
npm test
npm run build
npm pack --dry-runUnit and deterministic integration tests cover revision identity, Unicode positions, section parsing, tracked and untracked OT operations, history normalization, update limits, queue/cache behavior, Socket.IO frames, timeout recovery, comment attachment, file-tree events, and MCP registration.
Live tests are disabled by default and must target a disposable project:
RUN_OVERLEAF_LIVE_TESTS=1 \
OVERLEAF_LIVE_TEST_PROJECT_ID=0123456789abcdef01234567 \
npm test -- test/liveAdd RUN_OVERLEAF_LIVE_REVIEW_TESTS=1 for review reads, RUN_OVERLEAF_LIVE_TRACKED_WRITE_TESTS=1 for a disposable tracked file create/delete, or RUN_OVERLEAF_LIVE_HISTORY_TESTS=1 for read-only history normalization. Feature availability depends on the deployment and account. Keep request volume low and treat cleanup failures as test failures.
Git workflows, collaborator/account administration, billing, chat, background history watching, backward history pagination, version diffs and restoration, label mutation, and editing or deleting individual comment messages are outside the current release. Private API compatibility is version-specific and maintained on a best-effort basis.
License
Licensed under the MIT License.
