JavaScript client
The datanotes package exports a client of the HTTP API with no dependencies. It runs in Node,
in browsers and in Obsidian. The MCP server is built on it.
npm install datanotesimport { DatanotesClient } from "datanotes/client";
const db = new DatanotesClient({ url: "http://127.0.0.1:27150", token: process.env.DATANOTES_TOKEN, actor: { harness: "my-script" }, // recorded with every write});
const books = await db.call("select_rows", { table: "book", order_by: "-pages" });if (books.ok) console.log(books.value.rows);
const r = await db.call("insert_row", { table: "book", values: { title: "Dune", pages: 412 } });if (!r.ok) console.log(r.value); // why it was refused; nothing was writtencall(name, args, actor?)runs an operation by name with the same arguments agents use, and answers{ ok, value }. A refused write isok: falsewith a readable reason.invoke(name, args, actor?)runs an operation, or else the registered app tool of that name, and answers{ ok, value, servedBy }.post(route, body, actor?)sendsPOST /datanotes<route>(e.g.post("/apps/tools/")) and throws on an error status.ping()tells whether the engine answers.- Errors that are not answers throw a
DatanotesErrorwithkind:unreachable(the engine did not answer),auth(the token was refused) orhttp(an error status frompost, withstatus).
The catalogue itself is exported too: OPERATIONS (name, description, input schema) and
operationRequest(name, args) (the HTTP request behind an operation).
Find the local engine
Section titled “Find the local engine”datanotes/local (Node only) finds the engine running on a vault of this machine:
import { localEngine } from "datanotes/local";
const engine = localEngine("/path/to/vault");// { url, token, lock } while an engine runs on the vault, else null;// throws when the engine holding the vault runs on another machineIn Obsidian
Section titled “In Obsidian”Pass Obsidian’s requestUrl as the transport, so requests are not subject to CORS:
const db = new DatanotesClient({ url, token, transport: async (req) => { const r = await requestUrl({ ...req, throw: false }); return { status: r.status, text: r.text }; },});