Skip to main content
The MongoDB VFS exposes MongoDB databases, collections, and documents as a virtual filesystem mounted at some prefix such as /mongodb/. For connection setup, see MongoDB Setup. Install the extra:

Config

Fields marked secret are redacted in snapshots.

VFS.md

The VFS.md an agent reads with MongoDB mounted at /<path>.

Virtual Filesystem

/<path> layout

Supported Unix Commands for VFS

Unix commands work on each path as on a local filesystem, as far as the path supports them:

Limitations of Unix Commands for VFS

Where a path differs from a local filesystem:Run man <cmd> or <cmd> --help for one command’s usage.
The mount mirrors MongoDB’s cluster → database → collection / view model. The database directory always appears in the path, even when databases filters to a single entry.
Example:
Discovery lists databases, collections, views, and their fixed file names. It does not enumerate one filesystem entry per document. Schema inspection is separate from bulk document reads, so discovering a collection does not require exporting it. These paths and read contracts are shared by Python and TypeScript.

documents.jsonl

One JSON object per line, encoded with BSON Relaxed Extended JSON. BSON-specific types round-trip through their canonical $ wrappers:
cat / head / tail / grep / jq can read this file through the same streaming interface. The cursor fetches documents in batches; head can stop after a prefix. Commands that need the whole input, such as sort or jq -s, can still buffer it. Use bounded reads when exploring a large collection. Because the file is rendered on demand, stat / ls -l report no size and du returns 0 for it (computing the real size would require rendering the whole collection). Use wc -c documents.jsonl for the actual rendered byte count, or wc -l documents.jsonl for an exact document count (which can scan the collection). stat -c %s prints - for an unknown size and 0 only for a known empty file. Missing dates also display as -. Long directory listings include a total row. GNU ls reports allocated disk blocks there; the VFS does not expose allocation metadata, so Mirage prints total ? for nonempty listings and total 0 for empty listings. This is an intentional divergence from GNU output, not a sum of rendered file sizes. stat checks existence and type without counting documents, sampling fields, or fetching indexes. This keeps ls, find, and opening a stream independent of the collection size. The same unknown-size convention applies to Postgres row exports and other rendered VFS files.

schema.json

Generated from the first 100 documents in _id order. Includes:
  • field path → observed BSON type frequencies (nested paths unioned across the sample)
  • index definitions from listIndexes, without volatile access counters
  • the $jsonSchema validator if one is registered
Repeated reads of unchanged data produce identical bytes. Schema reads do not include document counts or $indexStats, so reading a schema cannot change its own content. Views skip indexes.

database.json

Lists collection and view names using two catalog listings, without a per-collection count. Useful for cat /mongodb/<db>/database.json to get an overview without recursing into each entity.

Elided fields

Fields listed under elide_fields are dropped entirely from documents.jsonl output. The type stays documented in schema.json, so heavy fields (embeddings, large binary, raw text blobs) can be hidden from agent reads without losing the schema signal:
Nested paths use dot notation. Elision applies to both cat (one-shot streaming reads) and tail -f (live change-stream follows).

Streaming and Limits

cat, grep, head, and tail -f consume documents lazily through a batched PyMongo async cursor (or change stream); the consumer cancels to stop fetching. Direct output is capped at 2,000 lines by default, with a truncation notice on stderr. Pipes and redirects bypass this output cap. See command output limits to change the bound.

Smart Commands

grep and rg

For one plain text in a collection’s or view’s documents.jsonl, grep and rg ask MongoDB for the documents that may hold it, in the _id order a plain read takes, and search their lines instead of the whole collection. The filter matches the text in any case against every key and string of a document, eight levels deep; a document nested deeper, or holding a value it cannot look into (binary, a regex, code), is always sent. MongoDB still scans the collection, but only those documents are sent. The file is read as usual when the text holds anything but ASCII letters and spaces, or could match an Extended JSON key ($oid, $date, $numberLong), a JSON literal (true, null) or an id (a word of hex letters only, such as ada). schema.json and database.json are always read, and -m stops the cursor early.

head / tail / tail -f

tail uses server-side sort + limit. A count past max_doc_limit on a collection that long is refused with File too large rather than printing fewer lines than asked. head streams in _id order and stops after the count. tail -f on a collection reads the last lines at one snapshot, then opens a Mongo change stream of the inserts after it and yields each new document as a JSONL line in the same format as cat; on a view it polls. See Lines:
tail -f follows inserts on a replica set on MongoDB 5.0 or later, for the snapshot read and the change stream; Atlas already satisfies this. On a server outside a replica set it polls, and so does a view, which has no change stream.

Cache

The MongoDB VFS lists database names, collection names, and document counts. These listings are not cached by default (index_ttl = 0); a workspace or mount index: caches them for its ttl. Document content is not cached. The VFS leaves caches_reads at its default of False, so cat, grep, head, and tail always query the live collection instead of serving a stored snapshot. This keeps reads consistent with a mutable database and ensures tail -f follows the live change stream rather than replaying cached bytes.

Integration

What MongoDB answers through its own API, so fewer files are read. Integration explains each command.

Example

Runnable examples

Three working examples live under examples/python/vfs/mongodb/:
  • mongodb.py — agent-shell workflow: ls, tree, cat, head, tail, wc, stat, grep/rg at every scope, jq, find, cd + relative paths.
  • mongodb_vfs.py — in-process VFS: os.listdir and open() walk every readdir level (root, database, collections/, views/, entity) and read database.json, schema.json, documents.jsonl (collection + view).
  • mongodb_fuse.py — same coverage as the VFS example, but the tree is mounted as a real filesystem so other processes can cat/ls/head the mountpoint directly.
All three default to the mirage_test database seeded by scripts/seed_mongodb_test.py.

Finding IDs

_id is serialized as {"$oid": "..."} under Extended JSON:

Working with Large Collections

Streaming is the default; reach for these patterns when you want to keep the round trip small:
Hide embeddings or large blobs from agent reads with elide_fields; schema.json still documents the original type so the agent can decide when to ask for the raw bytes through a different path.

Shell Commands

Standard commands available on the mounted MongoDB tree: