Skip to main content
Glama

Typst Web MCP

Model Context Protocol (MCP) server for https://typst.app — cloud projects, Yjs CRDT editing, and Typst compiler diagnostics

npm version Downloads License: MIT Node.js Package


Installation

Add typst-mcp to your MCP client configuration (.pi/agent/mcp-adapter.json, claude_desktop_config.json, or .cursor/mcp.json).

Prerequisites

  • Node.js >= 18

  • Typst CLI (optional: typst on PATH for local CLI compilation speed; if not installed, typst_get_diagnostics automatically uses Typst Web cloud compiler diagnostics)

Option 1: Normal (Standard)

Runs the published typst-mcp package (npx -y typst-mcp):

{
  "mcpServers": {
    "typst-mcp": {
      "command": "npx",
      "args": ["-y", "typst-mcp"],
      "env": {
        "TYPST_EMAIL": "your-email@example.com",
        "TYPST_PASSWORD": "your-password"
      }
    }
  }
}

Option 2: Always Latest

Bypasses local npx cache to automatically pull and run the newest release on launch (npx -y typst-mcp@latest):

{
  "mcpServers": {
    "typst-mcp": {
      "command": "npx",
      "args": ["-y", "typst-mcp@latest"],
      "env": {
        "TYPST_EMAIL": "your-email@example.com",
        "TYPST_PASSWORD": "your-password"
      }
    }
  }
}

Related MCP server: Typleaf MCP Server

Overview

typst-web-mcp connects AI coding and writing agents directly to collaborative typst.app cloud projects. Instead of relying on brittle browser DOM scraping, it implements the native typst.app client protocol:

  • Native Yjs CRDT Text Sync: Decodes and mutates multiplayer Y.Doc (doc.getText("text")) state vectors so surgical edits preserve collaborator cursors and version history.

  • Binary /editing/v3 WebSocket Wire Protocol: Encodes and decodes lib0 variable-length binary frames (Subscribe, TextUpdate, Pong, Refresh, Presence, Cursor, Leave) with REST /v1/files/:projectId/:fileId/yjs persistence.

  • GraphQL & REST Project Management: Full project CRUD, file tree inspection, rename/move, delete, and binary figure/asset uploads (PNG, JPG, SVG, PDF, fonts).

  • Direct Authentication + Fallback: Authenticates via GET /v1/to-signin + POST /v1/auth/signin (__Http-typst-session), with persistent session caching and automatic cookie/Playwright fallback on challenge.

  • Compiler Diagnostics, Preview Screenshots & PDF Export: Synchronizes cloud Yjs text and binary assets into an isolated workspace and runs the Typst compiler to return structured line/column diagnostics, high-DPI PNG preview screenshots (typst_capture_screenshot), and compiled PDFs (typst_export_pdf).


MCP Tools (18 Tools)

Category

Tool Name

Description

Auth

typst_auth_login

Authenticate with https://typst.app via email/password (POST /v1/auth/signin) or __Http-typst-session cookie, with browser fallback.

Auth

typst_auth_status

Check active authentication state, login method, and stored session cookies.

Projects

typst_list_projects

List all owned and shared/external projects in the user's typst.app dashboard (DashboardContent).

Projects

typst_get_project

Retrieve full project metadata, access permissions, pinned compiler version, and file tree (ProjectFiles).

Projects

typst_create_project

Create a new typst.app cloud project with initial .typ/.bib files and pinned compiler version.

Projects

typst_delete_project

Permanently delete a typst.app project by ID (DeleteProjectMutation).

Files & CRDT

typst_list_files

List all multiplayer Yjs text files and binary asset blobs in a project.

Files & CRDT

typst_read_file

Read bounded source pages (200 lines/16 KiB by default), with compact metadata, whole-file content hashes, separate continuation fields, and native image blocks.

Files & CRDT

typst_write_file

Create or overwrite a .typ/.bib/.toml file, protected by per-file mutation queue serialization, syncing Yjs state diffs over /editing/v3 WebSocket and REST.

Files & CRDT

typst_edit_file

Apply validated, unique edits to one snapshot with optional stale-content protection, exact matching by default, compact receipts, opt-in fuzzy fallback, and bounded diff previews.

Search & Replace

