From 2aa78aad5415ddaad3ccbdfbb80b7a600aba2e2d Mon Sep 17 00:00:00 2001 From: callumalpass Date: Sun, 4 Oct 2026 12:28:45 +1100 Subject: [PATCH] Publish Editor and MCP guides, generate the MCP tool reference, and describe account email --- .github/workflows/ci.yml | 7 + .github/workflows/deploy.yml | 7 + .github/workflows/update-connect-release.yml | 7 + .gitignore | 1 + package.json | 3 +- scripts/sync-mcp-tools.mjs | 83 +++++++++ src/data/docs-sections.ts | 63 ++++++- src/pages/apps/editor/index.astro | 99 +++++++++++ src/pages/apps/editor/links/index.astro | 83 +++++++++ src/pages/apps/editor/notes/index.astro | 137 +++++++++++++++ src/pages/apps/editor/sharing/index.astro | 87 ++++++++++ src/pages/apps/editor/shortcuts/index.astro | 86 +++++++++ src/pages/apps/editor/types/index.astro | 123 +++++++++++++ src/pages/apps/index.astro | 5 +- src/pages/apps/mcp/collections/index.astro | 115 ++++++++++++ src/pages/apps/mcp/data-handling/index.astro | 81 +++++++++ src/pages/apps/mcp/index.astro | 117 +++++++++++++ src/pages/apps/mcp/tools/index.astro | 82 +++++++++ .../apps/mcp/troubleshooting/index.astro | 121 +++++++++++++ .../apps/mcp/working-with-records/index.astro | 164 ++++++++++++++++++ src/pages/privacy/index.astro | 13 ++ 21 files changed, 1480 insertions(+), 4 deletions(-) create mode 100644 scripts/sync-mcp-tools.mjs create mode 100644 src/pages/apps/editor/index.astro create mode 100644 src/pages/apps/editor/links/index.astro create mode 100644 src/pages/apps/editor/notes/index.astro create mode 100644 src/pages/apps/editor/sharing/index.astro create mode 100644 src/pages/apps/editor/shortcuts/index.astro create mode 100644 src/pages/apps/editor/types/index.astro create mode 100644 src/pages/apps/mcp/collections/index.astro create mode 100644 src/pages/apps/mcp/data-handling/index.astro create mode 100644 src/pages/apps/mcp/index.astro create mode 100644 src/pages/apps/mcp/tools/index.astro create mode 100644 src/pages/apps/mcp/troubleshooting/index.astro create mode 100644 src/pages/apps/mcp/working-with-records/index.astro diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4f64c3..d11ce5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,6 +86,13 @@ jobs: working-directory: .sources/mdbase-spec/site run: npm ci && npm run build + - name: Build the MCP server for the tool reference + working-directory: .sources/mdbase-connect + run: | + pnpm_version="$(jq -r '.packageManager | sub("^pnpm@"; "")' package.json)" + npx --yes "pnpm@$pnpm_version" install --frozen-lockfile --filter "@mdbase/connect-mcp..." + npx --yes "pnpm@$pnpm_version" --filter "@mdbase/connect-mcp..." build + - name: Synchronize schemas, contracts, and conformance claims run: pnpm sync:sources env: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 203084c..5e378ad 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -93,6 +93,13 @@ jobs: working-directory: .sources/mdbase-spec/site run: npm ci && npm run build + - name: Build the MCP server for the tool reference + working-directory: .sources/mdbase-connect + run: | + pnpm_version="$(jq -r '.packageManager | sub("^pnpm@"; "")' package.json)" + npx --yes "pnpm@$pnpm_version" install --frozen-lockfile --filter "@mdbase/connect-mcp..." + npx --yes "pnpm@$pnpm_version" --filter "@mdbase/connect-mcp..." build + - name: Synchronize schemas, contracts, and conformance claims run: pnpm sync:sources env: diff --git a/.github/workflows/update-connect-release.yml b/.github/workflows/update-connect-release.yml index fd7b7b2..11a8273 100644 --- a/.github/workflows/update-connect-release.yml +++ b/.github/workflows/update-connect-release.yml @@ -127,6 +127,13 @@ jobs: working-directory: .sources/mdbase-spec/site run: npm ci && npm run build + - name: Build the MCP server for the tool reference + working-directory: .sources/mdbase-connect + run: | + pnpm_version="$(jq -r '.packageManager | sub("^pnpm@"; "")' package.json)" + npx --yes "pnpm@$pnpm_version" install --frozen-lockfile --filter "@mdbase/connect-mcp..." + npx --yes "pnpm@$pnpm_version" --filter "@mdbase/connect-mcp..." build + - name: Synchronize schemas, contracts, and conformance claims run: pnpm sync:sources env: diff --git a/.gitignore b/.gitignore index 9472de1..6f518ec 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ dist/ /public/theme-bootstrap.js /src/data/contracts.json /src/data/conformance.json +/src/data/mcp-tools.json diff --git a/package.json b/package.json index 3822541..c9ddb19 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "deploy:dev": "node scripts/deploy-pages-dev.mjs", "check": "astro check", "preview": "astro preview", - "sync:sources": "node scripts/sync-sources.mjs && node scripts/sync-contracts.mjs", + "sync:sources": "node scripts/sync-sources.mjs && node scripts/sync-contracts.mjs && node scripts/sync-mcp-tools.mjs", + "sync:mcp-tools": "node scripts/sync-mcp-tools.mjs", "sync:contracts": "node scripts/sync-contracts.mjs", "import:spec": "node scripts/import-spec.mjs", "check:links": "node scripts/check-links.mjs", diff --git a/scripts/sync-mcp-tools.mjs b/scripts/sync-mcp-tools.mjs new file mode 100644 index 0000000..169fb3f --- /dev/null +++ b/scripts/sync-mcp-tools.mjs @@ -0,0 +1,83 @@ +import { existsSync, statSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +// The MCP tool reference is read from the gateway's own tool registrations +// through an in-memory MCP client, so the published names, descriptions, +// annotations and input schemas are exactly what an MCP host receives. + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const connectDir = resolve(process.env.MDBASE_CONNECT_DIR ?? join(root, "..", "mdbase-connect")); +const mcpDir = join(connectDir, "services", "mcp"); +const built = join(mcpDir, "dist", "mcp.js"); +const source = join(mcpDir, "src", "mcp.ts"); + +if (!existsSync(built)) { + throw new Error(`Missing ${built}. Run pnpm --filter @mdbase/connect-mcp build in mdbase-connect.`); +} +if (statSync(source).mtimeMs > statSync(built).mtimeMs) { + throw new Error(`${built} is older than ${source}. Rebuild @mdbase/connect-mcp first.`); +} + +const sdk = join(mcpDir, "node_modules", "@modelcontextprotocol", "sdk", "dist", "esm"); +const { createMcpServer } = await import(pathToFileURL(built).href); +const { Client } = await import(pathToFileURL(join(sdk, "client", "index.js")).href); +const { InMemoryTransport } = await import(pathToFileURL(join(sdk, "inMemory.js")).href); + +async function listTools(scopes) { + // Listing tools never calls the gateway or OAuth service. + const server = createMcpServer({ connectionSetId: "reference", scopes }, {}, {}); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + const client = new Client({ name: "mdbase.dev-reference", version: "0" }); + await server.connect(serverTransport); + await client.connect(clientTransport); + const { tools } = await client.listTools(); + const version = client.getServerVersion()?.version; + await client.close(); + return { tools, version }; +} + +const read = await listTools(["mdbase:read"]); +const all = await listTools(["mdbase:read", "mdbase:write"]); +const readNames = new Set(read.tools.map((tool) => tool.name)); + +const tools = all.tools.map((tool) => ({ + name: tool.name, + title: tool.title ?? tool.name, + description: tool.description ?? "", + access: readNames.has(tool.name) ? "read" : "write", + annotations: tool.annotations ?? {}, + inputs: Object.entries(tool.inputSchema?.properties ?? {}).map(([name, schema]) => ({ + name, + required: (tool.inputSchema.required ?? []).includes(name), + type: describeType(schema), + description: schema.description ?? "" + })) +})); + +const output = { + generated_from: "mdbase-connect/services/mcp/src/mcp.ts", + server_version: all.version, + tools +}; +writeFileSync(join(root, "src", "data", "mcp-tools.json"), `${JSON.stringify(output, null, 2)}\n`); +console.log(`Wrote ${tools.length} MCP tools from mdbase MCP ${all.version}`); + +function describeType(schema) { + if (!schema || Object.keys(schema).length === 0) return "any"; + if (schema.const !== undefined) return JSON.stringify(schema.const); + if (schema.enum) return schema.enum.map((value) => JSON.stringify(value)).join(" | "); + if (schema.format === "uuid") return "UUID"; + if (schema.type === "array") return `${describeType(schema.items)}[]`; + if (schema.type === "integer") { + const bounds = [ + schema.minimum !== undefined ? `≥ ${schema.minimum}` : undefined, + schema.maximum !== undefined && schema.maximum < Number.MAX_SAFE_INTEGER + ? `≤ ${schema.maximum}` + : undefined + ].filter(Boolean); + return bounds.length > 0 ? `integer (${bounds.join(", ")})` : "integer"; + } + if (schema.type === "object") return "object"; + return schema.type ?? "any"; +} diff --git a/src/data/docs-sections.ts b/src/data/docs-sections.ts index 432a38c..1347542 100644 --- a/src/data/docs-sections.ts +++ b/src/data/docs-sections.ts @@ -1,6 +1,7 @@ import release from "./connect-release.json"; +import mcpTools from "./mcp-tools.json"; -export type DocsSectionId = "sdk" | "reader" | "writer"; +export type DocsSectionId = "sdk" | "mcp" | "editor" | "reader" | "writer"; type DocLink = { href: string; label: string; key: string }; type DocsSection = { @@ -51,6 +52,66 @@ export const docsSections: Record = { } ] }, + mcp: { + label: "mdbase MCP", + navLabel: "mdbase MCP documentation", + headerCurrent: "apps", + sourcePath: "src/pages/apps/mcp", + meta: { label: "Server", value: mcpTools.server_version }, + groups: [ + { + label: "Start", + docs: [ + { href: "/apps/mcp/", label: "Set up mdbase MCP", key: "overview" }, + { href: "/apps/mcp/collections/", label: "Collections and access", key: "collections" } + ] + }, + { + label: "Use", + docs: [ + { href: "/apps/mcp/working-with-records/", label: "Working with records", key: "records" }, + { href: "/apps/mcp/troubleshooting/", label: "Troubleshooting", key: "troubleshooting" } + ] + }, + { + label: "Reference", + docs: [ + { href: "/apps/mcp/tools/", label: "Tool reference", key: "tools" }, + { href: "/apps/mcp/data-handling/", label: "Data handling", key: "data" } + ] + } + ] + }, + editor: { + label: "mdbase Editor", + navLabel: "mdbase Editor documentation", + headerCurrent: "apps", + sourcePath: "src/pages/apps/editor", + meta: { label: "Web", value: "editor.mdbase.dev" }, + groups: [ + { + label: "Start", + docs: [ + { href: "/apps/editor/", label: "Get started", key: "overview" } + ] + }, + { + label: "Use", + docs: [ + { href: "/apps/editor/notes/", label: "Writing notes", key: "notes" }, + { href: "/apps/editor/links/", label: "Links, embeds and files", key: "links" }, + { href: "/apps/editor/types/", label: "Types", key: "types" }, + { href: "/apps/editor/sharing/", label: "Sharing a collection", key: "sharing" } + ] + }, + { + label: "Reference", + docs: [ + { href: "/apps/editor/shortcuts/", label: "Shortcuts and settings", key: "shortcuts" } + ] + } + ] + }, reader: { label: "mdbase Reader", navLabel: "mdbase Reader documentation", diff --git a/src/pages/apps/editor/index.astro b/src/pages/apps/editor/index.astro new file mode 100644 index 0000000..a053917 --- /dev/null +++ b/src/pages/apps/editor/index.astro @@ -0,0 +1,99 @@ +--- +import DocsLayout from "../../../components/DocsLayout.astro"; +--- + + +

What it is

+

+ mdbase Editor opens one mdbase collection and shows every record as a note. + It edits the Markdown files in place. Paths, frontmatter and type + definitions stay as ordinary files that other tools, such as a text editor, + Obsidian or an AI client, can keep using. +

+

+ It works with collections hosted by mdbase Connect and with collections + that stay on your computer and are served by the{" "} + Connector. +

+ +

Open a collection

+
    +
  1. Go to editor.mdbase.dev.
  2. +
  3. + Sign in to mdbase Connect. If you do not have an account,{" "} + sign up first. +
  4. +
  5. + Choose a collection. The list includes collections hosted by mdbase and + collections on your connected computers. +
  6. +
  7. + Approve the Editor's access to that one collection. Reading is + required. Creating, editing and deleting notes, managing types and + adding files are optional, and you can turn each one off. The Editor is + read-only for anything you do not approve. +
  8. +
+

+ The Editor opens mdbase 0.3 collections. For an older collection, upgrade a + copy with mdbase, check the copy, and then open it. Your original files can + stay untouched while you check the result. +

+ +

Find your way around

+ + + + + + + + + +
AreaWhat it holds
Collection railSwitches between All notes, Types and Settings, filters notes by folder, tag or type, shows the connection status and opens the Connect workspace.
Note listThe notes, and attached files, in the current filter. Sort by modified date, title or path from view options.
EditorThe note's Markdown body, with the title, properties and backlinks around it.
+

+ Press Ctrl P (⌘ P on a Mac) + to open any note by name, and ? to see the main shortcuts. On a + phone, each level of navigation is a separate screen. +

+ +

Connection status

+

+ The rail shows whether the collection is connected or reconnecting. A + collection on your computer can only be read and saved while the Connector + on that computer is running and online. When you are on that computer, + Use this computer in the rail, or{" "} + Allow local access under Settings → Connection, lets the + browser reach the Connector directly. +

+ +

Switch collections

+

+ Open the collection switcher from the rail. It lists collections you + opened before in this browser, and Connect another collection{" "} + starts a new approval. Forget from this browser in + Settings removes a collection from the Editor without changing its files. +

+ +

The Connect workspace

+

+ editor.mdbase.dev/connect{" "} + is where you manage your mdbase Connect account: collections, hosted + storage, sharing, connected applications, computers, sign-in methods and + browser sessions. It uses your account session, not a collection grant, so + it can list your collections but cannot read their contents. +

+
diff --git a/src/pages/apps/editor/links/index.astro b/src/pages/apps/editor/links/index.astro new file mode 100644 index 0000000..2626207 --- /dev/null +++ b/src/pages/apps/editor/links/index.astro @@ -0,0 +1,83 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +import CodeBlock from "../../../../components/CodeBlock.astro"; + +const links = `[[projects/alpha]] +[[projects/alpha|Project Alpha]] +[[projects/alpha#Goals]] +[[projects/alpha#^decision-1]]`; + +const embeds = `![[meeting-notes#Decisions]] +![[Attachments/diagram.png]] +![[Attachments/contract.pdf]]`; +--- + + + +

+ Type [[ and start typing a title or path. The Editor suggests + notes and files from the collection and completes the link: +

+ +

+ After a note name, type # to link to one of its headings, or{" "} + #^ to link to a block. Links are stored as ordinary Markdown + wikilinks, so other mdbase tools and Obsidian read them the same way. + Links that do not resolve to a note are marked as you write. +

+ +

Link with @

+

+ Typing @ at the start of a line, after a space or after an opening bracket opens the same suggestions and inserts a{" "} + [[wikilink]]. To limit suggestions to one type, type{" "} + @/, choose the type, and continue typing. For example,{" "} + @/person/sam suggests only records of the{" "} + person type that match "sam". +

+ +

Embed a note or file

+

+ Add ! before a link to show its content inside the current note. + You can embed a whole note, a section or block of it (#^id), or a file: +

+ +

+ The embedded content is read from the other file each time, so it stays up + to date. The Editor tells you when an embed points to a missing note or + heading, matches more than one note, or would include itself. +

+ + +

+ Backlinks lists every note that links to the one you are + reading. The button in the note header shows how many there are. +

+ +

Attach files

+

+ Choose Attach file… from the note's action menu. Each file + is uploaded to an Attachments folder next to the note, and an + embed or link to each file is added to the note. You can choose several + files at once. An existing file with the same name is never replaced. The + new file gets a numbered name instead. Images, PDFs, audio, video and text + files preview in the Editor. Other files show their name and path and are + stored as they are, for other tools to open. +

+

+ If the Editor's approval does not include file access, the menu shows{" "} + Request attachment access instead, which asks you to + approve it in Connect. +

+
diff --git a/src/pages/apps/editor/notes/index.astro b/src/pages/apps/editor/notes/index.astro new file mode 100644 index 0000000..b138b27 --- /dev/null +++ b/src/pages/apps/editor/notes/index.astro @@ -0,0 +1,137 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

Create a note

+

+ Choose New note or press Ctrl Shift{" "} + N. A note is not written to the collection until you create it, + so you can fill in everything first: +

+
    +
  • + Type. Pick one of the collection's types, or{" "} + General note for a note without a type. +
  • +
  • + Required properties. The fields the type requires are + shown up front. Nested objects and lists follow the type's schema. +
  • +
  • + Path. The Editor suggests where the file will live. + Edit it to choose another folder or file name. A new folder appears once + its first note is created. +
  • +
+

+ Press Ctrl Enter to create the note. +

+ +

Write

+

+ The body is plain Markdown. Changes save automatically. Type{" "} + / at the start of a line for Markdown commands such as + headings, lists, tasks, quotes, code blocks, tables and links. +

+

+ Ctrl B and Ctrl I set bold and + italic, Ctrl Shift C sets inline code,{" "} + Ctrl K adds a link, and pasting a URL over + selected text turns it into a link. Tab and{" "} + Shift Tab indent and outdent list items. +

+

+ Quiet Markdown, on by default, softens Markdown punctuation + away from the line you are editing and makes task checkboxes clickable. + Vim key bindings can be turned on in Settings. See{" "} + Shortcuts and settings. +

+ +

Properties

+

+ Open Note properties to see and edit frontmatter. It has + three views: +

+ + + + + + + + + +
ViewShows
FieldsStructured inputs based on the note's types, including dates, links, lists and nested objects.
JSONThe frontmatter stored in the file, as JSON.
SourceThe exact Markdown file, including YAML frontmatter and body.
+ +

Find notes

+
    +
  • + Quick open (Ctrl P) searches + titles, paths, properties and text. Start with > to search + actions instead. +
  • +
  • + Folders, Tags and By type in the collection rail filter the note list. + Its view options sort by modified date, title or path. +
  • +
  • + Alt J and Alt K move to the + next and previous note. Alt ← and{" "} + Alt → go back and forward through notes you + opened. +
  • +
  • Ctrl F finds text within the open note.
  • +
+ +

Rename and move

+

+ Click the path in the note header to rename or move the Markdown file; the + new path must end in .md. If other notes link to it, the + Editor asks whether to Rename and update links, which + rewrites those links, or Rename only. Otherwise it renames + the file and updates links straight away. +

+ +

Check a note

+

+ Check note, in the note's action menu, validates the note + against its types and reports any fields that do not fit. Links that do not + resolve are marked in the editor as you write. +

+ +

Edits made elsewhere

+

+ Every save checks that the file has not changed since the Editor read it. + If another app, a text editor or another person changed the note, the + Editor does not overwrite it. It shows This note changed elsewhere{" "} + and lets you compare the title and body before choosing{" "} + Keep my edits or Use latest. +

+

+ Edits that were not saved, for example because the browser closed, stay in + this browser for up to seven days. Reopening the note offers{" "} + Restore unsaved edits or Discard recovered edits. +

+ +

Delete a note

+

+ Delete note is in the note's action menu. It asks for + confirmation, then removes the Markdown file from the collection. +

+
diff --git a/src/pages/apps/editor/sharing/index.astro b/src/pages/apps/editor/sharing/index.astro new file mode 100644 index 0000000..ce91234 --- /dev/null +++ b/src/pages/apps/editor/sharing/index.astro @@ -0,0 +1,87 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

Which collections can be shared

+

+ Sharing is for collections hosted by mdbase Connect. A collection that + stays on your computer is not shared this way. Sharing is managed in the + Connect workspace at{" "} + editor.mdbase.dev/connect. + Open the collection and find People & sharing. Only + the collection's owner sees it. +

+ +

Roles

+ + + + + + + + + +
RoleCan
OwnerEverything, including inviting and removing people.
EditorEdit notes, manage types, rename the collection, and connect apps.
ViewerRead the collection and connect read-only apps or synced folders.
+

+ A viewer who opens the collection in mdbase Editor sees it read-only. +

+ +

Invite someone

+
    +
  1. Choose Invite person.
  2. +
  3. + Under Invite using, choose Verified email{" "} + and enter their email address, or choose Sharing code{" "} + and enter the code they gave you. +
  4. +
  5. Choose Viewer or Editor, then Create invitation.
  6. +
  7. Copy the invitation link and send it to them yourself.
  8. +
+

+ Email invitations only work for someone who already has a Connect account + with that email address verified. If they signed up after you created the + invitation, create a new one. +

+ +

Sharing codes

+

+ Use a sharing code when you cannot invite someone by email, for example if + they sign in with a different address. The person you are inviting creates + the code on the Account & sessions page in the Connect + workspace, under Sharing code → Generate code, + and sends it to you. A code can be used once. Invitations and sharing codes + expire after seven days. +

+ +

Accept an invitation

+

+ Open the invitation link while signed in to the account it was created for. + Connect shows A collection was shared with you. Choose{" "} + Accept to add the collection to your collections, then + open it in the Editor or approve other apps to use it. +

+ +

Change or remove access

+

+ In People & sharing, change a person's role from the + list, or choose Remove. Removing someone also revokes the + apps and synced folders they connected to the collection. Invitations that + have not been accepted are listed under Pending invitations, + where you can cancel them. +

+
diff --git a/src/pages/apps/editor/shortcuts/index.astro b/src/pages/apps/editor/shortcuts/index.astro new file mode 100644 index 0000000..99654e0 --- /dev/null +++ b/src/pages/apps/editor/shortcuts/index.astro @@ -0,0 +1,86 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; + +const shortcuts = [ + ["Ctrl P", "Quick open"], + ["Ctrl K", "Quick open, outside the note text"], + [">", "Actions, typed at the start of quick open"], + ["Ctrl Shift N", "New note"], + ["Ctrl Enter", "Create the note being composed"], + ["Ctrl Shift L", "Show or hide the notes sidebar"], + ["↑ / ↓", "Move through the note list"], + ["Alt J / Alt K", "Next or previous note"], + ["Alt ← / Alt →", "Back or forward through opened notes"], + ["Ctrl F", "Find in note"], + ["Ctrl B / Ctrl I", "Bold or italic"], + ["Ctrl Shift C", "Inline code"], + ["Ctrl K", "Add a link, in the note text"], + ["Tab / Shift Tab", "Indent or outdent a list item"], + ["/", "Markdown commands, at the start of a line"], + ["[[", "Link to a note or file"], + ["@", "Link to a note, optionally filtered by type"], + ["?", "Show the shortcut guide"], + ["Esc", "Close quick open or the shortcut guide"] +]; + +const settings = [ + ["Color theme", "Follow the system appearance, or keep a light or dark theme in this browser."], + ["Text size", "Compact, Comfortable or Large note text, without changing the rest of the interface."], + ["Wrap long lines", "Keep Markdown within the writing width. On by default."], + ["Quiet Markdown", "Soften punctuation away from the active line and make tasks checkable. On by default."], + ["Vim key bindings", "Use normal, insert, visual and command modes in the note editor. Off by default."] +]; +--- + + +

Keyboard shortcuts

+

+ On a Mac, use ⌘ in place of Ctrl. Press{" "} + ? anywhere outside a text field to see the guide in the Editor. +

+ + + + + + {shortcuts.map(([keys, action]) => ( + + ))} + +
KeysAction
{keys}{action}
+ +

Editor settings

+

+ Open Settings from the collection rail. These preferences + are stored in this browser only. +

+ + + + + + {settings.map(([name, effect]) => ( + + ))} + +
SettingEffect
{name}{effect}
+ +

Collection settings

+

+ Settings also shows the open collection: its ID, the specification version + it uses, its types folder, the frontmatter keys that declare a type, its + validation level, and the operations the Editor is approved for.{" "} + Forget from this browser removes the collection from the + Editor without changing its files. +

+
diff --git a/src/pages/apps/editor/types/index.astro b/src/pages/apps/editor/types/index.astro new file mode 100644 index 0000000..9f647fd --- /dev/null +++ b/src/pages/apps/editor/types/index.astro @@ -0,0 +1,123 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

What a type is

+

+ A type is a Markdown file in the collection's types folder. It names a kind + of record, such as a task or a person, and describes its frontmatter fields + with JSON Schema. The Editor uses types to build property forms, check + notes, and suggest links. Other apps use the same files. The format is + defined in the mdbase specification. +

+

+ Open Types from the collection rail to see every type. Changing + types needs the collection's definition management permission, which the + Editor requests when you approve it. +

+ +

Create a type

+

In the Types list, choose Add a type, then one of:

+
    +
  • + New type starts from an empty definition. Give the type + a unique name and add your own fields. +
  • +
  • + Ready-made types is a catalog. Each type comes + with an application contract, so apps built for that contract can use + your notes. Adding one creates a new, editable type. Existing files are + never overwritten. Installing one needs permission to install type packs; + without it, the catalog offers to request that access. +
  • +
+ +

Fields

+

+ The visual editor covers the field shapes most collections need: text, + numbers, dates and times, choices, links, lists, nested objects, lists of + objects, and required fields. You can also set Read defaults, which are + used when a note leaves a property out. Source files stay unchanged. +

+

+ Link rules say which fields point to other records, which types they may + point to, and whether the target must exist. Uniqueness rules require a + value to be unique within the type, across the collection, or among + records that match a path pattern. +

+

+ Anything the visual editor cannot represent stays in the YAML source, + marked where it appears. Switch to YAML to edit the complete + definition directly. +

+ +

Type membership

+

+ Type membership decides which notes belong to the type. + A note that names a type in one of the collection's type keys (type{" "} + or types by default) belongs to the types it names, and the + automatic rules below are skipped. Otherwise the note belongs when every + configured condition matches: +

+ + + + + + + + + +
ConditionMatches when
PathIts path matches one of the path patterns.
Field presenceIts frontmatter contains all the listed fields.
ExpressionEach extra rule on its fields is true. These rules are edited in YAML.
+

+ Some collections turn explicit assignment off. Then every note is + classified by the other rules. +

+ +

Collection behaviour

+

+ Collection behaviour controls how the type appears and + acts across tools: the field used as a record's name, description and + colour, an icon, and a path policy. The path policy tells tools where to put + new records of this type and how to name them. Changing it affects future + files only. Existing files are not moved. +

+ +

Works with applications

+

+ An application contract describes the fields an app expects, such as a + task manager's due date and status. Works with applications{" "} + connects a type to an installed contract and maps each contract field to one + of your field names. The app reads your notes through that mapping, and your + notes keep their own field names. A mapping copies values as they are. It + does not convert them. +

+

+ The Editor suggests contracts that might fit, based on field names and + shapes. Check that the meanings match before you accept a suggestion. +

+ +

Review and save

+

+ A type change can affect every note of that type. Before saving, the Editor + shows the fields added, changed and removed, the YAML differences, and + which existing notes would need attention. You can open the list of + affected notes. The collection checks the complete definition when you + confirm. +

+
diff --git a/src/pages/apps/index.astro b/src/pages/apps/index.astro index 44df789..859afa3 100644 --- a/src/pages/apps/index.astro +++ b/src/pages/apps/index.astro @@ -32,6 +32,7 @@ const applications: CatalogueEntry[] = [ collections: "Hosted by Connect or local through Connector", links: [ { label: "Open Editor", href: "https://editor.mdbase.dev/" }, + { label: "Documentation", href: "/apps/editor/" }, { label: "Source", href: "https://github.com/mdbase-dev/mdbase-connect/tree/main/apps/editor" } ] }, @@ -75,8 +76,8 @@ const applications: CatalogueEntry[] = [ runsOn: "OAuth-capable MCP clients", collections: "Hosted by Connect or local through Connector", links: [ - { label: "Setup and tools", href: "https://github.com/mdbase-dev/mdbase-connect/blob/main/docs/mcp-gateway.md" }, - { label: "Endpoint", href: "https://mcp.mdbase.dev/mcp" } + { label: "Set up", href: "/apps/mcp/" }, + { label: "Tool reference", href: "/apps/mcp/tools/" } ] } ]; diff --git a/src/pages/apps/mcp/collections/index.astro b/src/pages/apps/mcp/collections/index.astro new file mode 100644 index 0000000..98bda08 --- /dev/null +++ b/src/pages/apps/mcp/collections/index.astro @@ -0,0 +1,115 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

One approval per collection

+

+ The client does not get general access to your account. Each collection is + approved on its own, with its own list of operations. There is no query or + write that spans collections, and no collection is used unless you approved + it. +

+ +

Connection IDs

+

+ list_connections returns one entry for each approved + collection: +

+ + + + + + + + + + + +
FieldMeaning
idThe connection ID. Every collection tool requires it as connection_id.
collection_idThe collection's ID in Connect.
display_nameThe collection name shown in Connect.
operationsThe operations you approved, such as read, query or update.
authoritylocal when the collection is on your computer, remote when it is hosted.
+

+ Connection IDs are opaque. They are not collection paths and do not reveal + where the collection is stored. +

+ +

Connect more collections

+

+ Ask the client to connect another collection. It calls{" "} + add_connection, which returns a link for you to open in a + browser. The link can be used once and expires after ten minutes. +

+

+ The link opens the same Connect approval screen as the first setup. Choose + the collection and its operations, approve, then ask the client to list + collections again. +

+ +

Reconnect or broaden access

+

+ If a collection's approval expires, or you want to allow operations you + previously left out, the client calls reconnect_collection{" "} + with that connection ID. The returned link opens Connect on that + collection only. You review and approve its operations, or decline. +

+ +

Read and write access

+

+ Two separate approvals control writing. The first is the MCP sign-in scope + the client requests: mdbase:read, mdbase:write, + or both. A client that does not ask for a specific scope gets both. The + client only sees the write tools when the scope includes{" "} + mdbase:write. +

+

+ The second is the set of operations you approve for each collection in + Connect. This one decides what can actually happen. If you approved a + collection for reading only, a write tool fails with{" "} + insufficient_collection_access. It never expands your + approval by itself. If you narrow access in Connect, calls may fail with a + different code until the MCP server's sign-in next refreshes, within an + hour. +

+ +

Revoke access

+

+ Open the Applications{" "} + page in the Connect workspace. The MCP server is listed as{" "} + mdbase. You can narrow or revoke its access to each + collection there. The next tool call for a revoked collection fails, and + other collections keep working. +

+

+ Removing the server from your MCP client stops that client from using it, + but does not remove the approvals held in Connect. Revoke them in Connect as + well if you no longer use them. +

+ +

Collections on your computer

+

+ For a collection that stays on your computer, requests travel from the MCP + server through the Connect relay to the Connector. They are encrypted end + to end between the MCP server and your Connector. The Connector checks its + own copy of your approval before it opens the collection, so a grant you + revoked is refused locally too. +

+

+ The Connector must be running and online. If it is not, tools return{" "} + connector_offline. See{" "} + Troubleshooting. +

+
diff --git a/src/pages/apps/mcp/data-handling/index.astro b/src/pages/apps/mcp/data-handling/index.astro new file mode 100644 index 0000000..5cbf193 --- /dev/null +++ b/src/pages/apps/mcp/data-handling/index.astro @@ -0,0 +1,81 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

Why it is a separate service

+

+ The Connect control plane, which handles accounts and approvals, does not + see collection content. Requests to a collection on your computer are + encrypted before they reach the Connect relay, and only your Connector + decrypts them. A hosted collection is stored by the mdbase hosted + provider, a separate service that can read it to perform operations; it is + encrypted at rest. +

+

+ An AI client cannot perform that encryption itself, so the MCP server does + it on the client's behalf. That means the MCP server sees operation inputs + and results in memory while it handles a tool call, for local and hosted + collections alike. It runs as its own service, with its own database, so + that this access stays outside the control plane. It is not a + zero-knowledge service. +

+ +

What is stored

+
    +
  • Client registrations (name and redirect URLs), hashes of access and refresh tokens, and short-lived sign-in state.
  • +
  • For each approved collection: its ID, display name, approved operations and contract scope.
  • +
  • The credentials the MCP server uses to reach Connect, encrypted.
  • +
  • A key pair for each connection, with the private key encrypted, and a plain message counter for each key.
  • +
+

+ Expired sign-in records are not currently deleted automatically. The + server does not log individual requests. Unexpected errors are logged for + diagnosis. +

+ +

What is not stored

+

The MCP server's database does not hold:

+
    +
  • Record contents, including frontmatter and bodies.
  • +
  • Tool call results.
  • +
  • Record paths within a collection.
  • +
  • Filesystem paths on your computer. These are never sent to the MCP server or to Connect.
  • +
+ +

Your MCP client

+

+ Whatever a tool returns goes to your MCP client and, through it, to the AI + model you are using. That client's own data policies apply to it. Approve + only the collections and permissions you are comfortable sharing with that + client. +

+ +

Your controls

+
    +
  • Each collection is approved separately, with its own permissions.
  • +
  • + Revoking a collection on the{" "} + Applications{" "} + page stops the next tool call. For a local collection, the Connector also + refuses a revoked approval on its own. +
  • +
  • + See the privacy notice and{" "} + security page for how mdbase handles account + data in general. +
  • +
+
diff --git a/src/pages/apps/mcp/index.astro b/src/pages/apps/mcp/index.astro new file mode 100644 index 0000000..f32b565 --- /dev/null +++ b/src/pages/apps/mcp/index.astro @@ -0,0 +1,117 @@ +--- +import DocsLayout from "../../../components/DocsLayout.astro"; +import CodeBlock from "../../../components/CodeBlock.astro"; + +const claudeCode = `claude mcp add --transport http mdbase https://mcp.mdbase.dev/mcp`; + +const firstPrompt = `List my mdbase collections, then describe the first one.`; +--- + + +

What it does

+

+ mdbase MCP is a remote Model Context Protocol server. An MCP client, such + as Claude, uses it to read and change records in mdbase collections you + have approved. It works the same way whether a collection is hosted by + mdbase Connect or stays on your computer and is served by the Connector. +

+

+ The client never receives your Connect account. You approve one collection + at a time, with the exact operations you want to allow, and you can revoke + that approval from Connect at any time. +

+ +

Before you start

+
    +
  • + An mdbase Connect account. Sign up{" "} + if you do not have one. +
  • +
  • + At least one collection. A hosted collection works immediately. A + collection on your computer needs the Connector{" "} + running and online whenever the client uses it. +
  • +
  • + An MCP client that supports remote servers over Streamable HTTP with + OAuth sign-in, including dynamic client registration and PKCE. +
  • +
+ +

Add the server to your client

+

Every client uses the same endpoint:

+ +

+ In Claude on the web or desktop, add it as a custom connector. In Claude + Code, add it from a terminal: +

+ +

+ Other clients have their own screens for adding a remote MCP server. Give + them the endpoint above. There is no API key to paste in. The client + discovers the sign-in flow from the server. +

+ +

Approve a collection

+

When the client first connects, it opens a browser window for sign-in.

+
    +
  1. Sign in to mdbase Connect.
  2. +
  3. Choose one collection.
  4. +
  5. + Review the permissions. Read this collection is + required. Create records, Edit records,{" "} + Delete records and Manage definitions{" "} + are optional, and you can leave any of them out. They appear when the + client asked for write access, which it does by default. +
  6. +
  7. Approve. The browser returns you to your client.
  8. +
+

+ Each approval covers one collection. To use more than one, ask the client + to connect another collection after setup. See{" "} + Connect more collections. +

+ +

Check the connection

+

Ask your client something that needs the collection:

+ +

+ The client should call list_connections and then{" "} + describe_collection. list_connections shows + each collection's approved operations and whether it is local or hosted; + describe_collection returns its types, fields and contracts. +

+ +

Next steps

+ +
diff --git a/src/pages/apps/mcp/tools/index.astro b/src/pages/apps/mcp/tools/index.astro new file mode 100644 index 0000000..08d982f --- /dev/null +++ b/src/pages/apps/mcp/tools/index.astro @@ -0,0 +1,82 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +import reference from "../../../../data/mcp-tools.json"; + +// Generated by scripts/sync-mcp-tools.mjs from the gateway's registered tools. +const groups = [ + { + id: "read-tools", + label: "Always available", + note: "Offered to every client. Tools that act on a collection still need the matching operation approved for it.", + tools: reference.tools.filter((tool) => tool.access === "read") + }, + { + id: "write-tools", + label: "Write tools", + note: "Offered only when the client's sign-in scope includes mdbase:write.", + tools: reference.tools.filter((tool) => tool.access === "write") + } +]; + +function behaviour(annotations: Record): string { + if (annotations.readOnlyHint) return "Read-only"; + if (annotations.destructiveHint) return "Destructive"; + if (annotations.openWorldHint) return "Returns a browser link"; + return "Changes the collection"; +} +--- + + ({ href: `#${group.id}`, label: group.label }))} +> +

+ This page is generated from the tool definitions in the MCP server, so the + names, descriptions and inputs match what your client receives. Inputs + marked optional can be left out. +

+ + { + groups.map((group) => ( +
+

{group.label}

+

{group.note}

+ {group.tools.map((tool) => ( + <> +

{tool.name}

+

{tool.description}

+

{tool.title} · {behaviour(tool.annotations)}

+ {tool.inputs.length > 0 ? ( + + + + + + {tool.inputs.map((input) => ( + + + + + + ))} + +
InputTypeNotes
{input.name}{input.required ? "" : " (optional)"}{input.type}{input.description}
+ ) : ( +

No inputs.

+ )} + + ))} +
+ )) + } +
+ + diff --git a/src/pages/apps/mcp/troubleshooting/index.astro b/src/pages/apps/mcp/troubleshooting/index.astro new file mode 100644 index 0000000..cbba566 --- /dev/null +++ b/src/pages/apps/mcp/troubleshooting/index.astro @@ -0,0 +1,121 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +--- + + +

+ Failed calls return an error with a code and a message. Most + clients show the message; ask the client for the code if it does not. + Some rejections, such as conflicts and validation problems, instead return + a result marked valid: false with diagnostics that carry the + code. +

+ +

Error codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeWhat happenedWhat to do
connector_offlineThe computer that holds this collection is not reachable.Start the Connector on that computer and check it is online, then retry.
connector_busyThe Connector is handling other work.Retry after a moment.
connector_upgrade_requiredThe Connector is too old for this request.Install the latest Connector from Downloads.
insufficient_collection_accessYou did not approve this operation for the collection.Ask the client to reconnect the collection, then approve the extra permission.
connection_expiredThe collection's approval is no longer valid.Ask the client to reconnect the collection.
connection_not_foundThe connection ID does not belong to this client's approvals.Ask the client to list collections again and use a current ID.
concurrent_modificationThe record changed after the client read it. Reported as a diagnostic.Let the client read the record again before changing it.
invalid_queryThe query does not follow the mdbase query format.The message names the problem. The client should correct the query.
encryption_binding_staleAccess to a collection on your computer changed in Connect.Retry later, or reconnect the collection.
generation_expired, query_cursor_expiredThe query cursor expired.Run the query again.
mutation_request_conflictA mutation_id was reused for a different change.Use a new ID, or repeat exactly the original change.
+ +

Sign-in does not finish

+

+ If you closed the browser window or declined the approval, start the + connection again from your client. Links from add_connection{" "} + and reconnect_collection can be used once and expire after + ten minutes, so ask the client for a new one if a link no longer works. +

+ +

A collection is missing

+

+ The client only sees collections you approved for it. Ask it to connect + another collection, or check the{" "} + Applications{" "} + page in Connect to see which collections mdbase can use. +

+ +

The client cannot write

+

+ If the client says it has no tool to create or change records, it signed + in with read-only scope. Remove the server from the client and add it + again. If the tools exist but fail with{" "} + insufficient_collection_access, reconnect the collection and + approve the write permissions. See{" "} + Read and write access. +

+ +

Self-hosted servers

+

+ Running your own MCP server alongside a self-hosted Connect is covered in + the MCP gateway operator guide. +

+
diff --git a/src/pages/apps/mcp/working-with-records/index.astro b/src/pages/apps/mcp/working-with-records/index.astro new file mode 100644 index 0000000..f11aa32 --- /dev/null +++ b/src/pages/apps/mcp/working-with-records/index.astro @@ -0,0 +1,164 @@ +--- +import DocsLayout from "../../../../components/DocsLayout.astro"; +import CodeBlock from "../../../../components/CodeBlock.astro"; + +const query = `{ + "connection_id": "…", + "types": ["task"], + "where": "status != \\"done\\" && priority >= 3", + "order_by": [{ "field": "due", "direction": "asc" }], + "limit": 20 +}`; + +const paged = `{ + "connection_id": "…", + "types": ["note"], + "pagination": "cursor", + "limit": 200 +}`; + +const update = `{ + "connection_id": "…", + "path": "tasks/renew-passport.md", + "patch": { "status": "done" }, + "if_revision": "…revision from read_record…" +}`; + +const receipt = `{ + "mutation_receipt": { + "request_id": "5b0d…", + "retry": "Reuse this request_id as mutation_id when retrying the exact mutation." + }, + "outcome": { … } +}`; +--- + + +

+ You do not need to call these tools yourself. Your MCP client chooses them. + This page explains what they do, so you can tell the client what you want + and understand what it did. +

+ +

Start with the collection

+

+ describe_collection returns the collection's types, their + fields and its contracts. A client that reads + it first can use your field names and types instead of guessing them from a + few files. +

+ +

Query records

+

+ query_records uses the mdbase query format from the{" "} + specification. where is an expression + over record fields, types limits the query to declared types, + and order_by sorts the results. +

+ +

+ Record bodies are left out unless include_body is{" "} + true. frontmatter_mode chooses between the + frontmatter stored in the file (persisted), the values after + type defaults and computed fields are applied (effective), or + both. +

+ +

Large result sets

+

+ limit can be at most 1,000. For large result sets, set{" "} + pagination to "cursor". Pages may be smaller + than limit. Each page's result + includes a cursor for the next page, and every page reads from the same + snapshot of the collection. +

+ +

+ A cursor that is no longer needed can be released with{" "} + release_query_cursor. Unused cursors expire after a short + idle period, from seconds to minutes, so continue promptly. To continue, + repeat the same query with the cursor. +

+ +

Read one record

+

+ read_record takes a path relative to the collection root, such + as projects/alpha.md. The result includes the frontmatter, + body, the types the record belongs to, and its current{" "} + revision. +

+ +

Create and change records

+

+ These tools are available when the client has write access and you approved + the matching operation for the collection. +

+ + + + + + + + + + +
ToolUse
create_recordCreate a record from a type, frontmatter and body. The path can be given or left to the collection's path rules.
update_recordChange fields with patch and replace the body, or replace the whole Markdown source with document. A document cannot be combined with the other two.
rename_recordMove a record. Links to it are updated unless update_refs is false or the collection turns this off.
delete_recordDelete a record. With check_backlinks: true, the result lists records whose links to it are now broken.
+

+ Changes are validated against every type the record belongs to. At the + default validation level, an invalid change is rejected with details and + nothing is written. A collection can lower its validation level in its + configuration. +

+ +

Revisions prevent lost edits

+

+ Each record has a revision that changes whenever the file changes. When a + client passes the revision it read as if_revision, the change + is applied only if nobody else has changed the record since. That includes + you, in another app or a text editor. +

+ +

+ If the record changed in the meantime, the change is not applied. The + result is marked valid: false with a{" "} + concurrent_modification diagnostic. The client should read the record again and decide what to do with the newer + content, rather than overwrite it. +

+ +

Retrying safely

+

+ Every change returns a receipt containing a request ID: +

+ +

+ If a call times out and the client cannot tell whether it happened, it can + repeat the same change with that ID as mutation_id. The + change is applied at most once. Reusing an ID for a different change fails + with mutation_request_conflict. +

+ +

Type definitions

+

+ read_type returns a type definition by name or path.{" "} + create_type and update_type take the complete + type file as document. Updating a type always requires its + current revision. A type change can affect every record of that type, so + the Manage definitions permission is approved separately in Connect. +

+
diff --git a/src/pages/privacy/index.astro b/src/pages/privacy/index.astro index 92d701c..9f80568 100644 --- a/src/pages/privacy/index.astro +++ b/src/pages/privacy/index.astro @@ -53,6 +53,19 @@ import BaseLayout from "../../layouts/BaseLayout.astro"; The provider decrypts them to execute authorized mdbase operations and acts as a trusted data processor.

+

Email

+

+ Connect uses your verified address for account email: verification and + other messages about your account that the service needs to send. Beta + accounts may also receive a short welcome and setup message. +

+

+ Occasionally, we may email account holders about a significant change to + mdbase Connect or a new mdbase application. These announcements are + infrequent and include an unsubscribe link. We do not send regular + product updates or marketing email unless you opt in, and we do not sell + or share your address for others' marketing. +

Application providers

Applications connected through mdbase receive data under the grants users