MobileReality/mdma

๐Ÿ’ป Developer Tools
0 Views
0 Installs

๐Ÿ“‡ โ˜๏ธ ๐Ÿ  ๐ŸŽ ๐ŸชŸ ๐Ÿง - MCP server for MDMA (interactive Markdown applications with mounted components). Exposes the MDMA spec, authoring prompts, package metadata, and live docs to AI assistants. Tools: get-spec, get-prompt, build-system-prompt, validate-prompt, list-packages, list-docs, get-doc. Install: npx @mobile-reality/mdma-mcp.

Quick Install

One-Click IDE Configuration
claude_desktop_config.json
{
  "mcpServers": {
    "mobilereality-mdma": {
      "command": "npx",
      "args": [
        "-y",
        "mobilereality-mdma"
      ]
    }
  }
}
Or

Using an AI coding agent (Claude Code, Cursor, etc.)? Copy a ready-made prompt that tells it to fetch the setup instructions and install this server for you.

Documentation Overview

MDMA Logo

MDMA

Markdown Document with Mounted Applications

Interactive documents from Markdown. Built for next gen-apps

๐ŸŒ Website ย ย ยทย ย  ๐Ÿš€ Live Demo ย ย ยทย ย  ๐Ÿ“– Docs ย ย ยทย ย  ๐Ÿ’ฌ Discord ย ย ยทย ย  ๐Ÿค— Model

Why MDMA?

AI conversations today are plain text โ€” the user reads a response and manually acts on it. MDMA changes that. When an LLM knows the MDMA spec, it can respond with interactive components (forms, tables, approval gates) instead of just text. The conversation becomes actionable: the user fills out a form, approves a step, or reviews structured data โ€” all inline, with a predictable schema that your app already knows how to render and process.

No custom UI per use case. No parsing free-form text. The AI generates structured, validated components and your frontend renders them instantly.

MDMA Demo

What is MDMA?

MDMA extends Markdown with interactive components defined in fenced mdma code blocks. A regular Markdown file becomes an interactive application:

# Patient Intake

```mdma
type: form
id: intake-form
fields:
  - name: patient-name
    type: text
    label: "Full Name"
    required: true
    sensitive: true
  - name: email
    type: email
    label: "Email"
    required: true
    sensitive: true
  - name: reason
    type: textarea
    label: "Reason for Visit"
    required: true
onSubmit: submit-intake
```

```mdma
type: button
id: submit-btn
text: "Submit Intake Form"
variant: primary
onAction: submit
```

Speed comparison

Same scenario, two models. GPT-5.5 and our own hosted MDMA-IL model.

Our model is available on Hugging Face: MobileReality/mdma-gemma4-26b-dsl-unsloth-v1

GPT-5.5Our own hosted model

MDMA_AUTHOR prompt matrix

Each cell shows the pass rate of the model-specialized MDMA_AUTHOR prompt variant on the listed eval suite.

โœ… 100% on the suite.

๐ŸŸก Scoring between 80โ€“99% on the suite.

๐Ÿ”ด Scoring below 80% on the suite.

Variantone-shotone-shot with custom promptconversationspecific flow of conversation
OpenAI
gpt-5.6-solโœ…โœ…โœ…โœ…
gpt-5.6-terraโœ…โœ…โœ…โœ…
gpt-5.6-lunaโœ…โœ…โœ…โœ…
gpt-5.5โœ…โœ…โœ…โœ…
gpt-5.4โœ…โœ… โ€ โœ… โ€ โœ… โ€ 
gpt-5.4-miniโœ…โœ…โœ… *โœ… *
gpt-5.4-nanoโœ…โœ…โœ… *โœ… *
gpt-5.2โœ…โœ…โœ…โœ…
gpt-5.1โœ…โœ…โœ…โœ…
gpt-5 [i]โœ…โœ…โœ…โœ…
gpt-5-mini [i]โœ…โœ…โœ… *โœ… *
gpt-5-nano [i]โœ…โœ…๐ŸŸก *๐ŸŸก *
gpt-4.1โœ…โœ…โœ…โœ…
gpt-4.1-miniโœ…โœ…โœ… *โœ… *
gpt-4.1-nanoโœ…โœ…โœ… *๐ŸŸก *
Anthropic
claude-opus-4.8โœ…โœ…โœ…โœ…
claude-opus-4.7โœ…โœ…โœ…โœ…
claude-opus-4.6โœ…โœ…โœ…โœ…
claude-sonnet-4.6โœ…โœ…โœ…โœ…
claude-haiku-4.5โœ…โœ…โœ… *โœ… *
claude-fable-5โœ…โœ…โœ…โœ…
Google
gemini-3.5-flashโœ…โœ…โœ…โœ…
gemini-3.1-pro-previewโœ…โœ…โœ…๐ŸŸก โ€ก
gemini-3.1-pro-preview-customtoolsโœ…โœ…โœ…โœ…
gemini-3.1-flash-lite-previewโœ…โœ…โœ… *โœ… *
gemini-3-flash-previewโœ…โœ…โœ… *โœ… *
gemini-2.5-proโœ…โœ…โœ…โœ…
gemini-2.5-flashโœ…โœ…โœ… *โœ… *
gemini-2.5-flash-liteโœ…โœ…โœ… *โœ… *
xAI
grok-4.3 [i]๐ŸŸก๐Ÿ”ด๐Ÿ”ด๐Ÿ”ด
grok-4.20โœ…โœ…โœ…โœ…
grok-4.5โœ…โœ…โœ…โœ…
Zhipu (z.ai)
glm-4-plusTBDTBDTBDTBD
Moonshot
kimi-k2TBDTBDTBDTBD
Alibaba
qwen3-maxTBDTBDTBDTBD
MiniMax
minimax-m1TBDTBDTBDTBD
Other
modelโ€”โ€”โ€”โ€”

Don't see your model? Add a prompt variant under packages/prompt-pack/src/prompts/mdma-author/<vendor>/ and open a PR โ€” we'll run the eval suite and add it to this table.

โ€  gpt-5.4 intermittent duplication bug โ€” gpt-5.4 passes one-shot evals reliably but shows a non-deterministic output duplication in multi-turn, custom-prompt, and flow evals (~7โ€“15% of runs). The model generates a complete, correct response and then immediately re-emits the entire output verbatim, causing [duplicate-ids] validation errors. This is a known model-level issue unrelated to the prompt variant. See the OpenAI community thread for details. If this affects your use case, prefer gpt-5.5 or gpt-5.2.

โ€ก gemini-3.1-pro-preview stochastic preamble loop โ€” on ~7โ€“15% of flow-eval runs, the model emits a chain-of-thought as visible Markdown prose (e.g. **Investigating Production Errors** repeated 3โ€“5 times) instead of opening a ```mdma block, producing either [yaml-correctness: outside fenced block] or [duplicate-ids] errors. Per Google's official Gemini 3 prompting guide, this is a model-level behavior driven by temperature/sampling โ€” prompt-level fixes shift which test loops rather than eliminating the loops. If deterministic flow output matters, prefer gemini-2.5-pro for production multi-step flows.

* Smaller / lower-tier models from any lab (OpenAI mini ยท nano, Anthropic Haiku, Google Gemini Flash, etc.) pass our eval suites, which exercise short, structured test cases. In longer real-world conversations they tend to hallucinate, forget earlier turns, or drift from the spec. For production use that involves multi-turn dialogue or stateful flows, prefer the flagship-tier model from the same family.

[i] Noticeably slow response times โ€” single-turn responses commonly take tens of seconds and full eval runs measure in minutes.

MDMA_FIXER prompt matrix

Each cell shows the pass rate of the model-specialized MDMA_FIXER prompt variant on the single-block fixer eval (16 tests covering structural fixes, bindings, PII, forms, tables/charts, approvals, and custom-component extraction). The fixer is what powers automatic repair of LLM output that fails validate() โ€” every supported model lands at โœ… via model-tailored inline guards (no-leading-separator, preserve-input-structure, table-key-direction, replace-all-placeholders, fix-all-listed-errors, etc.).

โœ… 100% on the single-block fixer eval (16/16).

Variantsingle-block fixernotes for testing
OpenAI
gpt-5.6-solโœ…
gpt-5.6-terraโœ…
gpt-5.6-lunaโœ…
gpt-5.5โœ…
gpt-5.4โœ…
gpt-5.4-miniโœ…
gpt-5.4-nanoโœ…
gpt-5.2โœ…
gpt-5.1โœ…
gpt-5โœ…
gpt-5-miniโœ…
gpt-5-nanoโœ…
gpt-4.1โœ…
gpt-4.1-miniโœ…
gpt-4.1-nanoโœ…
Anthropic
claude-opus-4.8โœ…
claude-opus-4.7โœ…
claude-opus-4.6โœ…
claude-sonnetโœ…catch-all variant โ€” matches claude-sonnet-4-5, claude-sonnet-4-6, etc.
claude-haikuโœ…
claude-fable-5โœ… โ€กrequires reasoning.exclude: true (wired in evals/promptfooconfig.fixer.js)
Google
gemini-3.5-flashโœ… โ€กrequires reasoning.exclude: true; adds an inline no-leading-separator guard
gemini-3.1-pro-previewโœ… โ€กrequires OpenRouter reasoning.exclude: true (already wired in evals/promptfooconfig.fixer.js)
gemini-3.1-pro-preview-customtoolsโœ… โ€กsame reasoning.exclude requirement
gemini-3.1-flash-lite-previewโœ…
gemini-3-flash-previewโœ…
gemini-2.5-proโœ… โ€กsame reasoning.exclude requirement
gemini-2.5-flashโœ…
gemini-2.5-flash-liteโœ…
xAI
grok-4.3โœ… โ€กminimal prompt + reasoning.exclude: true โ€” extra framing regresses Grok 4.3
grok-4.20โœ…
grok-4.5โœ… โ€กrequires reasoning.exclude: true (hidden-reasoning model)

โ€ก Reasoning-token leak suppression โ€” for reasoning-flavoured Gemini Pro variants and Grok 4.3, the fixer would otherwise see visible "Thinking: Topic" prose prepended to every response. The eval config sets passthrough.reasoning.exclude: true (and the demo's usePreviewValidation does the same per-provider) to strip reasoning tokens from the response body at the API layer rather than at the prompt layer.

Components

10 built-in component types, all rendered out of the box by @mobile-reality/mdma-renderer-react:

ComponentType keyDescription
FormformMulti-field forms with text, number, email, date, select, checkbox, textarea, and file fields. Supports validation, required fields, default values, and sensitive (PII) flags.
ButtonbuttonAction buttons with primary, secondary, and danger variants.
TasklisttasklistInteractive checkbox task items with labels.
TabletableData tables with typed columns and row data.
ChartchartTable fallback by default โ€” renders chart data as a simple HTML table to avoid forcing a charting dependency (~400KB). Override with your own renderer (e.g. recharts) via customizations.components.chart (see Custom Chart Renderer below).
CalloutcalloutAlert banners with info, warning, error, and success variants. Supports optional title and dismiss button.
Approval Gateapproval-gateApprove/deny workflow gates with pending, approved, and denied states.
WebhookwebhookWebhook triggers with idle, executing, success, and error status indicators.
ThinkingthinkingCollapsible thinking/reasoning blocks that show the AI's chain of thought.
CustomcustomHost-extensible escape hatch โ€” a stable envelope (name + open props + actions) that dispatches to a host-registered variant renderer. Register a variant's schema/behavior with registerCustomComponent and its renderer via customizations.customVariants. Use only when no built-in type fits.

Additionally, standard Markdown content (headings, paragraphs, lists, code blocks, images, links, tables, etc.) is rendered inline between components.

Custom Chart Renderer

The built-in chart renderer intentionally renders data as a plain table so the library stays lightweight. To get actual charts, register a custom renderer:

import { MdmaDocument } from '@mobile-reality/mdma-renderer-react';
import { MyRechartsRenderer } from './MyRechartsRenderer';

function App({ ast, store }) {
  return (
    <MdmaDocument
      ast={ast}
      store={store}
      customizations={{
        components: {
          chart: MyRechartsRenderer,
        },
      }}
    />
  );
}

This pattern works for overriding any built-in component โ€” pass a custom React component under customizations.components.<type>.

Installation

# Core โ€” parse and run MDMA documents
npm install @mobile-reality/mdma-parser @mobile-reality/mdma-runtime

# React rendering
npm install @mobile-reality/mdma-renderer-react

# AI authoring โ€” system prompts for LLM-based generation
npm install @mobile-reality/mdma-prompt-pack

# Validation โ€” static analysis for MDMA documents
npm install @mobile-reality/mdma-validator

# CLI โ€” interactive prompt builder + document validation
npx @mobile-reality/mdma-cli

All packages are published under the @mobile-reality npm org.

Usage

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkGfm from 'remark-gfm';
import { remarkMdma } from '@mobile-reality/mdma-parser';
import { createDocumentStore } from '@mobile-reality/mdma-runtime';
import type { MdmaRoot } from '@mobile-reality/mdma-spec';

// 1. Parse markdown into AST
const processor = unified().use(remarkParse).use(remarkGfm).use(remarkMdma);
const tree = processor.parse(markdown);
const ast = (await processor.run(tree)) as MdmaRoot;

// 2. Create a reactive document store
const store = createDocumentStore(ast, {
  documentId: 'my-doc',
  sessionId: crypto.randomUUID(),
});

// 3. Subscribe to state changes
store.subscribe((state) => {
  console.log('Bindings:', state.bindings);
});

// 4. Dispatch user actions
store.dispatch({
  type: 'FIELD_CHANGED',
  componentId: 'intake-form',
  field: 'patient-name',
  value: 'Jane Doe',
});

In a Chat

import { buildSystemPrompt, getAuthorPromptVariant } from '@mobile-reality/mdma-prompt-pack';

// Pick the prompt variant tuned for your model (falls back to default if unknown)
const { prompt: authorPrompt } = getAuthorPromptVariant('google/gemini-2.5-pro');

// Optionally layer a custom prompt on top for domain-specific generation
const systemPrompt = buildSystemPrompt({
  authorPrompt,
  customPrompt: `You are a bug tracking assistant. When a user reports a bug,
