Skip to main content
Glama

Contents


Related MCP server: FastMCP LaTeX Server (tex-mcp)

Install

pip install inclusio                       # engine + CLI
pip install 'inclusio[mcp]'                # + FastMCP server
pip install 'inclusio[provenance]'         # + pyhanko (PAdES)
pip install 'inclusio[dev]'                # + pytest, ruff, sphinx, interrogate

Requires Python ≥ 3.11 and a LuaLaTeX toolchain on PATH. Linux, macOS, and WSL are supported (native Windows works for the Python surface; the LaTeX gate needs WSL or a TeX Live install).

Optional tool

Adds

Install

verapdf

The strict EAA / accessibility audit gate

verapdf.org/install

pandoc (≥ 3.0)

HTML5 / JATS XML / EPUB3 multi-format emission

brew install pandoc · apt install pandoc

c2patool

C2PA Content Credentials

contentauth/c2patool releases

pyhanko (via [provenance])

PAdES B-T / B-LT / B-LTA signing

Pulled by the extra

Build from source

git clone https://github.com/sebastienrousseau/inclusio.git
cd inclusio
./bin/setup        # check toolchain + install dev extras
make test          # smoke suite
make coverage      # full suite (gate: 97 %)

Quick Start

A complete worked example you can paste into a fresh directory:

pip install inclusio

# Grab the minimal example, build + audit + emit + judge:
git clone --depth=1 https://github.com/sebastienrousseau/inclusio
cd inclusio/examples/01-hello-world && make

That single make produces build/hello.pdf (PDF/UA-2 + WTPDF + PDF/A-4f triple-conformance), runs veraPDF over it, and exits non-zero if any flavour fails.

Drive the same surface from Python:

# quickstart.py
import subprocess
from pathlib import Path

# 1. Render + build the bundled "hello" fixture — the CLI is the
#    canonical entry point for the LaTeX step.
subprocess.run(
    ["python", "-m", "inclusio.cli.build", "build", "--doc", "hello"],
    cwd="examples/01-hello-world",
    check=True,
)

# 2. Audit the produced PDF in-process — pure-Python, no subprocess.
from inclusio.cli import audit

pdfs = audit.collect_pdfs(
    target=Path("examples/01-hello-world/build"),
    build_dir=Path("examples/01-hello-world/build"),
    registry_stems={"hello"},
)
report = audit.audit(pdfs)
assert report["summary"]["fail"] == 0, "veraPDF reported a failure"
print(f'  PASS  {report["summary"]["pdfs"]} PDF(s), '
      f'{report["summary"]["pass"]}/{report["summary"]["total"]} checks')
# →   PASS  1 PDF(s), 3/3 checks

Features

  • Tagged PDF, by default. Every build emits a PDF/UA-2 + WTPDF + PDF/A-4f triple-conforming artefact via the LaTeX kernel's tagpdf integration. The veraPDF audit gate is wired into CI and exits non-zero on any FAIL.

  • Multi-format emission. The same LaTeX source produces HTML5 (WCAG-clean), JATS XML (1.3, JATS4R-ready), and EPUB3 via Pandoc.

  • LLM-augmented judges. ATS (Workday / Greenhouse / Lever heuristic), citation grounding, and JD-to-CV fit — local llama.cpp or BYO-key cloud (Anthropic / OpenAI), with heuristic-only fallback when the LLM is unreachable.

  • Content provenance. C2PA Content Credentials (via c2patool), PAdES B-T / B-LT / B-LTA signatures (via pyhanko), and SLSA L3 build attestation (via actions/attest-build-provenance).

  • MCP server. inclusio-mcp exposes list_docs, audit_pdf, render, and doc_count so Claude Code, Cursor, Continue, or any other MCP client can drive the engine.

  • JSON Resume importer. inclusio import-resume converts a jsonresume.org v1 document into the engine's CV YAML schema.

  • Brief-driven CV tailoring. ATS-clean variants tailored against a job description with British-English cleanup and consistency lint.

Usage

Build, audit, judge a registered document

inclusio build --doc cv --mode draft        # → build/cv.pdf
inclusio audit --strict                     # → veraPDF, non-zero on FAIL
inclusio judge --doc cv --judge ats         # → grade + findings

Score a CV against a job description

# score_cv.py — fully runnable: drop into a directory with brief.txt + cv.txt
from pathlib import Path
from inclusio.judge import jd_fit

jd_text = Path("brief.txt").read_text(encoding="utf-8")
cv_text = Path("cv.txt").read_text(encoding="utf-8")

report = jd_fit.score_jd_fit(jd_text, cv_text)
print(f"score:   {report.score}/100   grade: {report.grade}")
print(f"missing: {sorted(report.metrics['missing_required'])[:5]}")
# → score:   78/100   grade: B
# → missing: ['opentelemetry', 'rust']

Drive the engine over MCP

inclusio-mcp                          # stdio (Claude Code default)
inclusio-mcp --http --port 8765       # Streamable HTTP

Wire into Claude Code via ~/.claude/claude_desktop_config.json:

{
  "mcpServers": {
    "inclusio": {
      "command": "inclusio-mcp",
      "env": { "INCLUSIO_CONTENT_DIR": "/absolute/path/to/content" }
    }
  }
}

Embed C2PA Content Credentials

inclusio provenance --doc cv \
  --cert /path/to/cert.pem \
  --key  /path/to/key.pem \
  --output build/cv.c2pa.pdf

Tools

The inclusio-mcp server exposes four MCP tools:

  • list_docs — Enumerate documents registered in the content tree

  • doc_count — Quick count of available documents

  • render — Build a tagged, conformant PDF (and other formats) for a document

  • audit_pdf — Accessibility audit of a PDF (veraPDF)

Plus three read-only resources:

  • inclusio://meta — Project manifest (meta.yaml)

  • inclusio://audit/latest — Latest audit report

  • inclusio://version — Engine version card


Architecture

inclusio/                  # Python package
  cli/                     # build · audit · render · tailor · judge · emit · provenance · …
  judge/                   # ats · citations · jd_fit · local_llm · cloud_llm
  emit/                    # pandoc (HTML5 / JATS XML / EPUB3)
  provenance/              # c2pa (c2patool) · pades (pyhanko)
  mcp/                     # FastMCP server
  tools/                   # fix_semantic · stamp_pdfs · overlay
core/                      # LaTeX classes (.cls) and styles (.sty)
templates/                 # Jinja2 templates for the template-driven docs
benches/                   # pytest-benchmark micro-benchmarks
examples/                  # Six self-contained runnable scenarios
docs/                      # Sphinx documentation

External consumers supply their own content tree (LaTeX sources, YAML metadata, brand assets) and point the engine at it through INCLUSIO_CONTENT_DIR or --content-dir. The repo's own src/ and data/ directories double as the public-engine self-test fixtures.

Examples

#

Folder

What it teaches

1

01-hello-world/

Tagged-PDF build with the audit gate

2

02-cv-from-jsonresume/

JSON Resume → CV → ATS + JD-fit scoring

3

03-paper-with-citations/

Paper → PDF + HTML + JATS + EPUB + citation judge

4

04-mcp-agent/

inclusio-mcp + Claude Code skill

5

05-c2pa-sign/

C2PA Content Credentials

6

06-pades-sign/

PAdES B-T eIDAS signature

Each folder has its own Makefile (make help lists targets) and a README.md with the why + the how.

Documentation

  • Quickstart — five-minute walkthrough.

  • Tutorials — four end-to-end walkthroughs paired 1 : 1 with the examples.

  • Architecture — public-engine vs content-repo boundary, sprint history, decision log.

  • Tagged PDF — the conformance stack.

  • Multi-format — HTML / JATS / EPUB.

  • Judges — ATS, citations, JD-fit, LLM rerank contract.

  • Provenance — C2PA, PAdES, SLSA.

  • MCP server — tool + resource surface.

Publishing against an external content tree

make publish CONTENT_DIR=/absolute/path/to/your-content-repo

