The Matra rich text editor's documentation as an MCP server: every extension, command and API.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent — or use 1-click editor setup below.
One-click editor setup isn’t available for this listing yet — we don’t have a confirmed install command, and we’d rather show nothing than point your editor at the wrong package or host. Follow the project’s own setup instructions, linked above.
A headless rich text editor framework with a first-class extension API.
this, no classes, no inheritance chainsSee DESIGN.md for the API rationale, CHANGELOG.md for what changed when, and CONTRIBUTING.md before a pull request.
| Package | Purpose | Licence |
|---|---|---|
@matrajs/core | Engine, document model, extension API, starter kit | MIT |
@matrajs/react | useEditor, useEditorState, useEditorFocus, EditorContent | MIT |
@matrajs/vue | useEditor, useEditorState, useEditorFocus, EditorContent | MIT |
@matrajs/svelte | matra — a use: action, the editor, and a state store | MIT |
@matrajs/solid | createMatra — the editor, a mount ref, and a state signal | MIT |
@matrajs/ai | Streaming edits that survive concurrent typing | Commercial |
@matrajs/collab | Authority, step rebasing, remote cursors | Commercial |
@matrajs/versions | Snapshots, a real diff between them, restore as one undo step | Commercial |
Matra is মাত্রা — the horizontal line that runs across the top of Bengali
script and holds a word together. Packages live under the @matrajs scope,
matching matrajs.com.
Installing a binding installs the engine with it. For a React application
pnpm add @matrajs/react is the entire install: one package, and no
third-party dependency arrives behind it.
Every command comes from the array you passed. Nothing else is on editor.commands,
and calling something that is not there is a compile error.
Eight packages, one version number, released together. Every other package
depends on @matrajs/core and on nothing else, so installing a binding
installs the whole editor — there is no second package to remember, no
@matrajs/pm to keep in step, and no peer range to resolve by hand.
@matrajs/core — MITThe engine, and the only package that is not optional. The document model, transforms, position mapping, editor state and the editable view are written here, with zero runtime dependencies.
Entry points
| Export | What it is |
|---|---|
createEditor(options) | Builds an editor. The extensions array decides everything else about it. |
buildSchema(extensions) | The schema alone, for validating a document with no view and no DOM. |
pos(…), range(…) | Constructors for the two position types. |
starterKit | Seventeen extensions in one array — document, paragraph, text, heading, blockquote, code block, bullet/ordered/list item, horizontal rule, hard break, bold, italic, strike, code, link, history. |
| 79 named extensions | Every entry in Extensions, each importable on its own. |
| Helpers | tableOfContents(doc), assignIds(doc), commentRanges(doc), activeSuggestion(editor), searchEmoji(query), youtubeId(url), normalizeUrl(text), fieldsIn(doc), fillFieldsIn(doc, values), hashtagsIn(doc), parseDelimited(text), dictationSupported() — plain functions, not extensions. |
toMarkdown, fromMarkdown | Pure string work, so they run in Node, in a worker and at the edge. |
…CSS helpers | placeholderCSS, commentCSS, taskListCSS, dragHandleCSS, suggestionCSS, searchCSS, lockedCSS, fieldsCSS, columnsCSS, footnotesCSS and the rest — stylesheets to paste into an app rather than a stylesheet to import. |
EditorOptions
| Field | Type | Notes |
|---|---|---|
extensions | readonly AnyDef[] | Declare it as const. The tuple is what makes the commands infer. |
content | DocNode | string | Document JSON, or HTML to parse. |
editable | boolean | |
autofocus | boolean | 'start' | 'end' | |
element | HTMLElement | Mount as soon as the editor exists, instead of calling mount yourself. |
The editor
| Member | Signature | |
|---|---|---|
commands | CommandsOf<T> & CoreCommands | Only what the extensions you passed provide. Anything else is a compile error. |
can | same shape | Asks instead of does, so a button can be disabled rather than dead. |
batch(run) | => boolean | Several commands, one undo step. Rolls back entirely if any returns false. |
isActive(name, attrs?) | => boolean | Marks first, then nodes · isActive('heading', { level: 2 }) reads naturally. |
getJSON() | => DocNode | |
getHTML() | => string | Answers without a DOM. |
getText() | => string | |
setContent(content) | => void | |
selection | Selection | |
editable / setEditable(v) | ||
on(event, fn) | => () => void | change, focus, blur, selectionChange. Returns its own unsubscribe. |
extensionState<S>(name) | => S | undefined | How a toolbar reads a character count or a collab version without a global. |
mount(el) / destroy() | ||
unsafe | { view, state, schema } | Excluded from semver. Needing it means the public API has a gap — open an issue. |
Core commands, present whatever you pass: select, insert, replace,
remove, moveBlock, focus. insert and replace accept blocks at a
caret inside a paragraph and split the paragraph around them, which is what
a rule or a table asked for at the caret means.
What an extension may declare, beyond commands, keys and input rules:
| Field | On | What it does |
|---|---|---|
attributes | extension | Add attributes to nodes and marks defined elsewhere · [{ types: ['paragraph', 'heading'], attrs: { indent: { default: 0, render, parse } } }]. How textAlign, indent and uniqueId work without the paragraph knowing about them. |
handlePaste(ctx, { html, text, files }) | extension | Claim a paste before the editor parses it. Return true to keep it. |
handleDrop(ctx, { html, text, files, pos }) | extension | The same for something dropped from outside. Block drags inside the editor never reach it. |
filterChange(ctx) | extension | Veto a change before it lands. Return false and the document, the selection and the undo history stay as they were · how locked() refuses a keystroke, a paste and a drag alike. editor.can asks it too. |
nodeViews | extension | Render nodes defined elsewhere with your own DOM · { image: ({ node, getPos, editor }) => … }. How imageResize() puts a handle on the stock image. |
decorations(ctx) | extension | Draw over the document · highlights, widgets, a class on the current block. |
state | extension | Reduced on every transaction · read with editor.extensionState(name). |
code | node | Whitespace inside is literal, so a pasted function keeps its line breaks. |
listItem | node | Enter splits, Tab nests, Backspace at the start lifts. |
marks | node | Which marks the text may carry · '' for none. |
nodeView | node | Render with your own DOM and keep it across edits. |
@matrajs/react — MIT| Export | Signature |
|---|---|
useEditor(options) | Editor<T> — created lazily on first render, destroyed on unmount. |
useEditorState(editor, select) | S — a useSyncExternalStore subscription to change and selectionChange. |
useEditorFocus(editor) | boolean |
EditorContent | { editor } plus every div attribute. |
Options are read once. Changing them later does not recreate the editor,
because tearing down a live document on a prop change loses the user's work —
use the commands instead. The mount is guarded on unsafe.view, so StrictMode's
double invoke cannot leave two views fighting over one element.
@matrajs/vue — MITThe same four names as React, returning refs.
| Export | Signature |
|---|---|
useEditor(options) | Editor<T>, markRawped · works in a component or a bare effect scope. |
useEditorState(editor, select) | Readonly<Ref<S>> |
useEditorFocus(editor) | Readonly<Ref<boolean>> |
EditorContent | Component with an editor prop. |
The mount is guarded, so a <KeepAlive> remount does not attach a second view.
@matrajs/svelte — MITSvelte already has the right shape — an action runs when the element exists and is told when it goes away — so the binding is thin on purpose. Written with stores rather than runes, so it behaves identically on Svelte 4 and 5.
No reviews yet — be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/matra)<a href="https://allmcps.com/mcp/matra"><img src="https://allmcps.com/api/badge/matra?style=directory" alt="Matra on AllMCPs" /></a>