always generate a single form component matching this exact structure:

\`\`\`mdma
type: form
id: bug-report
fields:
  - name: title
    type: text
    label: "Bug Title"
    required: true
  - name: severity
    type: select
    label: "Severity"
    options:
      - { label: Critical, value: critical }
      - { label: High, value: high }
      - { label: Medium, value: medium }
      - { label: Low, value: low }
  - name: steps
    type: textarea
    label: "Steps to Reproduce"
    required: true
  - name: expected
    type: textarea
    label: "Expected Behavior"
  - name: actual
    type: textarea
    label: "Actual Behavior"
onSubmit: submit-bug-report
\`\`\``,
});

// Send to any OpenAI-compatible API
const response = await fetch('https://api.openai.com/v1/chat/completions', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
  body: JSON.stringify({
    model: 'gemini-2.5-pro',
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: 'The login page crashes after entering my password.' },
    ],
  }),
});

// The LLM responds with regular markdown containing ```mdma blocks
// Parse it into an AST + store as shown above

React

import { MdmaDocument } from '@mobile-reality/mdma-renderer-react';
import '@mobile-reality/mdma-renderer-react/styles.css'; // default styles

function App({ ast, store }) {
  return <MdmaDocument ast={ast} store={store} />;
}

Note: The styles.css import provides default styling for all MDMA components (forms, tables, callouts, animations, etc.). It's optional โ€” you can write your own styles targeting the .mdma-* CSS classes instead.

Theming

Both renderers accept a theme prop on MdmaDocument, so theming is entirely opt-in โ€” omit it and you get the default light look. Pass a built-in palette, follow the OS preference, or hand over a full custom token object:

<MdmaDocument ast={ast} store={store} theme="dark" />   // built-in dark palette
<MdmaDocument ast={ast} store={store} theme="auto" />   // follows OS light/dark
<MdmaDocument ast={ast} store={store} theme={myTheme} /> // custom MdmaTheme tokens

The web renderers (renderer-react, renderer-vue) and the native one (renderer-react-native) share the same MdmaTheme token shape, so a theme object is portable between them. On the web, tokens are applied as --mdma-* CSS variables (still fully overridable in your own CSS); on native, renderers read them via useMdmaTheme(). See the Theming guide for the full token reference.

Packages

PackageDescription
@mobile-reality/mdma-specThe foundation of the MDMA ecosystem โ€” Zod schemas, TypeScript types, and AST definitions for all 10 component types. Every other package depends on spec for validation and type safety.
@mobile-reality/mdma-parserA remark plugin that transforms standard Markdown into an MDMA-extended AST. Extracts mdma code blocks, validates YAML against component schemas, and builds a binding dependency graph.
@mobile-reality/mdma-runtimeHeadless state management engine for MDMA documents โ€” like a mini state specialized for interactive documents. Manages reactive bindings, dispatches actions, enforces environment policies, and writes every event to a tamper-evident audit log with automatic PII redaction.
@mobile-reality/mdma-attachables-coreHandlers for 7 of the 10 component types โ€” the ones that manage state (form, button, tasklist, table, callout, approval-gate, webhook). Chart and thinking are display-only and rendered directly without state handlers.
@mobile-reality/mdma-renderer-reactReact rendering layer with components for all 10 MDMA types and hooks for state access. Provides MdmaDocument for full-document rendering and useComponentState/useBinding for fine-grained reactivity.
@mobile-reality/mdma-renderer-vueVue 3 rendering layer โ€” the same surface as the React renderer, in Vue idiom: MdmaDocument, MdmaBlock, and composables (useComponentState/useBinding) that return ComputedRefs. Ships the same styles.css, so a theme is portable between the two web renderers.
@mobile-reality/mdma-prompt-packSystem prompts that teach LLMs how to author valid MDMA documents. Ships model-specialised variants for OpenAI, Anthropic, Google, and xAI โ€” select one with getAuthorPromptVariant(modelId). Exports buildSystemPrompt() to combine the variant with optional custom instructions for domain-specific generation.
@mobile-reality/mdma-validatorStatic analysis engine with 17 lint rules covering YAML correctness, schema conformance, ID uniqueness, binding syntax, action references, PII sensitivity, expected component verification, and flow ordering. Includes 6 auto-fix strategies and fuzzy type/ID suggestions. Powers programmatic validation in CI pipelines and custom tooling.
@mobile-reality/mdma-cliInteractive CLI tool for creating custom MDMA prompts. Opens a local web app where you visually select components, configure fields, set domain rules and trigger conditions, then an LLM generates a tailored customPrompt for use with buildSystemPrompt(). Also includes a validate command for static document analysis.
@mobile-reality/mdma-mcpMCP (Model Context Protocol) server that exposes MDMA spec, prompts, and tooling to AI assistants. Tools: get-spec, get-prompt (with optional variantId for model-optimised prompts), list-prompt-variants, build-system-prompt, validate-prompt, list-packages. Works with Claude Desktop, VS Code, Cursor, and any MCP-compatible client.

Architecture

@mobile-reality/mdma-spec                  Format specification + Zod schemas
  โ”œโ”€โ”€ @mobile-reality/mdma-parser          Markdown โ†’ MDMA AST (remark plugin)
  โ”œโ”€โ”€ @mobile-reality/mdma-prompt-pack     AI authoring prompts
  โ”œโ”€โ”€ @mobile-reality/mdma-validator       Document validation
  โ””โ”€โ”€ @mobile-reality/mdma-runtime         State / events / policy engine
        โ””โ”€โ”€ @mobile-reality/mdma-attachables-core   Component handlers
              โ”œโ”€โ”€ @mobile-reality/mdma-renderer-react   React components
              โ””โ”€โ”€ @mobile-reality/mdma-renderer-vue     Vue 3 components
@mobile-reality/mdma-cli                   CLI prompt builder + validation
@mobile-reality/mdma-mcp                   MCP server for AI assistants

Getting Started

pnpm install
pnpm build
pnpm test

CLI

Interactive prompt builder for creating custom MDMA prompts.

# Run the prompt builder โ€” opens a web app in your browser
npx @mobile-reality/mdma-cli

# Validate MDMA documents
npx @mobile-reality/mdma-cli validate "docs/**/*.md"
npx @mobile-reality/mdma-cli validate "docs/**/*.md" --fix  # auto-fix issues
npx @mobile-reality/mdma-cli validate "docs/**/*.md" --json # JSON output

The prompt builder walks you through:

  1. Pick components โ€” select from the 10 MDMA types (form, table, approval-gate, etc.)
  2. Configure โ€” define fields, options, roles, sensitive flags, and business rules
  3. Set triggers โ€” specify when the AI should generate MDMA components (keywords, contextual conditions)
  4. Generate โ€” an LLM creates a tailored customPrompt based on your configuration
  5. Export โ€” copy the result and use it in your app:
import { buildSystemPrompt } from '@mobile-reality/mdma-prompt-pack';

const systemPrompt = buildSystemPrompt({
  customPrompt: '<paste generated prompt here>',
});

Validator

Static analysis engine for MDMA documents. Validates structure, catches common LLM mistakes, and auto-fixes what it can.

import { validate } from '@mobile-reality/mdma-validator';