typst_grep_project

Search for text or regular expressions across project files, returning file paths, line numbers, and optional surrounding context lines.

Search & Replace

typst_find_and_replace

Replace text or regex in one file or project-wide. Batch ordered replacement rules in one call with one save per changed file, compact summaries, optional diffs, and dry-run previews.

Assets & Tree

typst_upload_asset

Upload or replace binary assets (PNG, JPG, SVG, PDF, fonts) from a local path or base64 payload.

Assets & Tree

typst_rename_file

Rename or move a file inside a typst.app project (UpdatesFileMutation).

Assets & Tree

typst_delete_file

Delete a file or binary asset from a project (DeleteFilesMutation).

Compiler

typst_get_diagnostics

Retrieve compiler diagnostics (errors, warnings, line/column numbers, and hints). Supports both local Typst CLI (mode="cli") and Typst Web cloud compiler (mode="web"), with automatic fallback (mode="auto").

Compiler

typst_export_pdf

Sync all cloud text & binary assets, compile the project to PDF, and save to outputPath.

Preview

typst_capture_screenshot

Capture high-DPI PNG preview screenshots (mode="pages" renders compiled PNG pages; mode="browser" screenshots the live typst.app web UI).


Read and edit efficiently

  1. Use typst_grep_project to locate relevant text, then read just that range with typst_read_file (offset is 1-based, limit defaults to 200 lines, maxBytes defaults to 16 KiB and can be raised to 1 MiB).

  2. Keep the returned contentHash. It is SHA-256 of the entire raw text file, including BOM and line endings, even when reading a range or displaying line numbers.

  3. Send all disjoint edits in one typst_edit_file call, with expectedHash set to that hash. Prefer a short unique oldText anchor over repeating a whole file.

{
  "projectId": "your-project-id",
  "filePath": "main.typ",
  "expectedHash": "<contentHash from the read response>",
  "edits": [
    { "oldText": "September 2025", "newText": "September 2026" }
  ]
}

Text read responses include source only in content, with totalLines, startLine, endLine, truncated, and nextOffset when more source remains. They never repeat source in truncation metadata or append instructions to it. Complete lines and original line endings are retained, so unnumbered pages can be concatenated without losing bytes. A trailing newline does not create a phantom extra line. An empty file has totalLines: 0, startLine: 1, endLine: 0.

Read metadata defaults to {id, name}. Use output: "full" for full file metadata; this does not increase the source range. lineNumbers: true adds display prefixes: remove those prefixes when constructing oldText. Byte budgets include those prefixes. If one line cannot fit, the tool returns an actionable error rather than an empty page that cannot advance.

Edits match against the same original snapshot, not the result of previous edits. All entries must be valid, and each anchor must be unique, including overlapping occurrences. Invalid batches, overlapping ranges, and stale hashes fail before saving. matchMode: "exact" is the default and accepts LF/CRLF differences. Use matchMode: "fuzzy" to opt into Unicode quote/dash/space and NFKC fallback when no exact match exists. Fallback matching preserves characters outside the matched span. Edits retain the BOM and untouched line endings, including mixed LF/CRLF files.

Successful edits return a compact receipt with file ID/name, appliedCount, the resulting contentHash, and firstChangedLine. This avoids returning the same changes as both a diff and a patch. Optional controls:

  • output: "diff" adds a display diff; output: "full" also adds a patch and full metadata.

  • Each diff/patch field is limited to 100 lines and maxDiffBytes bytes (default 8192, maximum 1 MiB). diffTruncated / patchTruncated explicitly flag omissions; read the affected range for complete source.

  • dryRun: true validates and previews without saving and defaults to diff output. Its appliedCount describes proposed edits; its contentHash still identifies the unchanged cloud text.

expectedHash is checked on fresh text inside the shared file mutation queue, which serializes local edits, replacements, and whole-file writes to existing files. It detects changes made since the read; it is not a cloud compare-and-swap transaction and cannot prevent a collaborator from editing during the subsequent save. Yjs still merges concurrent cloud updates.

Changed defaults: reads previously allowed 2,000 lines/50 KiB and embedded continuation hints in content. Read callers should follow nextOffset now. MCP edits previously returned full diffs/patches and used fuzzy fallback automatically; request output: "full" or matchMode: "fuzzy" explicitly when needed. The low-level editYjsText helper retains its legacy fuzzy default; the client/MCP edit path defaults to exact matching.

Batch replacements for agents

Use one typst_find_and_replace call for related replacements. For example, expand abbreviated month names throughout all .typ files:

{
  "projectId": "your-project-id",
  "glob": "*.typ",
  "replacements": [
    { "pattern": "\\bSep\\b", "replacement": "September", "regex": true },
    { "pattern": "\\bOct\\b", "replacement": "October", "regex": true }
  ]
}

Each file is downloaded once, all rules run in order on the previous rule's result, and the file is saved once if its final text changed. All rules are validated before any files are written. File mutations remain serialized with other edits; a project-wide operation is not atomic across files if a network or save error occurs.

Batch calls default to output: "summary":

{
  "filesModified": [
    {
      "file": "main.typ",
      "replacementsCount": 3,
      "replacementCounts": [2, 1],
      "firstChangedLine": 4
    }
  ],
  "totalReplacements": 3,
  "dryRun": false
}

replacementCounts follows the input rule order and counts matches applied by each rule in that changed file. Unchanged files, including batches whose rules cancel each other out, are omitted and do not contribute to totals.

  • Set dryRun: true to preview without saving. Add output: "diff" to include a single combined display diff per file.

  • Set output: "full" to include both the display diff and unified patch.

  • Set regex, ignoreCase, and limit on each batch rule. limit is a non-negative integer per rule per file; 0 disables that rule.

  • Use either replacements or the existing pattern/replacement fields. Existing single-replacement calls still default to output: "full"; they can request "summary" too.

  • Use filePath to target one file by path or ID. A missing explicit file returns an error.

Development & Verification

From Source (Development)

Requires Bun >= 1.2:

git clone https://github.com/caphefalumi/typst-web-mcp.git
cd typst-web-mcp
bun install
bun run dev

Build & Test

# Compile publishable output to dist/
bun run build

# Typecheck with strict TypeScript
bun run typecheck

# Full suite (includes test/smoke.test.ts: dist bin + npx -y typst-mcp)
bun test

# Smoke only (same as pi npx MCP config)
bun run test:smoke

Push/PR to main runs .github/workflows/ci.yml (bun ci, build, typecheck, bun test).

Publishing to npm

Same flow as Canvas-CLI:

  1. Bump version in package.json (must not match a version already on npm).

  2. Commit, push, and create a GitHub Release for that tag — or run Actions → Publish → Run workflow (workflow_dispatch).

.github/workflows/npm-publish.yml runs the same checks as CI (bun test, including smoke) in a test job; the publish job runs only if that passes, on the npm-publish environment: bun ci, bun run build, then npm publish --access public via npm trusted publishing (OIDC). The publish step clears NODE_AUTH_TOKEN so the CLI uses GitHub OIDC instead of a stale token from setup-node.

Trusted publisher (maintainers): package typst-mcp → Settings → Trusted publishing → GitHub Actions — user/org caphefalumi, repo typst-web-mcp, workflow file npm-publish.yml, environment npm-publish, allow npm publish.


License

Released under the MIT License. Copyright (c) 2026 Dang Duy Toan (caphefalumi).

Available Tools

18 tools
typst_auth_loginA

Authenticate with https://typst.app using direct email/password API login (POST /v1/auth/signin) or a session cookie (__Http-typst-session), with automatic cookie/browser fallback on challenge.

Inputs: email, password, sessionCookie, useBrowserFallback.

typst_auth_statusA

Check current https://typst.app authentication status, active session cookies, and login method.

Inputs: no named parameters.

typst_capture_screenshotA

Capture high-resolution PNG preview screenshots to verify the visual status of a https://typst.app project (mode='pages' renders compiled PNG pages via Typst; mode='browser' captures the live typst.app web editor & preview pane via Playwright).

Inputs: projectId (required), ppi, mode, pages, +3 more.

typst_create_projectC

Create a new project on https://typst.app with optional initial .typ/.bib files and pinned Typst compiler version.

Inputs: name (required), files, owner, folder, +1 more.

typst_delete_fileC

Delete a file or asset from a https://typst.app project via DeleteFilesMutation.

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

typst_delete_projectB

Permanently delete a project on https://typst.app by ID.

Inputs: projectId (required).

typst_edit_fileA

Apply all targeted edits against one original file snapshot, with one save. Prefer short unique oldText anchors and expectedHash from typst_read_file to reject stale edits. Exact matching by default (LF/CRLF resilient); matchMode='fuzzy' opts into Unicode/whitespace fallback. Malformed, ambiguous, or overlapping edits fail without saving. Summary output by default; dryRun previews a bounded diff. Unchanged characters and BOM are preserved.

Inputs: edits, dryRun, output, newText, +7 more.

typst_export_pdfB

Synchronize all text and binary files from a https://typst.app project, compile the document to PDF, and save it to outputPath.

Inputs: projectId (required), mainFile, outputPath.

typst_find_and_replaceA

Find and replace text or regex in one file or project-wide. Use replacements to batch mappings (e.g. Sep → September, Oct → October) in one call with one save per file. Rules run sequentially; later rules see earlier results. Batch output defaults to compact summary; request output='diff' or 'full' for previews. Supports dryRun and per-file mutation serialization. Project-wide changes are not atomic across files.

Inputs: projectId (required), glob, limit, regex, +8 more.

typst_get_diagnosticsA

Retrieve compiler diagnostics (errors, warnings, line/column numbers, and hints) for a https://typst.app project. Supports both local Typst CLI compilation (fastest) and Typst Web cloud diagnostics (zero-binary fallback using typst.app cloud compiler).

Inputs: projectId (required), mode, mainFile.

typst_get_projectA

Get detailed metadata, access permissions, pinned compiler version, and full file tree for a https://typst.app project.

Inputs: projectId (required).

typst_grep_projectA

Search for text or regular expressions across files in a https://typst.app project. Returns matching lines with file paths, line numbers, and optional surrounding context lines.

Inputs: pattern (required), projectId (required), glob, path, +4 more.

typst_list_filesB

List all files (multiplayer Yjs text files and binary asset blobs) inside a https://typst.app project.

Inputs: projectId (required).

typst_list_projectsA

List all owned and shared/external projects in the authenticated user's https://typst.app dashboard.

Inputs: no named parameters.

typst_read_fileA

Read project text in bounded pages (default 200 lines/16 KiB) or images as native image blocks. content contains source only; use nextOffset for continuation. contentHash covers the entire raw text file: pass it as expectedHash to typst_edit_file. Compact file metadata by default; output='full' adds metadata, not extra source lines. Use grep to locate relevant lines before reading large files.

Inputs: filePath (required), projectId (required), limit, offset, +3 more.

typst_rename_fileB

Rename or move a file inside a https://typst.app project via UpdatesFileMutation.

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

typst_upload_assetA

Upload or replace a binary asset (PNG, JPG, SVG, PDF, font, etc.) in a https://typst.app project from a local file path or base64 data.

Inputs: fileName (required), projectId (required), convert, base64Data, +1 more.

typst_write_fileB

Create or overwrite a text file (.typ, .bib, .toml, etc.) in a https://typst.app project, synchronizing the Yjs CRDT update via WebSocket (/editing/v3) and REST (/v1/files/:projectId/:fileId/yjs).

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

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 18 tools

    Disambiguation4/5

    Most tools have clearly distinct resource/action targets, and descriptions help separate rendering, searching, and file mutation operations. Some overlap remains between typst_write_file, typst_edit_file, and typst_find_and_replace, plus minor overlap between typst_list_files and typst_get_project.

    Naming Consistency4/5

    All tools use a consistent typst_ prefix and snake_case, with mostly predictable action_resource names. Minor deviations include typst_auth_login/typst_auth_status using auth as a grouping prefix and typst_find_and_replace using a compound verb.

    Tool Count4/5

    At 18 tools, the surface is slightly above the typical sweet spot but still reasonable for a project-management, file-editing, and rendering MCP. Each tool covers a meaningful operation, though the three content-mutation tools add some density.

    Completeness4/5

    Core project, file, auth, search, compile, export, and screenshot workflows are well covered, including binary asset handling. Minor gaps exist around project metadata updates, sharing/permissions management, and auth logout.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers