Server Mode

Server Mode

Server mode starts a local web server, allowing you to browse your markdown files in any web browser with live reload.

Starting the Server

mbr -s /path/to/notes

By default, the server runs at http://127.0.0.1:5200/.

Features

Live Reload

When you save changes to a file, the browser automatically reloads:

  1. mbr watches for file changes via the filesystem
  2. Changes trigger a WebSocket notification
  3. Connected browsers refresh the current page

This works for:

Press / or click the search icon to open search:

See Searching contacts for examples.

Directory Browsing

Navigate your markdown repository:

Tag Navigation

If your files use YAML frontmatter with tags:

---
tags: project, important, review
---

The sidebar shows a tag tree for filtering files.

Recent Files

mbr tracks recently viewed files (stored in browser localStorage), providing quick access to your working set.

Editing Is Off Unless Asked For

Unlike the GUI, mbr -s serves read-only by default. Turn in-browser editing on with --edit, edit_enabled = true in .mbr/config.toml, or MBR_EDIT_ENABLED=true; --no-edit turns it off whatever the configuration says. On a non-loopback --host, editing also needs an edit_token_hash.

Server mode deliberately does nothing with external links. https:// links, mailto:, message:, zoommtg: and every other scheme are left entirely to the browser you are visiting with, which already opens them the way you expect. Same for static builds.

This is the opposite of GUI mode, where there is no browser to defer to and mbr hands the URL to the operating system itself. That hand-off is GUI-only by design and enforced at runtime: the launcher refuses, before touching the OS, unless a GUI window is actually running in the process, and logs the refusal at warn.

The reason is worth stating plainly: a server must never be induced to launch applications on its host. Launching an application is something an interactive window does for the person in front of it. mbr -s has no such person, and if a page could make the serving process start programs, anyone who could reach that page — especially on a shared or non-loopback bind — could start programs on the machine running it. So the capability simply is not available outside GUI mode, regardless of what a page, a template override, or a future code path asks for.

File Browser Sidebar

Press - (minus key) to open the file browser sidebar. This is a three-pane navigator for exploring your entire markdown collection.

Layout

┌──────────────────────────────┐
│  × Close                     │
├──────────────────────────────┤
│  🔍 Filter...                │
├──────────────────────────────┤
│  SHORTCUTS                   │
│    ⭐ My Important File      │
│    ⭐ Daily Notes            │
├──────────────────────────────┤
│  RECENT                      │
│    📄 guide.md               │
│    📄 notes.md               │
├──────────────────────────────┤
│  TAGS                        │
│    ▸ project (12)            │
│    ▸ review (5)              │
│    ▾ important               │
│        ▸ urgent (3)          │
├──────────────────────────────┤
│  FOLDERS                     │
│    ▸ docs/ (24)              │
│    ▸ notes/ (156)            │
│    ▾ projects/               │
│        ▸ website/ (8)        │
└──────────────────────────────┘

Browser Sections

SectionDescription
FilterQuick text filter across all visible items
ShortcutsFiles you’ve pinned for quick access
RecentRecently viewed files (persisted in localStorage)
TagsHierarchical tag tree with file counts
FoldersDirectory structure mirroring your filesystem

Selecting a folder or tag opens a second pane listing its notes. For a folder, the pane lists the folder’s direct subfolders first (with their note counts), then the notes directly inside it; tapping a subfolder moves the pane into it and expands the folder tree to match. On a phone the pane covers the tree, so this is how you walk down the folders. Long lists show 100 entries at a time, with Show more to reveal the next 100. The note you are reading is marked with a tinted card and an accent bar.

Keyboard Shortcuts

KeyAction
-Toggle sidebar open/closed
EscapeClose sidebar
↑ / ↓Navigate items
EnterOpen selected file or expand folder
→Expand folder or tag
←Collapse folder or tag

Pinning Shortcuts

Right-click any file in the browser to add it to your shortcuts. Shortcuts appear at the top for instant access to frequently used files.

To remove a shortcut, right-click it and select “Remove from shortcuts.”

Tag Hierarchy

Tags support hierarchical organization using / as a separator:

---
tags: project/website, project/website/frontend
---

This creates a nested tag tree:

Click a parent tag to see all files with that tag or any descendant tags.

Persistence

The browser remembers your preferences across sessions:

DataStorageCleared By
Recent fileslocalStorageClear browser data
ShortcutslocalStorageClear browser data
Expanded foldersSession onlyPage refresh
Selected tagsSession onlyPage refresh

Full-Text Search

Press / (forward slash) to open the search dialog.

Search Features

FeatureDescription
Fuzzy matchingFinds partial matches and typos
Ranked resultsBest matches appear first
SnippetsShows matching text with highlighted terms
Metadata searchSearches titles, tags, and descriptions
Folder scopingLimit search to current directory

Search Syntax

QueryMatches
rust asyncFiles containing both “rust” AND “async”
"exact phrase"Files containing the exact phrase
tag:projectFiles with the “project” tag
title:guideFiles with “guide” in the title

Keyboard Navigation

KeyAction
/Open search
EscapeClose search
↑ / ↓Navigate results
EnterOpen selected result

Press f, F, or T to open the Link Explorer - a quick navigation modal for jumping between pages and headings.

The info panel open beside a note, with the link graph at the top and the note’s metadata below

The info panel (Ctrl/Cmd+G): a mini link graph, frontmatter and document stats.

Tabs

KeyTabDescription
fLinks OutAll links from the current page to other pages
FLinks InBacklinks - pages that link to the current page
TToCTable of contents - all headings in the current document

Features

Layout

┌──────────────────────────────────────────┐
│  [Links Out]  [Links In]  [ToC]          │
├──────────────────────────────────────────┤
│  🔍 Filter...                            │
├──────────────────────────────────────────┤
│  → Getting Started                       │
│  → Installation Guide                    │
│  → API Reference               ↗ (ext)   │
│  ← docs/intro (backlink)                 │
├──────────────────────────────────────────┤
│  ^n ^p navigate  Tab switch  Enter open  │
└──────────────────────────────────────────┘

Keyboard Shortcuts

KeyAction
fOpen Links Out tab
F (Shift+f)Open Links In (backlinks) tab
T (Shift+t)Open Table of Contents tab
TabCycle to next tab
Shift+TabCycle to previous tab
↑ / ↓Navigate items
Ctrl+n / Ctrl+pNavigate items (vim-style)
Ctrl+d / Ctrl+uScroll the list
EnterNavigate to selected item
EscapeClose the explorer

The Links Out and Links In tabs require link tracking to be enabled (default). This is controlled by the link_tracking config option:

# .mbr/config.toml
link_tracking = true  # default

When enabled, mbr automatically tracks:

This enables wiki-style bidirectional link navigation without requiring any special syntax.

Server Endpoints

EndpointMethodDescription
/GETHome page (root directory listing)
/{path}/GETMarkdown page or directory
/{path}GET301 to the canonical /{path}/ when it names a markdown page
/.mbr/site.jsonGETFull site metadata as JSON
/.mbr/searchPOSTSearch endpoint
/.mbr/ws/changesWSWebSocket for live reload
/.mbr/*GETStatic assets (CSS, JS, fonts)

Static Files and Byte Ranges

Files that are not markdown (images, PDFs, video, audio) are served as they are, with Accept-Ranges: bytes. A Range request gets 206 Partial Content and a Content-Range header, which is what lets a <video> element seek without downloading the whole file:

GET /videos/demo.mp4  Range: bytes=0-99    → 206 Content-Range: bytes 0-99/52428800
GET /videos/demo.mp4  Range: bytes=1000-   → 206 (from byte 1000 to the end)
GET /videos/demo.mp4  Range: bytes=-500    → 206 (the last 500 bytes)
GET /videos/demo.mp4  Range: bytes=99999999999-  → 416 Content-Range: bytes */52428800

A range that cannot be satisfied, does not parse, or asks for several parts at once is answered 416 Range Not Satisfiable.

When mbr runs inside the iOS app, a file the cloud provider has listed but not downloaded yet is answered 503 Service Unavailable with a Retry-After header (a note shows a “Downloading” page), and its download is requested.

Canonical URL Redirects

Markdown pages have exactly one URL: the directory-style one with a trailing slash (docs/guide.md → /docs/guide/). Any other spelling gets a 301:

GET /docs/guide      → 301 Location: /docs/guide/
GET /docs/guide.md   → 301 Location: /docs/guide/
GET /docs            → 301 Location: /docs/          (docs/index.md)
GET /docs/index/     → 301 Location: /docs/
GET /docs/guide?x=1  → 301 Location: /docs/guide/?x=1

This is not cosmetic. The trailing slash decides the base a browser uses for the page’s own relative links: from /docs/guide/ a ../other/ href reaches /docs/other/, but from /docs/guide it reaches /other/. Serving the page in place at the slashless URL would break every link on it, one click later.

Static files (/images/photo.png, /LICENSE), directory listings and /.mbr/* routes are never redirected.

Search API

The search endpoint accepts POST requests:

{
  "q": "search query",
  "limit": 50,
  "scope": "all",
  "filetype": "markdown",
  "folder": "/docs"
}

Response:

{
  "query": "search query",
  "total_matches": 42,
  "results": [
    {
      "url_path": "/docs/guide/",
      "title": "Guide",
      "description": "...",
      "tags": "...",
      "score": 95,
      "snippet": "..."
    }
  ],
  "duration_ms": 15
}

Two fields appear only when they apply: scan_in_progress: true while the initial repository scan is still running (results may be incomplete), and not_downloaded: N when content search had to skip N notes whose contents are not on the device yet (the iOS app with a cloud provider; never on the desktop).

Configuration

Port Configuration

Default port is 5200. Change via configuration:

# .mbr/config.toml
port = 3000

Or environment variable:

MBR_PORT=3000 mbr -s ~/notes

If the configured port is in use, mbr automatically tries the next port.

IP Binding

By default, mbr binds to 127.0.0.1 (localhost only). To allow network access:

# .mbr/config.toml
ip = "0.0.0.0"

Warning: Binding to 0.0.0.0 exposes your files to the network.

oEmbed Timeout

Control how long mbr waits for URL metadata:

mbr -s --oembed-timeout 1000 ~/notes  # 1 second

Development Workflow

A typical writing workflow:

# Terminal 1: Start server
mbr -s ~/notes

# Terminal 2: Edit files
vim ~/notes/new-article.md

Changes appear in the browser automatically.

With Editor Integration

Many editors can open URLs on save. Configure your editor to:

  1. Save the file
  2. Trigger browser refresh (or let live reload handle it)

Multiple Repositories

Run multiple servers on different ports:

mbr -s ~/notes &                    # Default port 5200
MBR_PORT=5201 mbr -s ~/docs &       # Custom port 5201

Caching

mbr provides proper cache headers for browser caching:

Browsers can cache static assets and validate on subsequent requests.

Troubleshooting

Port Already in Use

If you see “Address already in use”:

  1. Another mbr instance may be running
  2. Another application is using the port
  3. Try a different port: MBR_PORT=3000 mbr -s ~/notes

Live Reload Not Working

If changes don’t appear:

  1. Check WebSocket connection in browser DevTools
  2. Ensure file is being saved (not just buffered)
  3. Verify file is in the watched directory
  4. Check for errors with -v flag

Slow Initial Load

For large repositories:

  1. First load scans all files for metadata
  2. Subsequent loads are faster (browser caching)
  3. Consider using ignore_dirs to skip large directories