ShareLatexMCP
by vinconig
README.md
# ShareLaTeX MCP Server
An MCP (Model Context Protocol) server that gives Claude and other MCP clients access to **ShareLaTeX** projects over Git β read LaTeX files, analyze document structure, extract sections, and write changes back.
It targets **[ShareLaTeX @ TUM](https://sharelatex.tum.de)** (TUM's self-hosted Overleaf Server Pro instance) by default, and works with any other Server Pro deployment that has Git integration enabled β just set `SHARELATEX_HOST`.
> Forked from [mjyoo2/OverleafMCP](https://github.com/mjyoo2/OverleafMCP), which targets overleaf.com. This fork speaks the Server Pro URL shape (`https://<host>/git/<project_id>`) instead.
## Features
- π **Files**: list, read, write, append, and delete β with parent directories created on demand and binary files refused rather than mangled
- πΊοΈ **Outline**: one document-order tree across the whole `\input`/`\include` graph, not just per file
- βοΈ **Targeted edits**: replace a section, or insert a new one before/after an anchor, leaving the rest of the file untouched
- β
**Validation without compiling**: unbalanced braces, unclosed environments, unknown citation keys, undefined labels, missing includes β no LaTeX installation needed
- π **Bibliography merging**: import BibTeX by citation key, idempotently, so nothing already cited is ever lost
- π **History**: log, diff, and revert a file to any commit
- ποΈ **Multi-project**: several projects, even across instances
## Quick Start (recommended)
No clone, no `npm install`. Add this block to your Claude Desktop config and restart Claude Desktop.
**Config file location**
| OS | Path |
|---------|------|
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Linux | `~/.config/claude/claude_desktop_config.json` |
**macOS / Linux**
```json
{
"mcpServers": {
"sharelatex": {
"command": "npx",
"args": ["-y", "github:vinconig/ShareLatexMCP"],
"env": {
"SHARELATEX_PROJECT_ID": "YOUR_PROJECT_ID",
"SHARELATEX_GIT_TOKEN": "YOUR_GIT_TOKEN"
}
}
}
}
```
**Windows** β Claude Desktop on Windows needs `cmd /c` to find `npx`:
```json
{
"mcpServers": {
"sharelatex": {
"command": "cmd",
"args": ["/c", "npx", "-y", "github:vinconig/ShareLatexMCP"],
"env": {
"SHARELATEX_PROJECT_ID": "YOUR_PROJECT_ID",
"SHARELATEX_GIT_TOKEN": "YOUR_GIT_TOKEN"
}
}
}
}
```
Restart Claude Desktop. The `sharelatex` tools should appear in the π§ menu.
The host defaults to `sharelatex.tum.de`, so TUM users need nothing beyond the project ID and token.
> **Updating**: nothing to do β `npx` re-resolves the branch against GitHub on every launch and reinstalls if the commit changed. Push to `master` and the next Claude Desktop restart runs it.
>
> The flip side is that each launch needs network access to GitHub. If you want the server to start offline (or faster), use the local clone from [Local Development](#local-development) instead and `git pull` when you want updates.
## Getting your credentials
1. **Project ID** β open the project in ShareLaTeX; the ID is the last segment of the URL: `https://sharelatex.tum.de/project/[PROJECT_ID]`
2. **Git Token** β ShareLaTeX β Account Settings β Git Integration β "Create Token". The token is shown **once**; copy it immediately.
Sanity-check the pair from a terminal before wiring up Claude Desktop β this should prompt for a password (paste the token) and clone:
```bash
git clone https://git@sharelatex.tum.de/git/YOUR_PROJECT_ID
```
## Using another Server Pro instance
Set `SHARELATEX_HOST` alongside the other env vars:
```json
"env": {
"SHARELATEX_PROJECT_ID": "...",
"SHARELATEX_GIT_TOKEN": "...",
"SHARELATEX_HOST": "sharelatex.example.edu"
}
```
A full URL is accepted too (`https://sharelatex.example.edu/`) β it is reduced to the bare hostname. The Git URL is always built as `https://<host>/git/<project_id>`.
In a multi-project `projects.json`, set `host` per project instead; it overrides `SHARELATEX_HOST` for that entry.
## Multi-Project Setup
The env-var Quick Start only handles a single project. For multiple projects, drop a `projects.json` file into the user config directory and skip the `env` block in your Claude Desktop config.
**File location**
| OS | Path |
|-----------------|------|
| Windows | `%APPDATA%\sharelatex-mcp\projects.json` |
| macOS / Linux | `~/.config/sharelatex-mcp/projects.json` (or `$XDG_CONFIG_HOME/sharelatex-mcp/projects.json` if set) |
**File contents**
```json
{
"projects": {
"default": {
"name": "Main Paper",
"projectId": "...",
"gitToken": "..."
},
"thesis": {
"name": "My Thesis",
"projectId": "...",
"gitToken": "..."
},
"external": {
"name": "Paper on another instance",
"projectId": "...",
"gitToken": "...",
"host": "sharelatex.example.edu"
}
}
}
```
**Claude Desktop config** β same as Quick Start but no `env` block:
```json
{
"mcpServers": {
"sharelatex": {
"command": "npx",
"args": ["-y", "github:vinconig/ShareLatexMCP"]
}
}
}
```
(Add `cmd /c` on Windows, as in the Quick Start.)
Reference a specific project in tool calls with `projectName`:
```
Use read_file with filePath: "main.tex", projectName: "thesis"
```
If `projectName` is omitted, the `default` entry is used. To put `projects.json` somewhere other than the standard location, point `SHARELATEX_PROJECTS_CONFIG=/absolute/path/projects.json` at it from the `env` block.
## Configuration Reference
The server picks the **first** matching configuration source:
1. **Env vars (single project)** β `SHARELATEX_PROJECT_ID` + `SHARELATEX_GIT_TOKEN`. Optional: `SHARELATEX_PROJECT_NAME` for the display name.
2. **Token from a file** β set `SHARELATEX_PROJECT_ID` together with `SHARELATEX_GIT_TOKEN_FILE=/path/to/token.txt` (instead of `SHARELATEX_GIT_TOKEN`). Useful when you don't want the token in the Claude Desktop JSON. The file is read once at startup and any trailing whitespace/newline is trimmed.
3. **Multi-project file** β `SHARELATEX_PROJECTS_CONFIG=/absolute/path/projects.json`.
4. **User config dir** β `projects.json` in:
- Windows: `%APPDATA%\sharelatex-mcp\projects.json`
- macOS / Linux: `$XDG_CONFIG_HOME/sharelatex-mcp/projects.json` (defaults to `~/.config/sharelatex-mcp/projects.json`)
5. **Working directory** β `./projects.json`
6. **Package directory** β `projects.json` next to the server script (legacy, for clone-based installs).
`SHARELATEX_HOST` is independent of the above β it applies to every project that doesn't set its own `host`, and defaults to `sharelatex.tum.de`.
When env vars are set and a file is also present, env vars win and a notice is logged to stderr so the shadowing is visible.
### Environment variables
| Variable | Required | Purpose |
|---|---|---|
| `SHARELATEX_PROJECT_ID` | yes (single-project mode) | Project ID from the ShareLaTeX URL |
| `SHARELATEX_GIT_TOKEN` | yes, unless `..._FILE` is used | Git token from Account Settings |
| `SHARELATEX_GIT_TOKEN_FILE` | β | Path to a file containing the token |
| `SHARELATEX_HOST` | β | Instance hostname (default `sharelatex.tum.de`) |
| `SHARELATEX_PROJECT_NAME` | β | Display name for the single project |
| `SHARELATEX_PROJECTS_CONFIG` | β | Absolute path to a `projects.json` |
| `SHARELATEX_CONFIRM` | β | `all` (default), `destructive`, or `off` β see [Confirmation before writing](#confirmation-before-writing) |
## Local Development
### Option 1 β Run the cloned script directly
```bash
git clone https://github.com/vinconig/ShareLatexMCP.git
cd ShareLatexMCP
npm install
```
Then point Claude Desktop at the script and pass credentials via env vars (the same loader path the `npx` install uses):
```json
{
"mcpServers": {
"sharelatex": {
"command": "node",
"args": ["/absolute/path/to/ShareLatexMCP/sharelatex-mcp-server.js"],
"env": {
"SHARELATEX_PROJECT_ID": "...",
"SHARELATEX_GIT_TOKEN": "..."
}
}
}
}
```
On Windows, `args` should use `"C:\\Users\\you\\ShareLatexMCP\\sharelatex-mcp-server.js"`.
If you'd rather use a multi-project file:
```bash
cp projects.example.json projects.json # then edit it
```
`projects.json` next to the script is the lowest-priority fallback, so this still works without env vars.
### Option 2 β Smoke-test the MCP protocol from the shell
No Claude Desktop required:
```bash
SHARELATEX_PROJECT_ID=... SHARELATEX_GIT_TOKEN=... node sharelatex-mcp-server.js
```
You should see `ShareLaTeX MCP server running on stdio` on stderr. The process stays open waiting for JSON-RPC on stdin; Ctrl+C to exit.
To drive a real tool call, pipe in an `initialize` handshake followed by a `tools/call`:
```bash
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_files","arguments":{}}}' \
| SHARELATEX_PROJECT_ID=... SHARELATEX_GIT_TOKEN=... node sharelatex-mcp-server.js
```
The working clone lives in your temp directory as `sharelatex-<project_id>`.
## Available Tools
All tools take an optional `projectName` (defaults to `"default"`). Every tool that writes takes a `commitMessage`.
### Reading and navigating
| Tool | Purpose |
|---|---|
| `list_projects` | List configured projects. |
| `list_files` | List files. Defaults to `.tex`; pass `extension: "*"` for everything, `includeBuild: true` to include `build/`. |
| `read_file` | Read a text file. Binary files (PDF, images) are rejected rather than returned as mojibake. Optional `maxBytes`. |
| `get_sections` | Sectioning commands in one file, with line numbers. |
| `get_outline` | **Document-order outline of the whole thesis**, following `\input`/`\include` recursively from `main.tex`. Use this instead of `get_sections` on `main.tex`, which contains only includes. |
| `get_section_content` | The content of one section by title. |
| `search_project` | Regex or literal search across files β `file:line text`. |
| `status_summary` | File counts by extension, chapter list, bibliography size, validation totals. |
| `validate_project` | See below. |
### Writing
| Tool | Purpose |
|---|---|
| `write_file` | Write a complete file. Creates parent directories. |
| `write_section` | Replace one existing section, leaving the rest of the file untouched. `occurrence` disambiguates repeated titles. |
| `insert_section` | Insert a **new** section `before`/`after` an anchor section, or at `end_of_file`. `write_section` cannot add sections that don't exist yet. |
| `append_to_file` | Append to a file, creating it if absent. |
| `delete_file` | Remove a file and push the deletion. |
### Bibliography
| Tool | Purpose |
|---|---|
| `list_bib_keys` | Citation keys already in the bibliography, with type and title. |
| `add_bib_entries` | Merge BibTeX **by citation key**. Existing keys are kept unless `overwrite: true`, so nothing already cited can be lost. Re-running with the same input is a no-op. |
### History
| Tool | Purpose |
|---|---|
| `file_history` | Recent commits, optionally for one file. |
| `show_diff` | Diff the working tree against a commit (default `HEAD~1`). |
| `revert_file` | Restore a file from a commit and push that restoration. |
## Validation
`validate_project` checks the whole `\input` graph **without compiling** β no LaTeX installation required, so it works identically in Claude Desktop:
| Check | Severity |
|---|---|
| Unbalanced braces | error |
| `\begin{X}` / `\end{X}` mismatch | error |
| `\input`/`\include` target missing | error |
| Citation key not in `bibliography.bib` | warning |
| `\ref`/`\autoref` to an undefined label | warning |
| Duplicate `\label` | warning |
| Undefined glossary or acronym key | warning |
Comments are ignored, and the bodies of `verbatim`/`lstlisting`/`minted` blocks are excluded so code samples with unbalanced braces don't produce false alarms.
Every write goes through the same structural gate: a write whose result would have unbalanced braces or an unclosed environment is **refused before pushing**, with the offending line numbers. Warnings never block β you routinely cite a key moments before importing it β they come back in the tool response instead.
## Confirmation before writing
By default **every tool that writes stops and shows you what would change before anything is pushed.** Claude Desktop does prompt before each tool call, but that prompt shows what Claude is *sending* β never the text about to be *overwritten* β and it stops appearing once you click "Allow always for this chat".
The first call writes nothing and answers with a preview:
```
write_section would change chapters/01_introduction.tex β 123 lines now, 123 after (+0).
@@ -2,7 +2,7 @@
\chapter{Introduction}\label{chapter:introduction}
-Use with pdfLaTeX and Biber.
+This chapter motivates the work and states the research question.
Nothing has been written. To apply it, re-call write_section with the same
arguments plus confirm: "4b77477b".
```
Say "go ahead" and Claude re-calls with the token. If the client supports MCP **elicitation**, the server uses a real prompt instead and resolves it inside the single call β it detects this at startup and logs which path it took.
The token is derived from the file's current content plus the proposed content, not stored. That makes staleness self-detecting: **if the file changed since the preview β you edited it in the web editor, say β the token no longer matches**, and you get a fresh preview rather than an approval silently landing on different text.
A write whose result is byte-identical to what's already there skips the whole exchange.
| `SHARELATEX_CONFIRM` | Behaviour |
|---|---|
| `all` | *(default)* every writing tool confirms |
| `destructive` | only `delete_file` and `revert_file` |
| `off` | writes push immediately; relies on the client's own prompt |
```json
"env": {
"SHARELATEX_PROJECT_ID": "...",
"SHARELATEX_GIT_TOKEN": "...",
"SHARELATEX_CONFIRM": "destructive"
}
```
An unrecognised value falls back to `all` with a warning on stderr β a typo must never quietly disable the safety net.
## Thesis workflows
### Citations, without exporting `.bib` by hand
If you also have a Zotero MCP configured in the same client, the manual "export from Zotero, upload to the web editor" loop disappears:
1. Find sources with the Zotero MCP (`zotero_semantic_search`, `zotero_advanced_search`).
2. `zotero_export_bibliography(item_keys=[...], export_format='bibtex')` β raw BibTeX.
3. `add_bib_entries` merges it by key and pushes. Nothing already present is touched.
4. Cite it. Check `list_bib_keys` first if you're unsure what's already there.
5. `validate_project` confirms every `\cite` key resolves.
Two things to get right up front: `zotero_export_bibliography` renders through Zotero's **web API** even in local mode, so it needs `ZOTERO_API_KEY` and `ZOTERO_LIBRARY_ID`; and citation keys must be **stable** (BetterBibTeX with pinned keys), or citations silently rot when keys drift.
### Figures and tables
This server writes UTF-8 β it cannot push a PNG. That is a better fit for LaTeX than it sounds: write plots as **pgfplots code plus a CSV**, both plain text, both pushable:
```latex
\begin{figure}[htpb]
\centering
\begin{tikzpicture}
\begin{axis}[xlabel={Epoch}, ylabel={Accuracy}]
\addplot table[x=epoch, y=acc, col sep=comma] {figures/results.csv};
\end{axis}
\end{tikzpicture}
\caption{Validation accuracy.}\label{fig:accuracy}
\end{figure}
```
Vector output, reproducible, diffable, and it regenerates when the numbers change β unlike an exported bitmap. Tables work the same way via `pgfplotstable`, or as `booktabs` markup. Genuinely binary assets (screenshots, photographs) still have to go through the web editor.
### Conventions that survive both Claude Desktop and Claude Code
Put a `CONVENTIONS.md` **in the LaTeX project itself** and start writing sessions with "read CONVENTIONS.md first". It travels with the project and is readable through `read_file` anywhere β unlike client-specific configuration. Worth encoding: which citation and cross-reference commands your template uses, label prefixes, table style, and **one sentence per line**, which is what makes `show_diff` and section rewrites reviewable.
### Safety
Avoid leaving the ShareLaTeX web editor open on a project while writing through the MCP β the editor auto-commits, which shows up here as a rejected push. After a substantial rewrite, `show_diff` then `revert_file` if it went wrong.
## Usage Examples
```
# List all projects
Use the list_projects tool
# Get project overview
Use status_summary tool
# Read main.tex file
Use read_file with filePath: "main.tex"
# Get Introduction section
Use get_section_content with filePath: "main.tex" and sectionTitle: "Introduction"
# List all sections in a file
Use get_sections with filePath: "main.tex"
# Write the full content of a file to the project
Use write_file with filePath: "main.tex", content: "...", commitMessage: "..."
# Write the content of a specific section to the project
Use write_section with filePath: "main.tex", sectionTitle: "Introduction", newContent: "\\section{Introduction}\n...", commitMessage: "..."
```
## Security Notes
- The Git token grants full read/write access to your project β treat it like a password.
- The token is passed to `git` through a credential helper reading it from the process environment. It never appears on a command line and is never written into the temp clone's `.git/config`.
- Prefer `SHARELATEX_GIT_TOKEN_FILE` over inlining the token in the Claude Desktop JSON if your config file is backed up or synced.
- `projects.json` is `.gitignore`d in this repo. Never commit real project IDs or Git tokens.
- File paths supplied through MCP tool calls are restricted to the cloned project directory; `..` traversal and absolute paths are rejected.
## License
MIT β see [LICENSE](LICENSE). Original work Β© mjyoo2.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues