An Obsidian plugin that adds document templates ("charts") to Obsidian Local REST API. It is an API extension: it does not run its own server, it registers extra REST routes and MCP tools on the host plugin via its public extension API.
A template is rendered deterministically from agent-supplied values that are first validated against a JSON Schema. This gives REST and MCP clients an API-level guarantee that generated documents match a declared structure — for example "one supporting section per thesis point" — instead of relying on the model to format things correctly.
- Obsidian Local REST API installed and enabled (it is the host that serves the REST/MCP endpoints).
- A version of the host that supports API extensions with MCP tools
(
getPublicApi(...).addMcpTool). The MCP tools require a reasonably recent host.
Note: If your host build already ships a built-in templates feature (its own
/templates/routes andtemplate_rendertool), do not run both at once — the host throws when an MCP tool name is registered twice. Use this extension with a host that does not have the built-in feature.
Cursor / MCP client ─┬─ REST ─┐
└─ MCP ──┤
▼
Obsidian Local REST API (host)
· authenticates requests
· runs the MCP server
· exposes getPublicApi()
▲
addRoute / addMcpTool
│
Local REST API Templates (this plugin)
· TemplateOperations (validate + render)
· reads/writes the vault via Obsidian App
▼
Vault: <templatesDir>/<name>/...
On load the plugin calls the host's getPublicApi(this.manifest) and registers
its routes and tools. It handles either load order (host before or after this
plugin) by also listening for the host's obsidian-local-rest-api:loaded event,
and it cleans up via api.unregister() on unload.
This is a normal Obsidian plugin. To install a build manually:
- Build it:
npm install npm run build - Copy
main.js,manifest.json, andstyles.cssinto a new folder in your vault:<your-vault>/.obsidian/plugins/obsidian-local-rest-api-templates/ - In Obsidian, enable Local REST API Templates under Settings → Community plugins (the host plugin must also be enabled).
| Setting | Default | Description |
|---|---|---|
| Templates folder | olrapi-templates |
Vault folder that holds your templates. |
Each template is a subfolder of the templates folder:
<templatesDir>/<name>/template.md # Markdown body (Mustache subset)
<templatesDir>/<name>/values.schema.json # JSON Schema for the input values
<templatesDir>/<name>/guidance.md # optional authoring guidance
A folder is only treated as a template if it contains both template.md and
values.schema.json. The body uses a small, safe Mustache subset:
{{ name }}/{{ a.b.c }}interpolation{{# section }} ... {{/ section }}iterate an array (or render once if truthy){{^ section }} ... {{/ section }}inverted (render when empty/falsy){{! comment }}comments{{ . }}the current item inside a section
There are no partials, helpers, eval, or prototype-chain lookups, and output is
not HTML-escaped (templates produce Markdown).
examples/templates/essay/ contains a ready-to-use template. Copy it into your
vault's templates folder:
cp -R examples/templates/essay "<your-vault>/olrapi-templates/essay"
It enforces a thesis-driven structure: a thesis overview, one section per
supporting point, and a closing summary (sections has minItems: 1, and each
section requires point, heading, and body).
All routes are registered on the host's authenticated router, so they require the same API key as the rest of the host's REST API.
| Method | Path | Description |
|---|---|---|
| GET | /templates/ |
List templates with optional descriptions. |
| GET | /templates/{name}/schema |
The template's JSON Schema. |
| GET | /templates/{name}/guidance |
The template's guidance Markdown (404 if none). |
| POST | /templates/{name}/render |
Validate values and render; optionally write to the vault. |
POST /templates/{name}/render accepts a JSON body
(Content-Type: application/json):
{
"values": { "...": "must satisfy values.schema.json" },
"path": "Notes/My Essay.md",
"overwrite": false
}- Omit
pathto get the rendered Markdown back in the response body. - With
path, the document is written into the vault (parent folders are created) and the response setsContent-Location. Writing fails with409if the file exists unlessoverwriteistrue. - Invalid
valuesreturn422with a list of schema violations; nothing is written. - Paths that are absolute or escape the vault return
400.
| Tool | Description |
|---|---|
template_list |
List templates with their description, JSON Schema, and guidance. Call this first. |
template_render |
Validate values against the template's schema and render; optionally write to the vault. |
Because the extension API does not expose MCP resources, template discovery is
provided by the template_list tool (the host's built-in feature uses an MCP
resource for this instead).
npm install
npm run lint # eslint, incl. eslint-plugin-obsidianmd
npm run typecheck # tsc --noEmit
npm test # unit + in-process integration tests (jest)
npm run build # bundle to main.js
npm run dev # watch build
CI (.github/workflows/test.yml) runs lint, typecheck, tests, and build on every
push. Tagged pushes trigger .github/workflows/release.yml, which builds,
attaches main.js/manifest.json/styles.css to a GitHub release, and attests
their build provenance.
The tests run without a live Obsidian instance: they exercise the renderer, the template operations against an in-memory vault, and the real routes/tools against a mock host API.
Issues and pull requests are welcome — see CONTRIBUTING.md. This is an API extension: it does not modify or fork the host plugin.