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.
- →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
- ✓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.
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
Echo round-trip
Requester → echo bot → requester · 2,000 round-trips
Connect storm
500 concurrent connection opens · per-connect latency + rate
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.
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); };
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
ShippedPython
ShippedPHP
ShippedBrowser (WASM)
RoadmapWhen 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.
Frequently Asked Questions
How does mtwRequest differ from NATS or Centrifugo?
Are the benchmarks reproducible?
JSON or MsgPack — which should I use?
What language bindings are available?
Is there a module marketplace?
License and support?
Reproduce the bench, fork the core
Apache-2.0. The runner is in the repo. If you want production help, book a consult.