TL;DR
mlx_lm.server .
On a MacBook Pro M5 Max with 128 GB, Qwen3.6-35B-A3B generates 107 tokens per second on a coding prompt under mlx_lm.server and 271 tokens per second under mlx-serve with its MTP head. Both runs use 4-bit MLX weights. The model stays the same; the server and the speculative-decoding setup change.
Measured on 19 October 2026. Servers in this space ship releases every few weeks, so these numbers describe one snapshot.
mlx_lm.server 0.32.2 (Apple's reference), vllm-mlx 0.5.0, Rapid-MLX 0.16.1, dflash-mlx (August 2026 main branch) and mlx-serve 26.10.2.
Without speculation, three of four servers land at 87 to 109 tok/s. mlx_lm.server , vllm-mlx and Rapid-MLX produce the same speed within noise.
mlx-serve runs at 188 to 217 tok/s without any speculation. A wall-clock check with prompt-lookup drafting also disabled gave 216 tok/s against 118 for mlx_lm.server . Its log reports fused Metal kernels for MoE routing and the MLP layers. mlx-serve is written in Zig on MLX's C API, with no Python in the decode loop.
MTP adds 25% to 150%, depending on server and workload. Qwen models ship a multi-token-prediction head, a small extra layer that drafts the next few tokens for the main model to verify in one pass. Rapid-MLX attaches it automatically and goes from 96 to 240 tok/s on code. mlx-serve with its own MTP build goes from 217 to 271 on code and from 188 to 273 on the long prompt.
Code benefits most. Drafted tokens are accepted more often when output is predictable. dflash-mlx accepted 72% of drafted tokens on the code task and 65% on prose, and its speed followed: 210 against 142 tok/s.

Rapid-MLX with a DFlash drafter is fastest on two of three workloads , at 166 tok/s on code and 144 on the long prompt. DFlash is a block-diffusion drafter trained for one specific target model.
mlx-serve is fastest on prose, at 135 tok/s, and slowest on the long prompt. Its drafters gave no gain on this model. mlx-serve disables drafters for MoE targets by default; forced on, DFlash had low acceptance and switched itself off, and the Gemma assistant drafter dropped code speed from 136 to 82 tok/s. The long-prompt runs on mlx-serve stopped after 72 tokens, so those three figures carry more noise than the rest.

Four clients keep the same ranking and narrow the gaps. For Qwen3.6-35B-A3B, four simultaneous 400-token coding requests produced 412 tok/s in total on mlx-serve with MTP, 320 on Rapid-MLX with MTP, 280 on Rapid-MLX without speculation and 249 on vllm-mlx with continuous batching. Each request used a distinct prompt, and I recounted output tokens from the returned text.
Batching gains shrink as single-request speed rises. In the same test, vllm-mlx went from 86 tok/s for one request to 249 for four (2.9×); mlx-serve went from 282 to 412 (1.5×). Single-request figures here include prompt processing. A likely reason: when one request already keeps the GPU busy, batching has less idle time to fill.
Gemma 4 26B-A4B barely gains from batching on either server. Four requests produced 150 tok/s in total on Rapid-MLX with DFlash (146 for one) and 132 on mlx-serve (127 for one).

On the same server with no speculation, Qwen3.8-27B (dense) generates about 31 tok/s and Qwen3.6-35B-A3B (MoE) about 105. Token generation on Apple silicon is limited by memory bandwidth: a dense model reads all 27B weights per token, and the MoE model reads its 3B active parameters plus routing. The dense model is the newer release and may give better answers; this test measured speed only.
mlx_lm.server (about 110 tok/s). OptiQ-4bit ran at about 83, because it keeps some layers at higher precision.Tested on macOS 26.6 with an M5 Max and 128 GB. Each model's 4-bit weights take about 21 GB of disk and the same in memory. Keep the Mac on AC power while testing; generation on battery was markedly slower in these runs.
mlx-serve needs macOS 26.2 or later on Apple silicon.
brew tap ddalcu/mlx-serve <https://github.com/ddalcu/mlx-serve> brew trust ddalcu/mlx-serve brew install mlx-serve
brew trust lets this third-party tap install and update without prompting. brew untap ddalcu/mlx-serve removes it.
Download the 4-bit build that bundles the MTP draft head (about 21 GB), then serve it:
hf download ddalcu/Qwen3.6-35B-A3B-MLX-Serve-4bit mlx-serve --host 127.0.0.1 --model ~/.cache/huggingface/hub/models--ddalcu--Qwen3.6-35B-A3B-MLX-Serve-4bit/snapshots/*/
hf comes with pip install -U huggingface_hub . Without --host 127.0.0.1 , mlx-serve listens on every network interface.
The server exposes an OpenAI-compatible API on port 11234. List the model id, then send a request:
curl -s <http://127.0.0.1:11234/v1/models> curl -s <http://127.0.0.1:11234/v1/chat/completions> -H 'Content-Type: application/json' \ -d '{"model": "MODEL_ID_FROM_ABOVE", "messages": [{"role": "user", "content": "Write a Python LRU cache with tests."}], "max_tokens": 512}'
Rapid-MLX installs commands named vllm-mlx , so it goes in its own virtual environment to avoid clashing with an existing vllm-mlx install:
uv venv -p 3.12 ~/.venvs/rapid-mlx VIRTUAL_ENV=~/.venvs/rapid-mlx uv pip install 'rapid-mlx==0.16.1'
Qwen3.6-35B-A3B with its MTP head (the head downloads automatically):
~/.venvs/rapid-mlx/bin/vllm-mlx serve mlx-community/Qwen3.6-35B-A3B-4bit \ --speculative-config '{"method":"mtp","num_speculative_tokens":3}' --host 127.0.0.1 --port 8000
Gemma 4 26B-A4B with a DFlash drafter:
~/.venvs/rapid-mlx/bin/vllm-mlx serve lmstudio-community/gemma-4-26B-A4B-it-QAT-MLX-4bit \ --speculative-config '{"method":"dflash","model":"z-lab/gemma-4-26B-A4B-it-DFlash"}' --host 127.0.0.1 --port 8000
Both serve an OpenAI-compatible API at http://127.0.0.1:8000/v1 . Any OpenAI client works by setting its base URL to that address.