Library / SDK
foxglove/mcap avatar
foxglove/mcap

MCAP: a serialization-agnostic log container format

MCAP is a modular, performant, and serialization-agnostic container file format, useful for pub/sub and robotics applications.

1,123 stars240 forksRustMIT

At a glance

What is it?
MCAP is a file format and a set of logging libraries for recording time series and message streams, built for robotics and other pub/sub workloads where files have to stay readable as schemas change. The repository ships implementations in C++, Go, Python, JavaScript, TypeScript, Swift, and Rust, plus a CLI for inspecting, merging, and splitting files.
Who is it for?
Adopt MCAP if your application records time series or message streams that later have to be replayed and read with schemas that evolve, which is the robotics and vehicle logging case the format was designed for. Do not adopt it as a general structured logging format for a web service, where a text log and an aggregator are simpler.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why a container format rather than a serialisation

MCAP is described as a logging library and file format, commonly used in robotics applications, and it works well under various workloads, resource constraints, and durability requirements. The description in the repository metadata calls it a modular, performant, and serialization-agnostic container file format, useful for pub/sub and robotics applications.

The distinction that defines the format is between the container and the encoding of the messages inside it. A typical log file, whether JSON lines or a protobuf stream, bakes the serialization format into the file. If you change your message schema, the old files become unreadable, or at best readable by a decoder that you have to keep around forever. MCAP separates the two. The container knows about channels, schemas, and message boundaries, and the payload of a message can be encoded with whatever format the producer used.

That is why the format is described as serialization-agnostic, and it is the reason a robotics log can be read years later even after the ROS message definitions have changed, as long as the schema was recorded alongside the data.

The format is specified rather than merely implemented. The documentation section links a file format specification at mcap.dev/spec and, unusually, a Kaitai Struct definition of that specification, which is a machine-readable description of the binary layout. There is also a motivation document, an evaluation PDF, and a support matrix. The spec-first approach is what allows six language implementations to be interchangeable, and it is why the conformance tests matter.

Seven languages, one specification

The quickstart table is the clearest statement of the project's scope. MCAP libraries are provided in C++, Go, Python, JavaScript and TypeScript, Swift, and Rust, and each language has its own README with guidance and its own API documentation.

The distribution channels differ per language, which tells you something about the maturity of each. C++ ships as the mcap package on Conan. Python ships as mcap on PyPI, and the release history shows the Python package at v1.5.0 from 2026-09-24, following v1.4.0 in June. JavaScript and TypeScript ship as @mcap/core on npm, and the npm workspace reveals that the JavaScript side is split into several packages, with @mcap/core, @mcap/support, @mcap/nodejs, and @mcap/browser as separate build outputs, plus example packages. Rust ships as mcap on crates.io, and Go and Swift are described as see releases, meaning they are versioned from the repository releases rather than through a central package index.

A separate CLI is published for the command line, with its own release at v0.3.0 from 2026-07-15, and the README says you can install it with brew install mcap or download the latest version from the releases page.

The repository layout matches the multi-language structure, with a directory per language, a website/ directory holding the documentation site, benchmarking/ for performance work, testdata/ for fixtures, and tests/ for the cross-implementation tests. The Rust side is a Cargo workspace with two members, rust/mcap and rust/cli, using resolver version 2, and the release profile strips symbols and aborts on panic.

The CLI for inspecting, merging, and splitting

The command line tool is what you reach for when you already have files and need to answer questions about them. The README describes it as a way to inspect, merge, and split MCAP files, and the CLI documentation at mcap.dev/guides/cli covers installation and usage. Installation is either brew install mcap or a download from the releases page.

The three verbs map onto the operations that matter in practice. Inspect is for understanding a file, which channels it holds, what schemas it references, and what the time range is. Merge is for combining recordings from several robots or several runs into one file that can be searched as a whole. Split is for cutting a long recording into segments, which is how you keep file sizes manageable when a vehicle logs continuously.

The build configuration for the CLI binary shows a decision worth noting. The Cargo manifest defines a separate profile named dist that inherits release and adds lto with codegen-units set to 1, and the comment in the manifest explains why: fat LTO over a single compilation unit shrinks the binary substantially but roughly doubles a clean release build and makes an incremental relink about five times slower, so it lives in its own profile instead of release. The release profile itself strips symbols and sets panic to abort, while a separate bench profile keeps debug info and enables LTO so that benchmark numbers reflect optimised code.

That care about the shipped binary is a reasonable signal for a tool that gets distributed to laptops and CI images, where size and startup time matter more than for a library.

Conformance testing across implementations

The repository has a testdata/ directory and a tests/ directory, and the root package.json contains the scripts that make the cross-implementation testing work. There is a workspace package at tests/conformance, and two scripts drive it:

json
"test:conformance:generate-inputs": "yarn workspace @foxglove/mcap-conformance generate-inputs --data-dir \"$(pwd)/tests/conformance/data\"",
"test:conformance": "yarn workspace @foxglove/mcap-conformance run-tests --data-dir \"$(pwd)/tests/conformance/data\""

