Skip to main content
Glama

litewrite-mcp-server

An MCP 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 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/, ...}

Related MCP server: Typleaf MCP Server

Requirements

  • Node.js >= 18

  • A running, reachable self-hosted HKUDS Litewrite server, with INTERNAL_API_SECRET set.

Install & Build

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:

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):

{
  "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

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

Available Tools

14 tools
litewrite_create_fileCreate a New FileB
Idempotent

Create a new text file (or directory) in a Litewrite project (POST /api/internal/files/create).

Args:

  • projectId (string, required): The project id.

  • name (string, required): Name of the new file or folder, e.g. "notes.md".

  • type (string, required): "file" or "directory".

  • parentPath (string, optional): Parent directory relative to project root, e.g. "chapters".

  • content (string, optional): Initial text content for a file.

Returns a confirmation.

Inputs: name (required), type (required), projectId (required), content, +1 more.

litewrite_delete_fileDelete a FileA
Destructive

Delete a file (or directory) from a Litewrite project (POST /api/internal/files/delete). This is irreversible.

Inputs: filePath (required), projectId (required).

litewrite_list_filesList Files in a ProjectA
Read-onlyIdempotent

List the files and directories in a Litewrite project (POST /api/internal/files/list).

Args:

  • projectId (string, required): The project id (from litewrite_list_projects).

  • directory (string, optional): Subdirectory to list from the project root, e.g. "chapters".

  • recursive (boolean, optional): When true, list all nested files; default true.

Returns an array of {path, type: 'file'|'directory', size?}.

Inputs: projectId (required), directory, recursive.

litewrite_list_projectsList Litewrite ProjectsA
Read-onlyIdempotent

List projects available in the Litewrite platform for a given owner (POST /api/internal/projects/list).

Use this to discover a projectId before pulling or reading files.

Args:

  • ownerId (string, optional): defaults to the LITEWRITE_OWNER_ID env var, or "default".

  • search (string, optional): name filter.

  • limit (number, optional, 1-200, default 50): max results.

Returns an array of projects with fields {id, name, description?, mainFile?, compiler?, updatedAt?, createdAt?}.

Inputs: limit, search, ownerId.

litewrite_local_listList Local Working CopyA
Read-onlyIdempotent

List the files in the local mirror of a project (no network call).

This is the local working copy at ~/.litewrite-mcp/ used by litewrite_pull/push/status.

Args:

  • projectId (string, required): The project id.

Returns relative file paths present on disk.

Inputs: projectId (required).

litewrite_local_readRead Local Working Copy FileA
Read-onlyIdempotent

Read a file from the local mirror of a project (no network call).

Unlike litewrite_read_file, this reads the on-disk local copy at ~/.litewrite-mcp/.

Args:

  • projectId (string, required): The project id.

  • filePath (string, required): Relative path in the local copy.

Returns the raw bytes (framed as text) of the local file.

Inputs: filePath (required), projectId (required).

litewrite_local_writeWrite Local Working Copy FileA
DestructiveIdempotent

Write or overwrite a file in the local mirror of a project (no network call).

Changes are NOT uploaded to Litewrite until you run litewrite_push.

Args:

  • projectId (string, required): The project id.

  • filePath (string, required): Relative path in the local copy.

  • content (string, required): The full text content to write.

Text files edited/created here will be uploaded by litewrite_push.

Inputs: content (required), filePath (required), projectId (required).

litewrite_pullPull Project to Local MirrorA
Idempotent

Mirror a Litewrite project down into a local directory (git-clone/pull style).

Downloads all text files from the server into the local working copy at ~/.litewrite-mcp/ (or LITEWRITE_LOCAL_DIR), removes local files that no longer exist on the server, and records a content manifest so a later push can detect changes.

Args:

  • projectId (string, required): The project id.

Returns what was downloaded and removed.

Inputs: projectId (required).

litewrite_pushPush Local Changes to LitewriteA
DestructiveIdempotent

Upload local working-copy changes back to Litewrite (git-push style).

Compares the local mirror (~/.litewrite-mcp/) against the last manifest: new/changed text files are uploaded, removed local files are deleted on the server, and the manifest is refreshed.

Use litewrite_status first to see what will change.

Args:

  • projectId (string, required): The project id.

Returns what was uploaded and deleted.

Inputs: projectId (required).

litewrite_read_fileRead a File from LitewriteA
Read-onlyIdempotent

Read the content of a file directly from the Litewrite server (POST /api/internal/files/read).

Prefers the server copy over the local mirror; use litewrite_local_read to read the local working copy instead.

Args:

  • projectId (string, required): The project id.

  • filePath (string, required): Path relative to the project root, e.g. "main.tex" or "chapters/intro.tex".

  • startLine / endLine (number, optional): Read only a line range.

Returns the file content as UTF-8 text.

Inputs: filePath (required), projectId (required), endLine, startLine.

litewrite_rename_fileRename / Move a FileA
DestructiveIdempotent

Rename or move a file/folder in a Litewrite project (POST /api/internal/files/rename).

Args:

  • projectId (string, required): The project id.

  • sourcePath (string, required): Current relative path.

  • newName (string, optional): New name (keeps the same parent).

  • targetPath (string, optional): Full target relative path to move it.

Provide at least one of newName or targetPath.

Inputs: projectId (required), sourcePath (required), newName, targetPath.

litewrite_statusShow Project Sync StatusA
Read-onlyIdempotent

Compare the local mirror of a project with Litewrite without changing anything (git-status style).

Reports which local files are added/modified/removed versus the last pull/push, and which files exist only on the remote. Use it before deciding whether to push local changes or pull remote ones.

Args:

  • projectId (string, required): The project id.

Returns a list of changes with their kind (added/modified/removed/remote_new).

Inputs: projectId (required).

litewrite_upload_fileUpload a File (Text or Binary)A
Destructive

Upload a file to Litewrite, creating or overwriting it (POST /api/internal/files/upload).

Use for binary assets (images, PDFs) where edit/create are unsuitable, or as an alternative to create.

Args (provide exactly one source):

  • projectId (string, required): The project id.

  • filePath (string, required): Relative target path, e.g. "figures/logo.png".

  • content (string, optional): The text content to upload.

  • contentBase64 (string, optional): The raw file data base64-encoded.

  • overwrite (boolean, optional): Allow overwriting an existing file; default false.

Returns a confirmation.

Inputs: filePath (required), projectId (required), content, overwrite, +1 more.

litewrite_write_fileWrite / Update a File on LitewriteA
DestructiveIdempotent

Replace the full content of an existing file on the Litewrite server (POST /api/internal/files/edit).

For creating a brand-new file use litewrite_create_file; for binary files use litewrite_upload_file.

Args:

  • projectId (string, required): The project id.

  • filePath (string, required): Path relative to the project root.

  • content (string, required): The new full text content.

Returns a confirmation.

Inputs: content (required), filePath (required), projectId (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    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.

    Related MCP Connectors

    Related MCP Servers