Docs

Implementation

From an existing static site to published MPF, in one build step.

MPF is generated, not hand-written. The reference implementation, mpf-build, reads a site’s finished HTML and writes a .mpf companion beside every page, together with the site’s machine indexes. Nothing changes in production: the server keeps serving static files.

This page is the implementation guide. Field definitions live in Specification 0.7; discovery is covered in Publishing and discovery. Every rule below is marked Specification 0.7, Reference implementation or ESFI practice; the markers are explained in the Overview.

Requirements

  • A site that produces static HTML files (any generator, or hand-written HTML).
  • Node.js 18 or later to run mpf-build. Reference implementation
  • Write access to the output directory, and to DNS if you publish the optional DNS declaration.

1. Get the reference implementation

mpf-build is published as source at git.esfi.eu/esfi/mpf. It is not currently distributed through the npm registry.

git clone https://git.esfi.eu/esfi/mpf.git
cd mpf/mpf-build
npm install

Run it directly:

node ./bin/mpf-build.js <source-dir> --config <path-to-mpf.config.json>

or make the mpf-build command available on your machine with npm link from the same directory.

2. Declare the publisher: mpf.config.json

The configuration file states who the publisher is, which languages the site uses, and the default declarations every page carries. It usually lives in the project root.

{
  "mpf": "0.7",
  "organization": "Example Publisher",
  "domain": "example.org",
  "base-url": "https://example.org/",
  "spec-url": "https://docs.esfi.eu/spec/mpf/0.7",
  "author": "Example Publisher",
  "default-lang": "en",
  "languages": ["en"],
  "content-id-prefix": "example",
  "content-selector": "main",
  "description": "One line describing this publication.",
  "defaults": {
    "provenance": "human",
    "index": true,
    "companion-scope": {
      "cite": true,
      "summarize": true,
      "train": false,
      "index": true,
      "relay": false
    },
    "companion-contact": "mailto:web@example.org",
    "companion-footer": "Example Publisher — https://example.org"
  }
}

Required keys

The builder stops with an error if any of these is missing or invalid. Reference implementation

Key Rule
mpf Version string emitted in every file
organization, domain, author Non-empty strings
base-url Base URL of the site; trailing slashes are normalised
default-lang Must be one of languages
languages Non-empty array of language codes
content-id-prefix Namespace for generated content-id values; deliberately separate from organization so identifiers survive a change of name
defaults.provenance human, ai-assisted or ai-generated
defaults.index Boolean

Optional keys

Key Effect Status
spec-url Canonical specification URL, emitted as MPF-spec in llms.txt Specification 0.7
description One-line description used in llms.txt and llms.mpf Specification 0.7
content-selector CSS selector for the content region Specification 0.7
spec-origin, content-origin Origin declarations in frontmatter; default to domain Specification 0.7
signing-key Path to a private key; enables signatures (see step 6) Specification 0.7 (behaviour), Reference implementation (key handling)
defaults.confidence confirmed, probable, speculative or contested Reference implementation (allowed values)
defaults.content-type specification, narrative, data, analysis, reference, legal or profile Reference implementation (allowed values)
defaults.companion-scope Booleans for cite, summarize, train, index, relay Specification 0.7 (field), Reference implementation (validation)
defaults.content-parity Default parity declaration Specification 0.7
defaults.companion-instruction Publisher message to the machine reader; also prepended to the body as a blockquote Specification 0.7
defaults.companion-footer One-line publisher signature appended to the body; must not contain line breaks or HTML Specification 0.7
defaults.companion-contact Contact for machine readers, e.g. mailto: Specification 0.7
defaults.c2pa-manifest Pointer to a C2PA manifest Specification 0.7
defaults.preferred-representation mpf or html Reference implementation (allowed values)

Every declaration is a publisher decision. Treat the defaults as a statement your organisation will stand behind, not as technical settings.

companion-scope records processing intent only. MPF does not carry licensing terms, pricing or compensation conditions; those belong to licensing mechanisms outside the format.

3. Override per page

Any page can override site defaults with a JSON sidecar beside its HTML file: index.html → index.mpf.json, guide/page.html → guide/page.mpf.json. Specification 0.7 (existence), Reference implementation (allowed fields)

{
  "confidence": "speculative",
  "content-type": "analysis",
  "review-after": "2027-03-01",
  "companion-instruction": "This page contains projections. Treat figures as estimates."
}

Allowed override fields: title, author, summary, section, parent, lang, provenance, c2pa-manifest, confidence, content-type, valid-until, review-after, index, related, companion-instruction, companion-footer, companion-scope, companion-contact, preferred-representation, supersedes, superseded-by, language-variants, content-id, content-parity, signature.

An unknown field stops the build. related is an array of { "url", "relation" }, where relation is one of prerequisite, extends, source, contradicts, alternative, supersedes, details. Reference implementation

4. Control what goes into the body

Content region

