Apache-2.0
Rust · Real-time

mtwRequest

One Rust runtime for WebSocket, HTTP and AI agents.

Stop gluing three services. Shared connection, auth and state — in a single core.

Three services in one

Most stacks bolt together a pub/sub broker, a REST framework and an agent runtime — three deploys, three auth surfaces, three failure modes. mtwRequest collapses all three into a single Rust core.

Three separate services
  • →NATS / Centrifugo for pub/sub
  • →Express / Fastify for HTTP
  • →Separate agent framework for AI
  • →Three deployments, three auth surfaces
  • →Hand-written glue for state sync
One mtwRequest core
  • ✓WebSocket + HTTP share the same connection
  • ✓AI agents are first-class modules
  • ✓One auth, one state, one tracing surface
  • ✓Module marketplace for composition
  • ✓Apache-2.0 — fork it, ship it

Head-to-head benchmarks

Same-host, Docker 2 CPU / 2 GB per competitor, payload 128 B, HdrHistogram 3 sig figs.

Reproducible runner in bench-suite/.

Scenario mtwRequest vs leaders
🥈 Fanout 100 subs · p50 17.53 ms tied with NATS (16.97 ms)
🥇 Fanout 1000 subs · p50 197.53 ms 1.5× faster than NATS (299.63 ms)
🥇 Fanout 1000 subs · p99 367.79 ms better than NATS (554.70 ms)
🥈 Echo RTT · p50 62.2 µs tied with NATS (Δ 3.8 µs)
🥇 Connect storm · rate 50.9 k conn/s 2.7× more than NATS

mtwRequest places 🥇 or 🥈 on every latency metric — while also bundling HTTP, AI agents, auth, trading and MCP in the same core.

Where NATS wins

NATS still leads on raw broadcast throughput on fanout-1000: 2.66 G/s vs mtwRequest's 506 M/s (5.2× more). That's a structural ceiling of TCP-without-WebSocket — a deliberate trade-off we make to keep the protocol browser-compatible. If your hot path is server-to-server only, NATS is the right call.

Charts from the latest run

Distribution plots over mtw, nats, centrifugo and socketio. Generated by the bench-suite — same artifact you'd get locally.

Fanout latency

1 publisher → N subscribers · 100 and 1000 subs · 128 B payload

SVG
Fanout latency benchmark chart

Echo round-trip

Requester → echo bot → requester · 2,000 round-trips

SVG
Echo round-trip benchmark chart

Connect storm

500 concurrent connection opens · per-connect latency + rate

SVG
Connect storm benchmark chart

Run bench-suite/run.sh in the repo to reproduce on your own host.

What's in the core

Not a stitched-together broker. A single runtime with batteries included.

One runtime, not three

pub/sub + REST + AI agents share connection, auth and state. Stop gluing NATS + Express + a separate agent framework.

Dual wire format

JSON by default for interop. MsgPack opt-in via the mtw.msgpack.v1 subprotocol — p99 distribution 4.7× tighter, ~50% fewer bytes.

Composable modules

A MtwModule trait with lifecycle hooks, prioritised middleware, glob-matched pub/sub channels and history. Install via the marketplace.

Observability built-in

Structured tracing, per-module health checks, HdrHistogram metrics in the bench-suite. Production wiring ships with the core.

Multi-language bindings

Native bindings for Node.js, Python and PHP. Browser via WebAssembly. Same wire protocol across every client.

Glob pub/sub + history

Subscribe with patterns like orders.eu.*. Channels carry replayable history; new subscribers can catch up.

Two views of the same runtime

Subscribe from a browser. Compose a server-side module. Same connection, same auth.

Browser WebSocket + MsgPack subprotocol
client.ts
const ws = new WebSocket('wss://api.example.com/mtw', 'mtw.msgpack.v1');

ws.onopen = () => {
  ws.send(JSON.stringify({
    "type": "subscribe",
    "channel": "orders.eu.*"
  }));
};

ws.onmessage = (msg) => {
  const evt = JSON.parse(msg.data);
  console.log('event', evt.channel, evt.payload);
};
Rust MtwModule trait
price_feed.rs
use mtw_request::{MtwModule, Context, Result};

pub struct PriceFeed;

#[async_trait]
impl MtwModule for PriceFeed {
  fn name(&self) -> &str { "price-feed" }

  async fn on_start(&self, ctx: &Context) -> Result<()> {
    ctx.subscribe("ticker.*").await?;
    Ok(())
  }

  async fn on_message(&self, ctx: &Context, m: Message) -> Result<()> {
    ctx.publish("alerts", m.payload).await
  }
}

Bindings for every client

Same wire protocol. Same auth. Different language at the edge.

Node.js

Shipped

Python

Shipped

PHP

Shipped

Browser (WASM)

Roadmap

When mtwRequest, when not

Honest defaults. Pick the right tool for your hot path.

Pick mtwRequest if…

  • • You need WebSocket + HTTP + AI agents in one runtime
  • • Tail latency on browser-facing fanout is your SLA
  • • You want module composition, not a frozen broker
  • • You want auth, MCP and trading in the same core (in roadmap / shipped)

Pick NATS if…

  • • Your hot path is server-to-server TCP, no browsers
  • • You need 1 G/s+ raw broadcast throughput
  • • You already run a JetStream cluster you trust
  • • You don't need HTTP or AI agents in the same process

Built on

Boring foundations. Predictable behaviour.

Rust Tokio tokio-tungstenite ArcSwap MsgPack HdrHistogram WebAssembly Apache-2.0

Frequently Asked Questions

How does mtwRequest differ from NATS or Centrifugo?
Most alternatives are narrow pub/sub engines. mtwRequest bundles WebSocket, HTTP and AI agents in the same Rust core, with shared connection, auth and state — so you don't glue three services together. NATS still wins on raw broadcast throughput (1.20 G/s vs 124 M/s on fanout-500); that's a structural ceiling of TCP-without-WS and a deliberate trade-off for browser compatibility.
Are the benchmarks reproducible?
Yes. Same-host runs in Docker with 2 CPU and 2 GB per competitor, 128 B payload, HdrHistogram at 3 significant figures. The runner lives in bench-suite/ in the repo. Don't extrapolate to distributed production — the suite is for head-to-head comparison.
JSON or MsgPack — which should I use?
JSON is the default for interop. Opt into MsgPack via the mtw.msgpack.v1 subprotocol when the tail matters: p50 drops 17.5% and the p99 distribution is 4.7× tighter. Wire size is ~50% smaller. Use it when you have an SLA on tail latency.
What language bindings are available?
Node.js, Python and PHP are shipped today. The browser binding compiles the core to WebAssembly and is on the roadmap. All bindings speak the same wire protocol and authenticate against the same connection.
Is there a module marketplace?
Yes. The MtwModule trait, lifecycle hooks and middleware system are shipped. The public registry is on the roadmap — see ARCHITECTURE.md for the current state.
License and support?
Apache-2.0. Source on GitHub at fastslack/mtwRequest. Commercial support available — book a consult if you want production help.

Reproduce the bench, fork the core

Apache-2.0. The runner is in the repo. If you want production help, book a consult.