Skip to main content
Glama

Assembly MCP

A small Model Context Protocol server that gives any MCP client (Claude Code, Claude Desktop, …) document-conversion and assembly-app upload tools:

Tool

Direction

Engine

convert_pdftomd

PDF → Markdown

assembly-app pdf2md CLI (pdf.js)

convert_mdtopdf

Markdown → PDF

WeasyPrint

upload_issue / issue_draft

files → draft issue → issued

assembly-app upload-issues CLI

upload_renders

images → Renders tab

assembly-app upload-renders CLI

dwg_to_geomap

Revit DWG → lines on Site → Revit Maps

assembly-app upload-dwg-geomap CLI (DWG converted by civil-map-service)

convert_pdftomd and the upload tools run the assembly-app CLIs from self-contained bundles in cli/bin/*.mjs (built by cli/build.mjs), so no assembly-app checkout is needed to use them — just Node ≥ 22. The bundles talk straight to the app's server (Supabase at newapi-next.assembly.nz) as the signed-in person. See Building the CLI bundles. convert_mdtopdf renders Markdown/HTML → PDF with WeasyPrint (pure-Python, no TeX toolchain).


Requirements

  • Python ≥ 3.11

  • uv (recommended) or pip

  • Node ≥ 22 — runs the bundled CLIs in cli/bin/. convert_pdftomd also needs cd cli && npm ci --omit=dev once (pdf.js + the native canvas module).

  • An assembly-app checkout is optional: only used when a bundle is missing (falls back to <ASSEMBLY_APP_DIR>/apps/frontend/scripts/<name>.ts) and for env="dev" config (its apps/frontend/.env.local).

  • WeasyPrint native libraries — only needed for convert_mdtopdf (convert_pdftomd works without them):

    • Linux (Debian/Ubuntu): apt install libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 libffi-dev

    • macOS: brew install pango gdk-pixbuf libffi

    • Windows: install the GTK3 runtime. Without it, convert_pdftomd still works and convert_mdtopdf returns a clear "install GTK" error.


Related MCP server: Markdown2PDF MCP Server

Install

git clone https://github.com/AssemblyJustin/assembly-mcp.git
cd assembly-mcp
uv sync            # creates .venv and installs everything

Run the server directly to confirm it starts (it speaks MCP over stdio and will wait for a client — Ctrl-C to exit):

uv run assembly-mcp

Add to Claude Code

From anywhere, register the server (adjust the path to your clone):

claude mcp add assembly -- uv --directory /ABSOLUTE/PATH/TO/assembly-mcp run --no-sync assembly-mcp

(--no-sync: on Windows, a second Claude session's uv run otherwise tries to reinstall the assembly-mcp.exe the first session is running, fails with "file in use", and the server never connects. Run uv sync yourself after pulling.)

Then the tools are available in your session. This repo also ships matching slash commands — run Claude Code from inside the repo (or copy .claude/commands/* into your project) to use:

/convert-pdftomd  report.pdf  report.md
/convert-mdtopdf  notes.md     notes.pdf
/upload issues
/upload renders
/dwgtogeomap

Add to Claude Desktop

Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\) and add:

{
  "mcpServers": {
    "assembly": {
      "command": "uv",
      "args": ["--directory", "C:\\ABSOLUTE\\PATH\\TO\\assembly-mcp", "run", "--no-sync", "assembly-mcp"]
    }
  }
}

Restart Claude Desktop. The tools appear under the 🔌 tools menu.


Tools

convert_pdftomd

Convert a PDF file to Markdown. PDF→Markdown runs the assembly-app pdf2md converter (pdf.js) — headings, lists, ruled tables, images (saved to <stem>_images/). Requires node ≥ 22 and cli/ installed (npm ci --omit=dev).

Argument

Type

Default

Description

pdf_path

string

—

Path to the source .pdf.

output_path

string

null

Optional path to also write the .md.

strip_watermarks

bool

true

Kept for compatibility; always on in the unified converter.

front_matter

bool

true

Kept for compatibility; always on in the unified converter.

Returns the Markdown text (prefixed with a <!-- pdf2md: … --> summary comment giving page/table/image counts and the output path).

This is a code-only extraction. It does not run vision-based verification, so treat the output as a high-quality first pass, not a certified copy.

convert_mdtopdf

Convert Markdown to a PDF file. Provide either md_path or markdown_text.

Argument

Type

Default

Description

output_path

string

—

Where to write the .pdf (required).

md_path

string

null

Path to a source .md.

markdown_text

string

null

Raw Markdown (alternative to md_path).

title

string

null

Document title (falls back to front-matter title).

css

string

null

CSS to replace the built-in print stylesheet.

Renders Markdown → HTML → PDF with a clean A4 print stylesheet (tables, code blocks, page numbers) and verifies the PDF magic bytes before writing.

upload_issue / issue_draft / upload_renders / dwg_to_geomap

Upload to an assembly-app project as the person doing it. These are thin wrappers over the assembly-app CLIs upload-issues, upload-renders and upload-dwg-geomap, run from the bundles in cli/bin/ (node ≥ 22; no checkout). Each signs in as uploader_email, so the database's own permission rules apply: people can only upload to projects they're on, and viewers and clients can't upload. The slash command /upload issues / /upload renders (.claude/commands/upload.md) drives them; /dwgtogeomap (.claude/commands/dwgtogeomap.md) drives dwg_to_geomap.

Tool

Does

upload_issue(project, issue_type, issue_name, files, env="prod", dry_run=False, uploader_email=None)

Files → a draft issue (Transmittal) on the project's Documents tab. Returns collectionId + recipientChoices. Never issues.

issue_draft(collection_id, issue_type, recipients=[], cover_notes=None, env="prod", uploader_email=None)

Issues that draft (allocates the issue number, which can't be undone). recipients = people and/or organisation names.

upload_renders(project, files, title=None, env="prod", dry_run=False, uploader_email=None)

Images → the project's Renders tab. Skips non-images and images already there.

dwg_to_geomap(project, file, name=None, env="prod", dry_run=False, uploader_email=None)

A Revit DWG → stored lines on the project's Site → Revit Maps tab. The DWG is converted by civil-map-service (POST /api/dwg/geojson, coordinate system + units auto-detected near the project's site). One drawing per name (default: file stem); the same name again replaces it. project may also be a project name. The dry run converts and reports coordinate system, units, layers, line count and distance to site without writing. Civil-map URL: https://civilmap.assembly.co.nz (prod) / https://civilmap-dev.assembly.co.nz (dev), override ASSEMBLY_CIVILMAP_URL.

save_login(email, password, env="prod", make_default=True)

Checks the login by signing in, then saves it to ~/.assembly/credentials.json and (by default) makes them the default uploader. /upload calls it the first time only.

saved_login()

Who /upload acts as on this machine (default + saved people). Never returns passwords.

uploader_email is optional everywhere: omitted, the tools act as the saved default.

project is the project number (e.g. 2610) or UUID. issue_type is the issue purpose: For Information / Review / Approval / Construction / Tender / Coordination / Record (or an org's own).

Setup (once per machine):

  • Login: nothing to do by hand. The first /upload asks for the person's app email + password once and save_login stores them in ~/.assembly/credentials.json ({"_default": "<email>", "<email>": "<password>"}, several people allowed). After that it never asks again. ASSEMBLY_PASSWORD still works for scripted use.

  • Prod: set ASSEMBLY_SUPABASE_ANON_KEY to the prod app's public anon key (URL defaults to https://newapi-next.assembly.nz; override with ASSEMBLY_SUPABASE_URL).

  • Dev (env="dev"): read from the checkout's apps/frontend/.env.local.


Develop

uv run pytest            # smoke tests (PDF→MD skips without node/assembly-app; MD→PDF skips without GTK)

Project layout:

src/assembly_mcp/
  server.py       FastMCP server — registers the tools (stdio); convert_pdftomd
                  shells out to the assembly-app pdf2md CLI (_app_dir())
  md_to_pdf.py    python-markdown → WeasyPrint rendering
.claude/commands/ /convert-pdftomd, /convert-mdtopdf, /upload and /dwgtogeomap slash commands
tests/            smoke tests

License

MIT — see LICENSE.


Building the CLI bundles

cli/bin/*.mjs are esbuild bundles of the assembly-app operator CLIs (upload-issues, upload-renders, upload-product, upload-dwg-geomap, upload-artifact, upload-panomap, pdf2md). They are built from a private repo, so they are gitignored here (this repo is public) and reach the shared copy on P: through push-to-p.sh. Rebuild after the app's CLIs change (build from main, which is what prod runs):

cd cli
npm ci
ASSEMBLY_APP_DIR=<assembly-app checkout on main> npm run build   # writes bin/*.mjs + bin/SOURCE.json

bin/SOURCE.json records the app commit the bundles came from.

Available Tools

2 tools
convert_mdtopdfA

Convert Markdown to a PDF file.

Renders Markdown → HTML → PDF with WeasyPrint (the Assembly MD→PDF stack)
using a clean print stylesheet. Provide EITHER `md_path` OR `markdown_text`.
A PDF is binary, so `output_path` is required.

Args:
    output_path: Path to write the resulting `.pdf` (required).
    md_path: Path to a source `.md` file.
    markdown_text: Raw Markdown string (alternative to `md_path`).
    title: Optional document title (falls back to front-matter `title`).
    css: Optional CSS to replace the built-in print stylesheet.

Returns:
    A confirmation string with the output path, byte size, and page count.

Inputs: output_path (required), css, title, md_path, +1 more. Returns: result

convert_pdftomdA

Convert a PDF file to Markdown.

Uses PyMuPDF with font-size heading detection, running header/footer
removal, table extraction, and optional watermark stripping — the Assembly
PDF→MD pipeline. Returns the Markdown text; when `output_path` is given it
also writes a `.md` file there.

Args:
    pdf_path: Path to the source `.pdf` file.
    output_path: Optional path to also write the Markdown to (`.md`).
    strip_watermarks: Remove Standards-NZ / IHS style watermark lines and
        light-grey overlay text.
    front_matter: Prepend YAML front-matter linking back to the source PDF.

Returns:
    The converted Markdown as a string.

Inputs: pdf_path (required), output_path, front_matter, strip_watermarks. Returns: result

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.6/5.0

    Scored across 2 tools

    Disambiguation5/5

    The two tools are exact inverses: one converts PDF to Markdown, the other Markdown to PDF. There is zero overlap or ambiguity between them.

    Naming Consistency5/5

    Both tool names follow the identical convert_<source>to<target> pattern (convert_pdftomd, convert_mdtopdf). The naming is perfectly consistent and predictable.

    Tool Count4/5

    The server has only 2 tools, which is on the low end, but the scope is tightly focused on bidirectional PDF/Markdown conversion. The count is slightly under the typical 3-15 range yet entirely reasonable for the stated purpose.

    Completeness5/5

    The tool surface fully covers the domain of PDF-Markdown conversion in both directions. There are no obvious missing operations for a conversion-focused utility.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers