OMGDB DOCS
// AI-native

MCP Server

Run omgdb as a stdio JSON-RPC MCP server that exposes the engine as scoped, agent-callable tools with two-layer capability enforcement.


OMGDB ships a minimal Model Context Protocol server that exposes the engine directly to LLM coding agents. Started with omgdb mcp, it speaks newline-delimited JSON-RPC 2.0 over stdin/stdout and advertises the database as a set of agent-callable tools built on the engine’s own JSON codec.

The defining feature is its capability-scope model. The server runs at a single ceiling — read, read-write, or dangerous — and a tool is only callable if its required scope is within that ceiling. Enforcement happens in two layers: tools above the ceiling are never advertised in tools/list, and every tools/call re-checks the ceiling before executing. As a result, an untrusted agent can be handed a read-only database it is structurally unable to mutate.

Running the server

omgdb mcp

This starts a stdio server at the default read-write scope. The process reads JSON-RPC requests one per line from stdin and writes one JSON response per line to stdout, flushing after each. It runs until stdin closes (EOF). Blank lines, lines that do not parse as a JSON object, and objects without a string method are silently ignored.

To restrict the server to read-only tools:

omgdb mcp --scope read
FlagDescription
--scopeCapability ceiling enforced on every tool call. read (alias ro), read-write (default; aliases write, rw), or dangerous (alias all). An unrecognized value aborts with invalid --scope '<x>' (use read, read-write, or dangerous).

Note: The server is stateless across calls. Every tool that touches data is passed a path argument and reopens the store with Store::open for that call; no connection or session handle is held between requests.

Capability scopes

There are three ordered scopes. The ordering is read < read-write < dangerous, and a tool is allowed if and only if its required scope is less than or equal to the server’s scope.

ScopeAliasesTools permitted
readroThe 7 read-only tools (find, aggregate, describe, explain, diagnose, vsearch, context_pack)
read-writewrite, rwAll 11 tools (the 7 read tools plus insert, plan_update, apply, rollback)
dangerousallReserved for tools marked destructive (currently none — see below)

Two-layer enforcement

The capability ceiling is enforced at both discovery and execution time:

  1. Discovery. tools/list filters the full 11-tool catalog down to only those whose required scope is within the server scope. A read server returns 7 tools; a read-write server returns all 11. A read-only agent never even sees the mutating tools.

  2. Execution. tools/call re-checks the ceiling before doing any work. A disallowed call returns a successful JSON-RPC result whose content is a text block with isError set to true and a message like:

    Error: tool `insert` requires `read-write` scope but this server runs with `read` scope

Because the check is repeated at call time, hiding a tool from tools/list is not the only line of defense — an agent that guesses a tool name it was never shown is still refused.

Limitation: No tool currently requires the dangerous scope. The scope resolver maps every unknown or unregistered tool name to dangerous, but dispatch returns an error for any name outside the 11-tool set. In practice --scope dangerous advertises and permits exactly the same 11 tools as --scope read-write; there is no destructive (drop/delete) tool implemented.

Tools

The server exposes 11 tools. All document, filter, pipeline, and update arguments are JSON values; path names the on-disk store.

ToolRequired scopeDescription
findreadFind documents matching a MongoDB-style filter (path, collection, optional filter); returns NDJSON.
aggregatereadRun an aggregation pipeline — an array of stages (path, collection, pipeline); returns NDJSON.
describereadGet a Markdown manual of the database (path).
explainreadExplain how a query will run, index scan vs full scan (path, collection, filter).
diagnosereadWhy-not debugger: per-predicate selectivity for a query (path, collection, filter).
vsearchreadSemantic search over a text field (path, collection, field, query; optional k, filter).
context_packreadBuild a token-budgeted, cited context bundle for a task over a text field (path, collection, field, query; optional budget, filter).
insertread-writeInsert a JSON document into a collection (path, collection, document); returns the new ObjectId.
plan_updateread-writeDry-run a $set/$unset/$inc update: returns a token plus a before/after sample, writes no data (path, collection, optional filter, update).
applyread-writeApply a planned change by token, reversibly (path, token).
rollbackread-writeRoll back a previously applied change by id (path, change_id).

Argument schemas

Each tool’s inputSchema lists its declared properties under properties (each with a JSON type) and marks them required — with one exception: a property literally named filter is never listed in required. For find, explain, and diagnose this leaves filter out of the schema’s required array while path and collection remain required. Note that this is a schema-level optionality only: at execution time, just find defaults a missing filter to empty, whereas explain and diagnose require filter to be present at call time and return a missing argument \filter“ error if it is omitted.

vsearch accepts an optional k (default 5) and context_pack an optional budget (default 1000). Both accept an optional filter object for hybrid search and embed text with the engine’s default hashing embedder. See vector search and context packs for details.

The mutation safety workflow

The mutating tools implement the reversible change workflow described in agent mutations:

  • plan_update is a dry run that writes nothing and returns a token plus a before/after sample.
  • apply commits a planned change by its token.
  • rollback reverses a previously applied change by its change_id.

All three require read-write scope. Plan tokens are produced and consumed by the underlying change engine, not held in MCP server memory, which keeps the server stateless.

JSON-RPC methods

MethodBehavior
initializeReturns protocolVersion "2024-11-05", capabilities.tools, and serverInfo { "name": "omgdb", "version": <crate version> }. Client params are ignored; there is no version negotiation.
tools/listReturns the scope-filtered tool catalog.
tools/callDispatches a tool by params.name with params.arguments.
notifications/*Any method beginning with notifications/ receives no reply, per JSON-RPC notification semantics.

Error handling

Two kinds of failures are distinguished. Protocol-level problems are returned as JSON-RPC errors:

CodeMessageCause
-32601method not foundMethod is not initialize, tools/list, tools/call, or a notifications/* notification.
-32602invalid paramsparams is not an object.
-32602missing tool nameparams.name is not a string.

Tool-level failures — including a refused-by-scope call, a missing argument, an unknown tool name, or an engine error — are not JSON-RPC errors. They return a successful result envelope whose content is a text block with isError set to true.

Safety annotations

Every tool carries an annotations object so an MCP host can reason about tool safety:

AnnotationValue
readOnlyHinttrue for the 7 read tools, false for the 4 mutating tools.
idempotentHintSame as readOnlyHint.
destructiveHintAlways false, including for apply and rollback.
requiredScopeThe tool’s required scope as a string (read / read-write / dangerous).

Note: requiredScope is an OMGDB-specific annotation, not part of the standard MCP annotation set (readOnlyHint / idempotentHint / destructiveHint / openWorldHint). Also note that because destructiveHint is hard-coded to false, hosts relying solely on destructiveHint will treat every OMGDB tool — even apply and rollback — as non-destructive. Use requiredScope or run the server at --scope read to fence off mutations.

Example: initialize and list tools

Send these two requests on stdin (one JSON object per line):

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}

The initialize response identifies the server:

{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"omgdb","version":"..."}}}

At the default read-write scope, tools/list returns all 11 tools, each with an inputSchema and annotations. A single entry looks like:

{
  "name": "find",
  "description": "Find documents matching a MongoDB-style filter",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {"type": "string"},
      "collection": {"type": "string"},
      "filter": {"type": "object"}
    },
    "required": ["path", "collection"]
  },
  "annotations": {
    "readOnlyHint": true,
    "idempotentHint": true,
    "destructiveHint": false,
    "requiredScope": "read"
  }
}

Example: calling a tool

A tools/call for find against the store app.omgdb:

{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"find","arguments":{"path":"app.omgdb","collection":"users","filter":{"age":{"$gte":21}}}}}

If the server were started with --scope read, a call to a write tool such as insert would return a result flagged as an error rather than performing the insert:

{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"insert","arguments":{}}}
{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"Error: tool `insert` requires `read-write` scope but this server runs with `read` scope"}],"isError":true}}
  • Agent mutations — the plan_update / apply / rollback change workflow surfaced by the write tools.
  • CLI reference — the full omgdb command surface, including the equivalent direct commands.

Edit this page on GitHub →