const result = validate(markdown);
// result.ok        โ€” true if no unfixed errors
// result.issues    โ€” all issues found
// result.output    โ€” auto-fixed markdown
// result.fixCount  โ€” number of issues auto-fixed

Rules

Every rule can be individually disabled via the exclude option:

const result = validate(markdown, {
  exclude: ['thinking-block', 'placeholder-content'],
});
RuleSeverityAuto-fixDescription
yaml-correctnesserror--YAML parses successfully. Detects and auto-splits multi-component blocks, strips --- separators LLMs insert.
field-name-typoswarning--Common field name mistakes: roles -> allowedRoles, onClick -> onAction, submit -> onSubmit.
schema-conformanceerroryesComponent type exists and data conforms to its Zod schema. Suggests closest type via fuzzy matching (e.g. "frm" -> did you mean "form"?) and lists all valid types.
duplicate-idserroryesAll component IDs are unique. Auto-fix appends -1, -2 suffixes.
id-formatwarningyesIDs follow kebab-case (my-component-id). Auto-fix converts camelCase, snake_case, PascalCase and updates all references.
binding-syntaxerror/warningyes{{binding}} expressions are well-formed. Catches empty {{ }}, extra whitespace {{ path }}, and single-brace {path}.
form-submit-actionerror--Every type: form component declares a non-empty onSubmit action.
sensitive-flagswarningyesForm fields and table columns with PII-like names (email, phone, ssn, address, etc.) have sensitive: true. Supports custom PII patterns.
required-markersinfo--Suggests required: true for fields named name, email, title, summary.
thinking-blockwarning/info--If a thinking block is present, it should be the first component and only one should exist.
table-data-keyswarning--Data row keys match defined column keys. Flags extra keys and columns with no matching data.
select-optionswarning--type: select fields have options defined as [{label, value}] objects.
chart-validationwarning--Chart CSV data has headers + data rows. xAxis/yAxis reference actual CSV column headers.
placeholder-contentinfo--Catches TODO, TBD, FIXME, ..., lorem ipsum in content fields.
flow-orderingwarning--Forward-only action references (targets defined later in the document), no circular refs, and multi-step flows flagged to be split across messages.
single-interactive-componentwarning--At most one interactive component (form, button, webhook, approval-gate, tasklist) per message.
expected-componentserror--Verifies that components present in the message match their expected types, form fields, and table columns. Components not in the message are silently skipped โ€” useful for multi-turn flows where you pass all expected components upfront.

Auto-fix Pipeline

When autoFix: true (default), 6 fix strategies run in strict dependency order:

  1. thinking-block โ€” merge stray thinking blocks into one and move it to the top
  2. id-format โ€” normalize IDs to kebab-case, update all cross-references
  3. duplicate-ids โ€” deduplicate after normalization
  4. binding-syntax โ€” fix {x} -> {{x}}, strip whitespace
  5. sensitive-flags โ€” add sensitive: true to PII fields
  6. schema-conformance โ€” patch missing labels/headers/content, infer field types, wrap bare bindings, re-validate with Zod

Expected Components

When you need to guarantee that the LLM generates specific critical components for the user (e.g. a form with required fields, a table with specific columns), pass their expected shapes to the validator. The rule only validates components that are actually present in the current message โ€” components not found are silently skipped. This makes it safe to pass the full set of expected components across a multi-turn flow:

// Define all expected components once (e.g. from a blueprint or flow definition)
const expectedComponents = {
  'contact-form': {
    type: 'form',
    fields: ['email', 'phone', 'full-name'],
  },
  'approval-gate': { type: 'approval-gate' },
  'submit-btn': { type: 'button' },
};

// Pass the same set to every message โ€” the rule checks only what's present
const result = validate(message1, { expectedComponents });
// Message 1 contains contact-form โ†’ validates type + fields
// approval-gate and submit-btn not in this message โ†’ skipped

const result2 = validate(message2, { expectedComponents });
// Message 2 contains approval-gate โ†’ validates type
// contact-form and submit-btn not in this message โ†’ skipped

For each component found in the message, the rule checks:

  • Is the type correct?
  • Are all expected form fields present? (lists available fields on mismatch)
  • Are all expected table columns present? (lists available columns on mismatch)

LLM Error Recovery

The parser handles three common LLM mistakes automatically during block extraction:

  • Colon-space in values โ€” label: Step 1: Enter info auto-quoted to label: "Step 1: Enter info"
  • YAML --- separators โ€” stripped before parsing
  • Multiple components in one block โ€” split at each root-level type: line into separate blocks

