open-context open-context
September 25, 2026 · 7 min read

DuckDB and SurrealDB: Two Unconventional MCP Backends

DuckDB and SurrealDB are the two most unusual entries in open-context's list of 15 MCP context store backends. DuckDB is an embedded, columnar analytics engine you point at a local file — no server, no client library beyond one npm package. SurrealDB is a remote, multi-model database queried with its own language, SurrealQL, and needs its own bespoke adapter rather than sharing code with the SQL or document families. Neither is the obvious first choice for a context store, but each solves a specific problem the other backends don't.

Key takeaways

  • DuckDB is an embedded, in-process, columnar-vectorized database — no daemon, no port, just a local file, per DuckDB's own documentation.
  • SurrealDB is a multi-model database that natively supports document, graph, relational, time-series, and vector data through one query language, SurrealQL, per SurrealDB's own docs.
  • open-context's DuckDB driver reuses the same sql adapter family and ? placeholder dialect as SQLite and Postgres — only the connection code differs.
  • SurrealDB gets its own adapter (adapters/surreal.ts) because SurrealQL and its schemaless DEFINE TABLE model don't fit the shared SQL or document driver contracts.
  • opencontext db migrate --to moves existing contexts to either backend without losing data, and both pass the same conformance suite every backend has to.

Why these two get grouped together

Every other backend in open-context's BYODB system fits neatly into one of two shared implementations: eight SQL engines behind a single Dialect interface, and four document/key-value stores behind a single DocumentDriver interface. DuckDB and SurrealDB are the exceptions, but for opposite reasons. DuckDB fits the SQL family's shape perfectly — it just runs in a place none of the other seven do: inside your own process. SurrealDB doesn't fit either shared shape at all, because it isn't really a SQL database or a document database; it's both, plus graph and vector, in one engine.

DuckDB: an embedded engine, not another networked database

DuckDB describes itself as an in-process SQL OLAP database with a columnar-vectorized execution engine and no external dependencies at compile time or runtime (DuckDB docs: Why DuckDB). Where SQLite processes rows one at a time and is built for transactional workloads, DuckDB processes batches of column values per operation and is built for analytical ones — the same tradeoff that separates a row store from a column store in any database engine.

open-context's DuckDB driver connects through the @duckdb/node-api package, opens (or creates) a file at the path you give it, and hands back a connection that speaks the same ?-placeholder SQL dialect as SQLite and Postgres. That's why DuckDB lives in the sql adapter family alongside those two: the schema, the queries, and the ordering guarantees are identical. The only thing that changes is which library opens the file and executes against it.

export OPENCONTEXT_DB_URL="duckdb:///home/you/.opencontext/opencontext.duckdb"

Because it's embedded, DuckDB needs nothing running in the background — the same as open-context's default SQLite backend. The reason to reach for it instead of SQLite is what happens after the data is in there: DuckDB can also open that exact file with its own CLI or Python bindings and run genuine analytical SQL over it — window functions, aggregations across your whole context history, joins against other DuckDB or Parquet files — without exporting anything first.

SurrealDB: one engine, several data models

SurrealDB bills itself as a multi-model database that natively supports document, graph, relational, time-series, geospatial, and vector data in a single engine, queried through SurrealQL and reachable from official SDKs in multiple languages (SurrealDB: One database, every data model). It can run as a standalone server, embedded in an application, or distributed across a cluster.

open-context only uses a small slice of that surface — SurrealQL's document-style CREATE, UPDATE MERGE, and SELECT ... WHERE statements against two schemaless tables, oc_context and oc_bubble — but even that slice doesn't fit either shared adapter family. SurrealDB addresses data inside a namespace and a database, not just a database name, and its connection needs to say which auth level a credential belongs to: a root user signs in with just a username and password, while a namespace- or database-scoped user has to name that namespace or database too. None of the SQL or document drivers need that concept, so SurrealDB gets its own adapter rather than a fifth DocumentDriver implementation.

export OPENCONTEXT_DB_URL="surrealdb://user:pass@host:8000/my-namespace/my-database?auth=root"

The ?auth= parameter defaults to root; set it to namespace or database if the credential you're using is scoped that narrowly. On first connect, open-context runs the namespace, database, and table DEFINE statements needed to set everything up, and quietly ignores permission errors from the namespace/database creation step — a properly provisioned but narrowly-scoped user doesn't need to run those and would otherwise fail on a step it never required in the first place.

Picking between them

If you…Reach for
Want zero infrastructure and might query your context history with SQL directlyDuckDB — embedded, one file, analytical queries built in
Already store other application data as documents, graphs, or bothSurrealDB — one engine instead of running several specialized databases
Need the context store reachable from more than one machineSurrealDB — it's a remote server by default
Want the simplest possible local setup with no npm packages beyond the driverDuckDB — npm i @duckdb/node-api and nothing else to run

Neither is the right pick if you just want the smallest possible footprint for a single local install — that's still the default JSON file or local SQLite. DuckDB and SurrealDB earn their place when you already have a reason to want their specific strengths: analytical SQL over your saved context in DuckDB's case, or a shared engine across multiple data shapes in SurrealDB's.

Connecting either one to open-context

Switching backends is always the same shape — one environment variable, one connection string:

# DuckDB — requires: npm i @duckdb/node-api
export OPENCONTEXT_DB_URL="duckdb:///path/to/opencontext.duckdb"

# SurrealDB — requires: npm i surrealdb
export OPENCONTEXT_DB_URL="surrealdb://user:pass@host:8000/namespace/database"

Already have contexts saved locally? Test the connection, switch to it, then bring your history along in that order:

opencontext db test "surrealdb://user:pass@host:8000/namespace/database"
opencontext db use "surrealdb://user:pass@host:8000/namespace/database"
opencontext db migrate --to "surrealdb://user:pass@host:8000/namespace/database"

The migration only ever reads from your current store and writes to the new one, so a failed run partway through leaves your original data untouched. Both backends pass the same ~50-test conformance suite every one of open-context's 15 supported backends has to — the CLI, the web UI, and every MCP tool behave identically once either one is active.

Point your MCP context store at DuckDB, SurrealDB, or any of 15 backends in one environment variable.

Get started with open-context →

FAQ

Does open-context support DuckDB and SurrealDB for the MCP context store?

Yes. DuckDB is a built-in sql-family backend and SurrealDB has its own bespoke adapter. Point OPENCONTEXT_DB_URL at a duckdb:// path for DuckDB or a surrealdb:// connection string for SurrealDB, and the CLI, web UI, and MCP tools behave identically to every other backend.

Do I need to install anything to use DuckDB with open-context?

Yes, one optional peer dependency: npm i @duckdb/node-api. DuckDB itself is embedded — there's no separate server to run, only that one npm package to add once you point OPENCONTEXT_DB_URL at a duckdb:// path.

What do I need to install to use SurrealDB?

The surrealdb peer dependency: npm i surrealdb. Unlike DuckDB, SurrealDB itself is a separate server process (or embedded engine) you run and connect to over the network, not a library that runs inside open-context.

Does DuckDB require a server, or does it run embedded like SQLite?

DuckDB runs embedded, the same way open-context's SQLite backend does. A duckdb:// connection string just points at a local file path, and open-context's driver opens it in-process — there's no daemon to start or port to open.

Can I switch from DuckDB or SurrealDB to another backend without losing my saved contexts?

Yes. Run opencontext db migrate --to "<new-connection-string>" and every context and bubble is copied across. The migration only ever reads from your current store, so a failed run partway through leaves your original data untouched.