Skip to main content
Glama
README.md
# overleaf-bridge

Agent access to a self-hosted Overleaf **Community Edition**: an MCP server and
a git remote, so any agent (Claude Code, OpenCode, Cursor, Codex, your own) can
read, edit, upload to and compile Overleaf projects. CE has no git-bridge and
no API; this fills that gap without patching Overleaf. See [DESIGN.md](DESIGN.md).

## How it works, in one paragraph

The bridge is an ordinary Overleaf user (`agent@…`). It sees only the projects
you **share with it**. Document edits go through Overleaf's own realtime
pipeline, so collaborators see them instantly and history shows the agent as
the author. Externally, one bearer token protects both the MCP endpoint and the
git remote. It runs as its own docker-compose project next to the
[Overleaf Toolkit](https://github.com/overleaf/toolkit) and never modifies it.

## Requirements

- Overleaf CE deployed with the Overleaf Toolkit (containers `sharelatex`,
  `mongo`, network `overleaf_default`). Tested with CE 6.2.
- Docker Compose v2.
- A public hostname (or two) that reaches this host — e.g. via a Cloudflare
  Tunnel, nginx, or Caddy — forwarding to `127.0.0.1:3900`.

## Deploy

1. **Create the agent user** in Overleaf (from the toolkit directory):
   ```bash
   bin/run-script /overleaf/services/web/modules/server-ce-scripts/scripts/create-user.js \
     --email=agent@overleaf.example.com
   ```
   Open the activation link it prints and set a password.

2. **Configure and start the bridge:**
   ```bash
   cp .env.example .env      # fill in OVERLEAF_SITE_HOST, agent credentials, BRIDGE_TOKEN, BRIDGE_ALLOWED_HOSTS
   bin/up                    # builds and starts `bridge` + `edge`
   curl -s -H "Authorization: Bearer $BRIDGE_TOKEN" http://127.0.0.1:3900/health   # -> ok
   ```

3. **Expose it.** Point your public hostname(s) at `http://127.0.0.1:3900`.
   With a Cloudflare Tunnel, add to the tunnel's ingress:
   ```yaml
     - hostname: mcp.example.com
       service: http://127.0.0.1:3900
     - hostname: git.example.com
       service: http://127.0.0.1:3900
   ```
   then `cloudflared tunnel route dns <tunnel> mcp.example.com` (same for
   `git.`) and restart cloudflared. One hostname for both is fine too — the
   bridge routes by path (`/mcp`, `/git/...`). Every hostname must be listed in
   `BRIDGE_ALLOWED_HOSTS`.

## Give an agent access to a project

In Overleaf: open the project → **Share** → add the agent's email with
*Can edit*. Remove it from Share to revoke. That is the whole permission model.

Sharing creates an *invite*; the bridge accepts it itself (on startup, on
`list_projects`, and whenever a request hits a 403), so the project is usable
right after you click Share — no email delivery needed.

## Connect an agent

**Claude Code**

```bash
claude mcp add --transport http overleaf https://mcp.example.com/mcp \
  --header "Authorization: Bearer <BRIDGE_TOKEN>"
```

**OpenCode** (`opencode.json`):

```json
{
  "mcp": {
    "overleaf": {
      "type": "remote",
      "url": "https://mcp.example.com/mcp",
      "enabled": true,
      "headers": { "Authorization": "Bearer <BRIDGE_TOKEN>" }
    }
  }
}
```

**Cursor / any MCP client** (`mcp.json`):

```json
{ "mcpServers": { "overleaf": {
    "url": "https://mcp.example.com/mcp",
    "headers": { "Authorization": "Bearer <BRIDGE_TOKEN>" } } } }
```

Tools: `list_projects`, `list_files`, `read_doc`, `edit_doc` (exact-fragment
patch; fails safely if the document changed), `write_doc` (create/rewrite),
`upload_file`, `download_file`, `delete_path`, `compile` (optionally
`root_doc="supplementary.tex"`), `get_compile_log`, `get_pdf`,
`get_messages` / `post_message` (project chat), `get_history` (who changed
what, with diffs).

**git**

```bash
git clone https://x:<BRIDGE_TOKEN>@git.example.com/git/<project_id>.git
# edit, commit, then:
git push
```

The username is ignored; the token is the password. `<project_id>` is the id
in the project's URL (`/project/<id>`) or from `list_projects`.

- `clone`/`pull` always reflect Overleaf as of that moment (a snapshot commit
  is added when something changed).
- `push` applies your commits to Overleaf. If Overleaf changed since your last
  pull, the push is **rejected** — pull, merge, push again. Only `main`,
  fast-forward only.
- `.tex/.bib/.cls/.sty/.bst/.txt/.md/.csv` are written as documents; anything
  else is uploaded as a file.

## Operating

| | |
|---|---|
| Logs | `bin/logs` |
| After an Overleaf upgrade | `bin/restart` (the bridge borrows the `sharelatex` network namespace) |
| Live end-to-end test | `bin/smoke <project_id>` on a throwaway project owned by/shared with the agent |
| Unit tests | `uv run pytest` |
| Rotate the token | edit `.env`, `bin/up`, update agents |
| New public hostname | add it to `BRIDGE_ALLOWED_HOSTS` (the MCP transport answers 421 to unknown `Host` headers) |

## What Community Edition does not have

Comments and track changes are a Server Pro feature; CE has no review panel
and no API for it, so the bridge cannot read them. Use the project chat
(`get_messages`/`post_message`) for remarks between people and agents, and
`get_history` to see what changed.

## Limits

One shared token for all agents; Overleaf's internal routes are not a public
API and may shift across major upgrades — `bin/smoke` catches that.
Login is rate-limited by Overleaf (10 per 2 minutes per user); the bridge
keeps one session, but many rapid git pushes each log in once.

## License

MIT.

Maintenance

ActivityMaintained
ResponsivenessNo issues