litewrite-mcp-server
# litewrite-mcp-server
An [MCP](https://modelcontextprotocol.io/) server that bridges local AI agents to the **HKUDS Litewrite** platform (a self-hosted, Overleaf-like collaborative LaTeX/Markdown writing platform). It lets agents discover projects, read, upload, and update files, and work against a **local mirror working copy** with git-style `pull` / `push` / `status` — conceptually mirroring how the [Overleaf MCP](https://github.com/mjyoo2/OverleafMCP) servers bridge MCP to Overleaf.
> Note: Litewrite stores files as objects (S3/MinIO) behind an internal HTTP API and has **no native Git integration**, so this server implements the "local directory + sync" model over that internal API instead of `git clone`/`git push`.
## Architecture
```
Local AI agent (Claude, etc.)
│ MCP (stdio)
▼
┌─────────────────────────┐ POST /api/internal/projects/* ┌──────────────────┐
│ litewrite-mcp-server │ ──► X-Internal-Secret header ─────────► │ Litewrite │
│ (TypeScript / MCP SDK) │ ◄── JSON {success,data} │ (self-hosted) │
└──────────┬──────────────┘ └──────────────────┘
│ local mirror working copy (~/.litewrite-mcp/<projectId>)
│ + .litewrite-manifest.json (content hashes)
▼
~/.litewrite-mcp/<projectId>/{main.tex, chapters/, figures/, ...}
```
## Requirements
- Node.js >= 18
- A running, reachable self-hosted **HKUDS Litewrite** server, with `INTERNAL_API_SECRET` set.
## Install & Build
```bash
cd litewrite-mcp
npm install
npm run build # emits dist/
```
## Configuration (environment variables)
| Variable | Required | Default | Description |
|---|---|---|---|
| `LITEWRITE_INTERNAL_SECRET` | yes | — | Must equal the Litewrite server's `INTERNAL_API_SECRET`. Sent as `X-Internal-Secret`. |
| `LITEWRITE_BASE_URL` | no | `http://localhost:3000` | Base URL of the Litewrite server. |
| `LITEWRITE_LOCAL_DIR` | no | `~/.litewrite-mcp` | Root dir for the per-project local mirror working copies. |
| `LITEWRITE_OWNER_ID` | no | `default` | Default owner used when a call omits `ownerId`. |
## Run
Once built, the server runs over `stdio`:
```bash
LITEWRITE_INTERNAL_SECRET=... node dist/index.js
```
### Register with a local agent
Add to your MCP client config (e.g. Claude Desktop `claude_desktop_config.json`):
```json
{
"mcpServers": {
"litewrite": {
"command": "node",
"args": ["/absolute/path/to/litewrite-mcp/dist/index.js"],
"env": {
"LITEWRITE_INTERNAL_SECRET": "your-internal-secret",
"LITEWRITE_BASE_URL": "http://localhost:3000"
}
}
}
}
```
## Tools
### Remote project & file operations (direct API)
| Tool | Endpoint | Description |
|---|---|---|
| `litewrite_list_projects` | `POST /api/internal/projects/list` | List projects for an owner; discover `projectId`. |
| `litewrite_list_files` | `POST /api/internal/files/list` | List files/dirs in a project (recursive option). |
| `litewrite_read_file` | `POST /api/internal/files/read` | Read a file's content from the server. |
| `litewrite_write_file` | `POST /api/internal/files/edit` | Replace an existing file's full content. |
| `litewrite_create_file` | `POST /api/internal/files/create` | Create a new text file or directory. |
| `litewrite_upload_file` | `POST /api/internal/files/upload` | Upload text or binary (base64) file, create/overwrite. |
| `litewrite_delete_file` | `POST /api/internal/files/delete` | Delete a file/directory (irreversible). |
| `litewrite_rename_file` | `POST /api/internal/files/rename` | Rename or move a file/folder. |
### Local working copy + sync (git-style)
| Tool | Network? | Description |
|---|---|---|
| `litewrite_pull` | yes | Mirror a project down into `~/.litewrite-mcp/<projectId>` and record a manifest. |
| `litewrite_push` | yes | Upload local changes up; delete remotely-removed-local files. |
| `litewrite_status` | yes | Diff local mirror vs server (`added/modified/removed/remote_new`). |
| `litewrite_local_list` | no | List files in the local mirror. |
| `litewrite_local_read` | no | Read a file from the local mirror. |
| `litewrite_local_write` | no | Write/overwrite a file in the local mirror. |
### Typical workflow
```text
1. litewrite_list_projects -> get projectId
2. litewrite_pull {projectId} -> mirror files locally
3. litewrite_local_list {projectId} -> see local files
4. litewrite_local_write ... -> edit locally (e.g. revise main.tex)
5. litewrite_status {projectId} -> review what changed
6. litewrite_push {projectId} -> upload changes to Litewrite
```
Or skip the local copy entirely and use `litewrite_read_file` / `litewrite_write_file` /
`litewrite_upload_file` directly.
## Security notes
- The MCP server holds the Litewrite `INTERNAL_API_SECRET`. It grants read/write to every
project the secret can reach, so keep it out of source control and restrict which agent can
start this server.
- All local file paths are validated against directory-traversal (`..` is rejected).
- The local working copies contain plaintext document content; guard the `LITEWRITE_LOCAL_DIR`.
## Limitations
- Binary files are uploaded via base64 (`upload`), but the `read` endpoint returns text, so
`pull` may skip binary assets it cannot round-trip. Upload such files directly.
- Endpoint request/response shapes follow the Litewrite internal API; field names may change
on upgrades. Adjust `src/api-client.ts` accordingly.
## License
MIT
TDQS
Scored across 14 tools
Most tools are clearly distinct, especially server vs local operations with explicit cross-references in descriptions. However, create_file, write_file, and upload_file have some overlap when creating or updating text files, though descriptions clarify intended use.
All tool names use the litewrite_ prefix followed by a snake_case verb_noun pattern, with local operations using litewrite_local_*. This is highly consistent and predictable.
14 tools provide a well-scoped set covering project listing, server file CRUD, and local mirror sync, with no excessive or trivial tools. Each tool earns its place.
Covers file lifecycle (create, read, update, delete, rename, upload) and local mirror workflow (pull, push, status, local list/read/write). Project listing suffices for discovery; no obvious gaps.