Skip to main content
Glama
README.md
# 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

A4/5.0

Scored across 14 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues