How to use md-graph as a context layer for your application or agent. Self-sufficient: no source access needed.
A hosted graph of markdown notes. Each node is a note (or a folder — same thing; folders are nodes with children). Nodes live in a tree via named edges; notes can also link to each other with typed, reasoned references; and every node can carry facets — namespaced JSON documents for structured app data that never touches the markdown.
md-graph speaks Connect protocol: plain HTTP POST + JSON.
POST <base-url>/mdgraph.v1.NodeService/<Method>
Authorization: Bearer <token>
Content-Type: application/json
Errors are JSON {"code": "...", "message": "..."} with matching HTTP
status (not_found, permission_denied, already_exists,
aborted = revision conflict, invalid_argument).
| Call | Body | Returns |
|---|---|---|
| NodeService/Resolve | {"path": "notes/2026-07-05.md"} | node (id, headRevisionId) |
| NodeService/Get | {"nodeId": "..."} | node + body (base64) |
| NodeService/ListChildren | {"nodeId": "..."} | children with names |
| NodeService/Create | {"parentId": "...", "name": "x.md", "bodyKind": "BODY_KIND_MARKDOWN", "body": "<base64>"} | new node |
| NodeService/PutRevision | {"nodeId": "...", "expectedHeadId": "...", "bodyKind": "BODY_KIND_MARKDOWN", "body": "<base64>"} | new revision |
| EdgeService/Link | {"srcId": "...", "dstId": "...", "kind": "EDGE_KIND_REF", "rel": "relevant-to", "reason": "why"} | edge |
| EdgeService/Refs | {"nodeId": "..."} | edges touching the node |
| FacetService/GetFacet / SetFacet | {"subjectKind": "SUBJECT_KIND_NODE", "subjectId": "...", "namespace": "myapp.state", "data": "<base64 JSON>"} | facet |
body and facet data are base64 in JSON (proto bytes). Paths are
always relative to your token's root — nothing outside it can even
be named.
Worked example — read a note, update it safely:
H='-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"'
# 1. resolve → node id + current head (for conflict-safe writes)
curl -s $BASE/mdgraph.v1.NodeService/Resolve $H -d '{"path":"context.md"}'
# → {"node":{"id":"…","headRevisionId":"…"}}
# 2. compare-and-swap write: expectedHeadId = the head you read
curl -s $BASE/mdgraph.v1.NodeService/PutRevision $H \
-d '{"nodeId":"…","expectedHeadId":"…","bodyKind":"BODY_KIND_MARKDOWN","body":"'$(printf '# Context\n' | base64)'"}'
# → `aborted` means someone wrote between your read and write:
# re-read, merge YOUR way, retry. The server never merges.
Agents can skip raw HTTP entirely: the mdg client's MCP mode
(mdg mcp) exposes the same operations as tools with the token in env.
headRevisionId → PutRevision with
expectedHeadId → on aborted, re-read and retry (bounded).myapp.*), whole-document
replace, keep each document small (KBs).[[wikilinks]] — the server indexes them into a link graph.Link with a rel and reason
when your agent concludes two notes are related. These survive
rewrites; wikilinks in prose don't./, max 255 bytes, unique within a folder; end notes
with .md.BODY_KIND_BINARY + mediaType) but keep
originals in your own storage — this is a context layer, not a CDN.recursive
deliberately.| Code | Meaning | Client behavior |
|---|---|---|
| aborted | CAS conflict | re-read, merge, retry ≤3 |
| not_found | outside scope / gone / bad path | treat as absent |
| already_exists | name collision | resolve + update instead |
| unauthenticated | bad/revoked token | halt, surface to a human |
| unavailable / 5xx | cold start or transient | backoff retry (1s, 5s, 25s) |
The service scales to zero; the first call after idle takes ~1–2s.
Copyright © 2026 Bejike Software, LLC