The content repo supplies its own data/meta.yaml (document registry) and src/**.tex (LaTeX sources). The engine reads no state from outside INCLUSIO_CONTENT_DIR once it's set.

Development

make test          # smoke (≤ 20 s)
make coverage      # full suite + 97 % gate (~3 min)
make docstrings    # 100 % interrogate gate
make benchmark     # pytest-benchmark micro-budgets
make audit-strict  # veraPDF, exits non-zero on any FAIL
make docs          # Sphinx

All commits to main are squash-merged via PR. Branch protection requires Lint (ruff) + Public Engine Checks (py3.11 / 3.12 / 3.13) + the Signed-commit gate to pass. See CONTRIBUTING.md.

Security

  • SSH-signed commits. Every commit on main is GitHub-verified.

  • Signed tags. Release tags are ED25519-signed.

  • SLSA L3 build provenance (gated on the repo being public or on a paid GitHub plan).

  • PyPI Trusted Publishing wiring (pypa/gh-action-pypi-publish) in release.yml; flip vars.PYPI_TRUSTED_PUBLISHING=true once the PyPI publisher is configured.

  • Cloud LLM keys are env-var onlyinclusio never auto- discovers credentials from disk.

Report vulnerabilities per SECURITY.md.

Sibling MCP servers by the same author — each targets a different agent workflow:

Server

Purpose

noyalib-mcp

Lossless YAML 1.2 parsing, formatting & validation (Rust)

rlg-mcp

RustLogs log streams for on-call / SRE agent workflows

pain001-mcp

Generate & validate ISO 20022 pain.001 payment initiation files

bankstatementparser-mcp

Parse bank statements (BAI2, MT940/MT942, CAMT.053, OFX, CSV)

camt053-mcp

Parse & reconcile ISO 20022 camt.053 bank-to-customer statements

acmt001-mcp

Generate & validate ISO 20022 acmt.001 account management messages


MCP Registry

mcp-name: io.github.sebastienrousseau/inclusio-mcp

Install the MCP server with pip install 'inclusio[mcp]' (the mcp extra pulls in mcp[cli]>=1.27.0). Run with inclusio-mcp — stdio transport, exposes accessibility-publishing tools to Claude Desktop, Cursor, and other MCP clients.


License

MIT. © 2026 Sebastien Rousseau.

Available Tools

4 tools
audit_pdfAudit PDF accessibility (veraPDF)A
Read-onlyIdempotent

Audit built PDFs for accessibility conformance with veraPDF.

    Use this to check whether a rendered PDF meets PDF/UA-2, WTPDF, and
    PDF/A-4f before publishing; it shells out to ``verapdf`` read-only
    and never modifies the PDF or the manifest. To produce a document's
    source first call ``render``; to see which documents exist call
    ``list_docs``. This inspects existing PDFs only — it does not build
    them.

    Args:
        target: PDF path or directory. Defaults to `build/` under
            INCLUSIO_CONTENT_DIR.
        strict: When True, every blocking-flavour FAIL is surfaced
            in the response (`blocking_failure: True`); the caller
            decides whether to treat this as an error.

    Returns the audit report dict (summary, by_pdf, by_flavour).
    Requires `verapdf` on PATH; the report contains
    `verapdf_present: False` when it is not.
    
ParametersJSON Schema
NameRequiredDescriptionDefault
strictNoWhen true, every blocking-flavour FAIL is surfaced as `blocking_failure: true` in the response.
targetNoPDF file path or directory to audit; defaults to `build/` under INCLUSIO_CONTENT_DIR.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnly and idempotent. Description adds important context: shells out to verapdf read-only, never modifies PDF/manifest, requires 'verapdf' on PATH, and includes 'verapdf_present' field in response. No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear first sentence, usage paragraph, parameter descriptions, and return info. No redundant or extraneous content; every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With output schema present, description sufficiently covers return type. Also documents external dependency and failure flag, making it complete for a tool that shells out.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers both parameters fully. Description adds value for 'strict' parameter by explaining caller decides error handling, which enhances semantic clarity beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb 'audit' and specific resource 'built PDFs for accessibility conformance with veraPDF' with explicit standards. Distinguishes from siblings by referencing 'render' and 'list_docs' for related tasks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use (before publishing) and what it does not do (does not build or modify). References alternative tools ('render' for production, 'list_docs' for listing) for proper workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

doc_countCount registered documentsA
Read-onlyIdempotent

Count the documents registered in data/meta.yaml.

    Use this as a cheap connectivity/health probe to confirm the server
    sees a valid manifest without transferring the full document list.
    When you need each document's id, class, and flags, call
    ``list_docs`` instead.

    Cheap probe for clients that just want to verify connectivity
    and that the engine sees a valid manifest.
    
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, idempotentHint, destructiveHint, openWorldHint. Description adds that it's a cheap probe and confirms server sees valid manifest without transferring full list. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very concise; uses two clear blocks. Main action front-loaded. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters, good annotations, and presence of an output schema, the description sufficiently covers all necessary contextual information for a simple count operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters defined; schema covers all. Baseline for 0 parameters is 4. Description does not need to add parameter detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Count the documents registered in data/meta.yaml' with a specific verb and resource. It also distinguishes from sibling tool list_docs by noting that list_docs provides individual document details.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use: as a cheap connectivity/health probe. Also tells when not to use: if you need each document's id/class/flags, call list_docs instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_docsList registered documentsA
Read-onlyIdempotent

List every document registered in data/meta.yaml with its metadata.

    Use this first to discover the ``doc_id`` values and document
    classes available before calling ``render`` or ``audit_pdf``. For
    just the document count (a connectivity probe) call ``doc_count``
    instead; to read the raw manifest text use the ``inclusio://meta``
    resource. Reads ``data/meta.yaml`` under ``INCLUSIO_CONTENT_DIR``
    (or the packaged content root); it writes nothing.

    Returns one dict per document with id, class, src, title, and
    any `pdf_a` / `note` flags. Empty list when no manifest exists.
    
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only and non-destructive behaviors; the description adds context about reading from INCLUSIO_CONTENT_DIR and returning specific fields, enhancing transparency beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the primary purpose, followed by usage context, technical details, and return format, all in a concise, well-organized structure without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters, rich annotations, and the existence of an output schema, the description covers the tool's full behavior including data source, return format, and edge case (empty list). Sufficiently complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters exist, so baseline 4 applies. The description does not need to elaborate on parameters, and schema coverage is 100% (vacuous).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists documents from data/meta.yaml, and distinguishes itself from siblings like render, audit_pdf, and doc_count by specifying its role as a discovery step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises using this tool first to get doc_id and class before calling render or audit_pdf, and suggests doc_count for just the count. Provides clear when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

renderRender document to a fileA
Idempotent

Render a registered template-driven document to a file on disk.

    Use this to materialise a document's source (LaTeX, Markdown, JSON,
    or text) into ``build/.cache/rendered/`` before compiling or
    auditing it. This writes the rendered output file but never mutates
    ``data/meta.yaml``. Discover valid ``doc_id`` values with
    ``list_docs`` first; audit the resulting PDF afterwards with
    ``audit_pdf``. This is the only write tool on this server — the
    others are read-only.

    Args:
        doc_id: registered template id (see `list_docs`).
        fmt: one of `latex`, `markdown`, `json`, `text`.
        mode: one of `draft`, `submission`, `camera-ready`.

    Returns `{"doc_id": …, "format": …, "output_path": …, "bytes": int}`.
    
ParametersJSON Schema
NameRequiredDescriptionDefault
fmtNoOutput format: one of `latex`, `markdown`, `json`, `text`.latex
modeNoRender mode: one of `draft`, `submission`, `camera-ready`.draft
doc_idYesRegistered template document id — see `list_docs`.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses write behavior to build/.cache/rendered/, non-mutation of data/meta.yaml, and idempotent nature. Consistent with annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=true). Adds context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

All sentences serve a purpose: purpose, usage, args, returns. Front-loaded with action and context. No fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Fully covered: purpose, usage, parameters, output schema, sibling relationships. Output schema is described in text. Annotations present. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Each parameter is described in the description with additional context (e.g., doc_id discovery via list_docs). Schema coverage is 100%, but description adds value by linking parameters to tool usage workflow.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it renders a template-driven document to disk. Distinguishes itself as the only write tool among siblings, using specific verb 'render' and explicit resource 'registered template-driven document'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use (materialise before compile/audit), what it does not do (never mutates data/meta.yaml), and suggests discovery with list_docs and follow-up with audit_pdf. Also contrasts with sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 2 tool updatesv0.0.9
    • Changedaudit_pdf2 fields changed
      • addedInput schema / properties / strict / description
        Added value: +"When true, every blocking-flavour FAIL is surfaced as `blocking_failure: true` in the response."
      • addedInput schema / properties / target / description
        Added value: +"PDF file path or directory to audit; defaults to `build/` under INCLUSIO_CONTENT_DIR."
    • Changedrender3 fields changed
      • addedInput schema / properties / doc_id / description
        Added value: +"Registered template document id — see `list_docs`."
      • addedInput schema / properties / fmt / description
        Added value: +"Output format: one of `latex`, `markdown`, `json`, `text`."
      • addedInput schema / properties / mode / description
        Added value: +"Render mode: one of `draft`, `submission`, `camera-ready`."
  2. 4 tool updatesv0.0.7
    • First observedaudit_pdf
    • First observeddoc_count
    • First observedlist_docs
    • First observedrender

TDQS

A4.6/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: audit_pdf checks PDF conformance, doc_count provides a count, list_docs lists all documents, and render generates source files. No overlap or ambiguity.

Naming Consistency4/5

Three tools follow a verb_noun pattern (audit_pdf, doc_count, list_docs), but 'render' is a verb-only name, deviating slightly from the convention. All use consistent snake_case.

Tool Count5/5

With 4 tools covering listing, counting, rendering, and auditing, the count is well-scoped for a document management server. Each tool serves a necessary function without excess.

Completeness3/5

The set covers document discovery, rendering, and auditing, but lacks a compile step to convert rendered source into PDFs, which is implied between render and audit. This gap may hinder workflows.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sebastienrousseau/inclusio'

If you have feedback or need assistance with the MCP directory API, please join our Discord server