MCP Server

MCP (Model Context Protocol) server that lets AI assistants understand and work with MDMA.

Setup

Add to your AI tool config (Claude Desktop, VS Code, Cursor, etc.):

{
  "mcpServers": {
    "mdma": {
      "command": "npx",
      "args": ["@mobile-reality/mdma-mcp"]
    }
  }
}

Tools

ToolDescription
get-specReturns the full MDMA specification: component types, JSON schemas, binding syntax, and authoring rules
get-promptReturns a named prompt (mdma-author, mdma-reviewer, or mdma-fixer). For mdma-author, accepts an optional variantId (e.g. google/gemini-2.5-pro) to return the model-optimised variant
list-prompt-variantsReturns all available MDMA_AUTHOR prompt variants (id, label, description) โ€” use the id with get-prompt to fetch the model-optimised prompt
build-system-promptGenerates a custom MDMA prompt from structured input (domain, components, fields, steps, business rules)
validate-promptValidates a custom prompt against MDMA conventions โ€” returns warnings, suggestions, and constraint reference
list-packagesReturns all MDMA packages with purpose, install command, and usage example
list-docsReturns the catalog of MDMA documentation files (path, title, description) available for fetching from the public GitHub repo
get-docFetches the latest version of an MDMA documentation file from raw.githubusercontent.com/MobileReality/mdma. Supports optional ref (branch/tag/SHA, defaults to main)

Example: Building a prompt with structured input

An AI agent calls build-system-prompt with:

{
  "domain": "HR onboarding",
  "components": ["form", "approval-gate", "webhook"],
  "fields": [
    { "name": "email", "type": "email", "sensitive": true, "required": true },
    { "name": "department", "type": "select", "options": ["Engineering", "Marketing"] }
  ],
  "steps": [
    { "label": "Registration", "description": "Employee fills in personal details" },
    { "label": "Approval", "description": "Manager reviews and approves" }
  ],
  "businessRules": "All PII fields must be marked sensitive."
}

The tool returns a structured custom prompt ready to use with buildSystemPrompt({ customPrompt }).

Testing locally

npx @modelcontextprotocol/inspector node packages/mcp/dist/bin/mdma-mcp.js

MCP vs No-MCP: Agent Implementation Comparison

We tested building the same MDMA chat app with two AI agents โ€” one with the MCP server enabled, one without. Here's what happened:

AspectWith MCPWithout MCP
Package discoveryAgent called list-packages โ€” got all 9 packages with install commands and usage in one stepAgent had to read README, explore repo, and piece together which packages exist
Spec knowledgeAgent called get-spec โ€” received all 10 component types with JSON schemas, binding syntax, and authoring rulesAgent had to read source files across multiple packages to understand component types
Prompt setupAgent called get-prompt("mdma-author") โ€” got the exact system prompt ready to useAgent had to find mdma-prompt-pack, understand buildSystemPrompt(), and figure out how to use it
Time to working appAgent knew the right packages, APIs, and patterns from the start โ€” fewer wrong turnsAgent spent significant time exploring, reading docs, and backtracking on wrong approaches
Code qualityFocused implementation โ€” agent used exactly the right APIs because MCP told it what existsMore verbose โ€” agent implemented some things manually that packages already provided

Key takeaway: The MCP server eliminated the discovery phase entirely. Instead of the agent reading source code to understand MDMA, it called 3 tools (list-packages โ†’ get-spec โ†’ get-prompt) and had complete, structured knowledge of the ecosystem within seconds.

Skills

Agent-authoring guidance packaged as a portable Agent Skill (compatible with Claude Code, the Agent SDK, and any harness that consumes SKILL.md).

SkillPathPurpose
mdma-integrationskills/mdma-integration/SKILL.mdTeaches agents how to integrate MDMA into an application โ€” package selection, parse โ†’ store โ†’ render wiring, LLM streaming (with the updateAst reparse pattern), custom components, prompt authoring & maintenance, CI validation, and MCP exposure.

The skill is intentionally portable: every code sample is inline and every reference uses @mobile-reality/mdma-* package names, so it works when dropped into a project that only installs the published packages. Drop the folder into .claude/skills/ (Claude Code), your Agent SDK skills directory, or any compatible location.

Paired with the MCP server, an agent gets both how to think about the integration (skill) and live access to spec, prompts, and docs (MCP tools) โ€” the skill tells it to call buildSystemPrompt / validate / updateAst, and the MCP tools give it the actual spec and docs to do so correctly.

Evals

LLM evaluation suite using promptfoo to verify MDMA generation quality.

# Run base eval suite (25 tests)
pnpm eval

# Run custom system prompt tests (10 tests)
pnpm eval:custom

# Run multi-turn conversation tests (25 turns across 11 conversations)
pnpm eval:conversation

# Run prompt builder tests (25 tests)
pnpm eval:prompt-builder

# Run all eval suites
pnpm eval:all

# View results in browser
pnpm eval:view

Key Features

  • Deterministic parsing โ€” Markdown + YAML, no runtime JS in documents
  • PII protection โ€” Automatic detection + redaction (hash, mask, omit)
  • Audit trail โ€” Append-only event log with tamper-evident hash chaining
  • Policy engine โ€” Allow/deny rules per action and environment
  • AI authoring โ€” System prompts for AI-assisted document creation

Initial Roadmap

v0.2 โ€” Developer Experience

  • More examples (14 real-world use cases)
  • CLI tool for prompt creation (MDMA flows)
  • Improved validator
  • Added MCP
  • Added Skills for Agentic usage
  • Improved error messages in parser
  • File upload field type for forms

v0.3 โ€” AI & Generation

  • Multi-model eval coverage (Claude, GPT, Gemini, Grok)
  • Prompt tuning toolkit โ€” test and compare custom prompts
  • Agent-friendly SDK โ€” let AI agent generate your MDMA
  • Validator tests & Fixer evals
  • Integrations
  • Webhook execution engine (real HTTP calls in production environments)

v1.0 โ€” Production Ready

  • Stable API with semantic versioning guarantees
  • E2E test suite for full document workflows
  • Performance benchmarks and optimization
  • Migration guides between versions
  • Blueprints promoted from experimental to stable

Future

  • Collaborative editing (multiplayer document state)
  • Custom component marketplace
  • Audit trail dashboard UI
  • HIPAA / SOC 2 compliance documentation

Tech Stack

TypeScript monorepo โ€” pnpm workspaces, Turborepo, Zod, React, Vitest, remark

Built by Mobile Reality

MDMA is built and maintained by Mobile Reality โ€” an AI automation agency specializing in AI agent development, custom software, and enterprise automation. We use MDMA in production across fintech and proptech projects.

Read more:

License

MIT


Made with โค๏ธ by Mobile Reality

Related MCP Servers

Moxie-Docs-MCPโ˜… Featured

MCP & Agent Skills for Automated Documentation, and codebase conventions + context

๐Ÿ’ป Developer Tools2 views
3KniGHtcZ/codebeamer-mcp

๐Ÿ“‡ โ˜๏ธ ๐ŸŽ ๐ŸชŸ ๐Ÿง - Codebeamer ALM integration for managing work items, trackers, and projects. Provides 17 tools for reading and writing items, associations, references, comments, and risk management data via Codebeamer REST API v3.

๐Ÿ’ป Developer Tools1 views
21st-dev/Magic-MCP

Create crafted UI components inspired by the best 21st.dev design engineers.

๐Ÿ’ป Developer Tools0 views
a-25/ios-mcp-code-quality-server

๐Ÿ“‡ ๐Ÿ  ๐ŸŽ - iOS code quality analysis and test automation server. Provides comprehensive Xcode test execution, SwiftLint integration, and detailed failure analysis. Operates in both CLI and MCP server modes for direct developer usage and AI assistant integration.

๐Ÿ’ป Developer Tools0 views

Engagement

Views
0
Installs
0
Upvotes
0

Views and upvotes are unique per visitor network (hashed IP). Installs count copy actions.

Status

Health: Not checked yet

We have not completed a health check for this listing yet.

No check timestamp yet.

Unclaimed listing (imported or pending owner verification). Claim it โ†’
โ˜… Spotlight Slot

Feature Your MCP Server

Get maximum visibility for your server across our directory, search results, and detail pages.

Spotlight Your Server

Own this project?

This directory is pre-filled from public sources. Claim via GitHub README, site badge, or DNS TXT to get the verified badge and attach your website.

Claim this listing

Promote this listing

Optional paid placement. Free listings stay free forever.

Share & Embed

Add our SVG badge (dark/light directory styles) or embeddable widget to your site.