The two-step design is what makes this a real cross-implementation check rather than a set of per-language unit tests. One implementation generates the input files, and then every implementation has to read them and produce the same result. A file written by the Rust writer and read by the Python reader, and the same file read by the TypeScript reader, all have to agree, and that is the property that matters for a format meant to be portable.

The conformance package is named @foxglove/mcap-conformance, and the data directory is shared at the repository root, so the fixtures are literally the same bytes for every language.

The JavaScript side also has a benchmark workspace at typescript/benchmarks, and the repository has a top-level benchmarking/ directory, which together with the Rust bench profile shows that write and read throughput is treated as a first-class property of the format rather than an afterthought.

What the format does not decide for you

MCAP is a container, and the boundaries of that decision are worth being clear about, because the format's flexibility is exactly what makes it useful and exactly what it refuses to solve.

The format does not define how your messages are encoded. That is the point of being serialization-agnostic, and the consequence is that a reader needs the schema, which the container records, and the decoder, which is your code's business. If you choose a bespoke binary encoding for your payloads, MCAP will store it faithfully and no one else will be able to read it without your decoder.

The format also does not give you a query language, a viewer, or an analytics layer. The CLI can inspect, merge, and split, and the documentation site is the reference, but the ecosystem around a MCAP file is yours to build. The citation block in the README asks that if you use MCAP in research you cite it, with a suggested BibTeX entry naming Foxglove Technologies as the publisher.

The one thing to be careful about is the two-sided nature of the implementation. Reading and writing are separately implemented in each language, and the conformance suite is what keeps them in agreement. If you pick a language whose conformance status you have not checked, you may find that it reads files the other implementations produce but that its own output is not portable, or the other way round. The support matrix at mcap.dev/reference is where that information is meant to live, and it is the first thing to check for a language you care about.

Against rosbag, and against plain log files

The comparison with ROS bag files is the obvious one, since robotics is the format's home territory. MCAP records the schema with the data, which is what allows the same file to be read by a tool written in a different language with no ROS dependency at all, and what allows the schema to evolve over a deployment's lifetime.

Against plain log files, the difference is structural rather than textual. A line-oriented text log is cheap, greppable, and readable by anything, and for an application whose logs are only ever read by a human or by a line-based aggregator, it remains the better choice. MCAP pays for the index and the channel and schema metadata in exchange for random access, per-channel filtering, and schema-aware decoding. That trade only makes sense when the log is a data product rather than a diagnostic output, which is the case in robotics, in vehicle data collection, and in any system where a recording has to be replayed and analysed later.

A third path is to use an existing time series database or a columnar format and skip the file entirely. The difference there is that a database gives you querying across many recordings and a live view, while a self-describing file gives you durability, a simple transfer, and the ability to hand someone a single artefact that contains everything needed to read it, years later, with no server running.

The project also publishes a motivation document and an evaluation, which is where the design rationale lives if you want to understand why the container is shaped the way it is before you commit to it.

Editorial conclusion

Adopt MCAP if your application records time series or message streams that later have to be replayed and read with schemas that evolve, which is the robotics and vehicle logging case the format was designed for. Do not adopt it as a general structured logging format for a web service, where a text log and an aggregator are simpler. Verify first that the conformance suite passes for your language implementation, since reading and writing are separately implemented in each one.

Frequently asked questions

What is MCAP and what is it used for?

MCAP is a logging library and file format, commonly used in robotics applications, and it works well under various workloads, resource constraints, and durability requirements. It is a modular, serialization-agnostic container file format useful for pub/sub and robotics applications.

Which programming languages have MCAP libraries?

C++ through the mcap package on Conan, Python as mcap on PyPI, JavaScript and TypeScript as @mcap/core on npm, and Rust as mcap on crates.io, with Go and Swift versioned from the repository releases. Each language has its own README and API documentation.

What can the MCAP CLI do?

The CLI is for inspecting, merging, and splitting MCAP files from the command line. You can install it with brew install mcap or download the latest version from the releases page, and the CLI guide at mcap.dev/guides/cli covers installation and usage.

How is compatibility between the MCAP language implementations tested?

Through a conformance package in the tests/conformance workspace. One implementation generates input files into a shared data directory with the generate-inputs script, and then every implementation reads them and must produce the same result, with the run-tests script driving the comparison.

Is MCAP a replacement for a text log?

Not really. A line-oriented text log is cheaper and greppable, and it is the better choice when the log is only read by a human or a line-based aggregator. MCAP pays for channel and schema metadata in exchange for random access, per-channel filtering, and schema-aware decoding, which suits recordings that are replayed and analysed later.

Official sources

  1. foxglove/mcap on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/foxglove-mcap.svg)](https://hysenlabs.com/projects/foxglove-mcap)

Was this useful?