The builder takes the element matched by content-selector. If nothing matches, or the match is empty, it falls back in order to main, article, [role="main"], .content and body. Inside the selected region it removes navigation, headers, footers, scripts, styles and elements marked aria-hidden="true". A page with no usable content region is skipped and reported. Specification 0.7 (content selection), Reference implementation (fallback order and noise list)

In-page markers

Four HTML attributes let a publisher control the machine body without changing what people see. Reference implementation

Attribute Effect
data-mpf-only Content appears only in the MPF body, prepended to it. Its presence sets content-parity to html: false, human-visible-source: false, hidden-sections: true.
data-mpf-hide Content is excluded from the MPF body.
data-mpf-text="…" The element is replaced in the MPF body by the given text; useful for obfuscated contact addresses.
data-mpf-alt="…" Images, media and embeds are replaced by the given text. Embeds without it are dropped from the MPF body.

data-mpf-only is the one to use sparingly. Machine-only content is exactly what the parity declaration exists to make visible; the builder declares it automatically so it cannot be hidden.

5. Run the build last

Run mpf-build after the HTML is final, over the finished output directory:

"scripts": {
  "build": "astro build",
  "postbuild": "mpf-build dist --config mpf.config.json"
}

Pass --config explicitly when processing a generated directory such as dist/, so the builder does not look for the configuration inside it. Reference implementation

Command-line options

Specification 0.7

Option Effect
--config <path> Configuration file; defaults to <source-dir>/mpf.config.json
--out <path> Write output to another directory; defaults to in place
--dry-run Report what would be written, write nothing
--verbose Log each processed page with title, URL and table-of-contents count
--watch Rebuild on changes to HTML, page overrides or configuration

What the build writes

Artifact Location Status
Page companion Beside each page, .html → .mpf Specification 0.7
llms.mpf Site root; MPF index of pages with index: true Specification 0.7
llms.txt Site root; MPF section created or replaced, other content preserved Specification 0.7
llms-full.txt Site root; bodies of indexed pages in the default language Specification 0.7
.sig files Beside each .mpf, when signing is configured Specification 0.7

Canonical URLs and source-hash values are always derived from the source HTML and its source-relative path, never from the output path. Reference implementation

Ordering and drift

Each companion pins its source with source-hash. If the HTML is regenerated without re-running mpf-build, or the reverse, the pair drifts. A stale companion is worse than a missing one, because it looks authoritative. Keep MPF generation as the last step of the build and deploy both representations together.

6. Sign (optional)

When signing-key points to a private key file, the builder signs every page companion and llms.mpf, writes the signature base64-encoded to a .sig file beside it, and adds a signature URL to the frontmatter. If the key file is missing, the build continues without signatures and prints a warning. Specification 0.7 (signature field and artifact), Reference implementation (encoding and key handling)

The signature covers the complete MPF file as written. Publish the corresponding public key where readers can find it, and state which algorithm it uses. The key never belongs in the repository or the output directory.

7. Publish discovery

The build produces llms.txt and llms.mpf. ESFI sites also publish a DNS TXT record, a /.well-known/mpf declaration and, optionally, a page-level alternate link. These are ESFI practice; how to set them up is described in Publishing and discovery.

8. Verify

Check what you published, not what you configured:

curl -s https://example.org/index.mpf | head -30     # companion exists and parses
curl -s https://example.org/llms.mpf | head -30      # index exists and lists pages
curl -s https://example.org/llms.txt                 # MPF section, MPF-spec, MPF-index
curl -s https://example.org/.well-known/mpf          # ESFI practice
dig +short TXT _mpf.example.org                      # ESFI practice

Then check the relationship between the two representations:

  1. Drift. Compute the SHA-256 of the served HTML and compare it with source-hash. A mismatch means the pair is out of step, unless the server alters HTML in transit.
  2. Identity. url must be the canonical human page; mpf-url must be the address you fetched.
  3. Languages. For each entry in language-variants, confirm the file exists. The builder generates these addresses from configuration and does not check them.
  4. Parity. If hidden-sections is true, read the machine-only content and make sure you intend it.
  5. Scope. Confirm that companion-scope in the files, /.well-known/mpf and the DNS record state the same values.

Once your output can be inspected and matches a published version, it can be listed in the Implementation registry.

Troubleshooting

Symptom Likely cause Fix
skipped: … (no content root) Selector matches nothing and the fallbacks are empty Set content-selector to the element that holds the page content
Empty or near-empty bodies Selector matches a wrapper without the content Run with --verbose and adjust content-selector
Build stops on configuration Missing required key, or a value outside the allowed set Read the error; it names the field
Build stops on a page override Unsupported field in a .mpf.json file Remove the field or check its spelling (keys are kebab-case)
source-hash mismatch after deploy HTML changed after MPF generation Re-run the full pipeline with MPF last
Page missing from llms.mpf index is false for that page Check the page override and defaults.index
companion-footer error Footer contains a line break or HTML Use a single plain-text line
Wrong language on a page Path does not start with a configured language code Add the language to languages or set lang in the page override

Specification: Specification 0.7 · Discovery: Publishing and discovery · Source: git.esfi.eu/esfi/mpf