Skip to main content

MLPal Gateway

One API for every model provider.
Anthropic, OpenAI, Google, and AWS Bedrock ship built in; new providers are an adapter away.
Self-hosted. Model routing, per-request cost metering, per-key access control, admin console.

PyPI License CI Python


Gateway console


Quick start

cp .env.oss.example .env      # add whichever provider keys you have
docker compose up             # Postgres + Redis + gateway + admin console
Gateway http://localhost:8000 — Swagger at /docs
Admin console http://localhost:8080
Bootstrap admin key printed once: docker compose logs seed

Adapters activate based on which provider keys you set. GET /v1/models lists only what your box can serve; a single-provider deployment works without any extra configuration.

Don't want to run infrastructure? The managed deployment of this same codebase runs at mlpal.ai — create a key and point the same SDK/CLI at https://models.mlpal.ai instead of localhost. Pricing is simple: routing is free for your first 300M tokens each month, then $50 flat per month up to 5B tokens; your tokens are always billed at provider list price, passed through with no markup, either way.

Prebuilt multi-arch images are on GHCR if you'd rather not build from source: ghcr.io/mlpal-ai/mlpal-gateway and ghcr.io/mlpal-ai/mlpal-gateway-console (tags: latest, version, commit SHA).

Calling it

Anthropic wire, any provider's model:

curl http://localhost:8000/v1/messages \
  -H "Authorization: Bearer $MLPAL_KEY" -H "content-type: application/json" \
  -d '{"model":"mlpal","max_tokens":512,"messages":[{"role":"user","content":"hi"}]}'

Existing OpenAI SDK code — point it at http://localhost:8000/v1. Python SDK — pip install mlpal-assistants:

from mlpal_assistants import MLPal

client = MLPal(base_url="http://localhost:8000")   # key from MLPAL_API_KEY
msg = client.messages.create(
    model="mlpal", max_tokens=512,
    messages=[{"role": "user", "content": "Hello"}],
)
print(msg.text, msg.compute_units)

What you get

  • One wire format for every provider. POST /v1/messages speaks the Anthropic Messages format for all served models; the gateway translates to each provider's native API and relays the SSE stream without re-chunking. OpenAI-compatible endpoints (/v1/chat/completions, embeddings, images, audio) serve existing OpenAI SDK code unchanged.
  • Router tags. "model": "mlpal" resolves to the best model your deployment serves, walking a curated candidate list that spans providers. Model retired? Provider key missing? Resolution falls through to the next candidate. Client code never changes.
  • Cost on every response. Requests are metered in compute units (1 CU = $10 of provider list price, no markup) and returned in an X-MLPal-Compute-Units header. The meter reproduces provider list pricing exactly, including prompt-cache discounts.
  • Per-key control. Model-policy globs (allow: ["claude-*"]), multi-window spend budgets, permissions — all enforced at admission, before the provider call. A running stream is never cut.
  • Observability. Per-key cache hit rate, latency p50/p95, time-to-first-token, request traces, and optional payload capture (zlib-compressed, runtime toggle — your box, your data).
  • Provider semantics preserved. Prompt caching (cache_control), tools, structured output, and MCP config pass through untouched.
  • Catalog that keeps itself current (opt-in, free). By default your box ships with the bundled model catalog, frozen at this version — fully functional offline, zero calls home. Subscribe to the hosted feed (Models page, or MLPAL_CATALOG_FEED=hosted) and the gateway pulls the curated catalog daily — new models appear and retired ones are absorbed with no upgrade. Subscribing requires a free mlpal.ai account key purely as identity — we recommend a dedicated key with no permissions (it can authenticate the feed and nothing else; feed pulls are never billed). See Telemetry.

Measured

Gateway overhead isolated against a zero-latency fake upstream, so provider variance can't hide anything — MLPal with its full admission pipeline (auth, rate limit, billing, model policy, budgets, metering, capture) against LiteLLM in both its bare mode and a production configuration with database-backed virtual keys, budgets, and spend tracking (N=100 per system; methodology in the technical report, raw data and harness in paper/bench/):

Gateway overhead benchmark

+8.5 ms with everything on — less than a bare proxy checks one static key for, and with the tightest tail (p95 33 ms vs 58/41 ms). Admission-time governance is computationally free. Provider semantics survive the hop too: a 22k-token cached prefix passes through byte-faithfully and metered 0.002756 CU on write, 0.000224 CU on read (12.3×) — matching Anthropic's list price to five decimals. The managed deployment of this same codebase, measured the same night from the same client, served claude-haiku-4.5 at 642 ms median TTFT vs OpenRouter's 898 ms (report §5.3–5.4).

Why a curated catalog

Production models retire on roughly a 12-month cycle now — from the providers' own deprecation ledgers:

Model launch-to-retirement spans

Serving a model well — valid parameter ranges, per-model cache minimums, reasoning budgets, provider quirks — is per-model engineering that does not scale to a 1,600-entry catalog. This gateway serves a curated set (~75 models) kept current by a data feed, and router tags absorb every retirement above server-side. You can always pin any explicit model tag or register your own adapter.

The full argument with benchmarks and sources: Curation Over Breadth · feature matrix vs. OpenRouter / LiteLLM / Portkey: docs/POSITIONING.md.

Router tags vs. catalog

Two ways to use the curated set — they differ in who picks the model:

Router tags — mlpal, mlpal-flash, mlpal-lite Catalog — GET /v1/catalog
Who decides The gateway: tag resolves to the best served model for the operation Your client: a ranked list with tiers, capabilities, per-token rates
Use when You want a good default and zero model-name maintenance You are writing routing logic (agents route sub-tasks this way)
One-provider box Falls through to whatever your key serves Unserved candidates are marked

Both are driven by the same feed (catalog/*.json) and update as data, not code.

API surface

Endpoint Purpose
POST /v1/messages Anthropic-wire inference, all providers, streaming SSE
POST /v1/chat/completions OpenAI-compatible chat
/v1/embeddings · /v1/images/generations · /v1/audio/* OpenAI-compatible modalities
GET /v1/models Models this deployment serves
GET /v1/catalog Ranked catalog: tiers, capabilities, rates
POST /v1/feedback Outcome feedback for routing scores
GET /v1/usage/* · /v1/keys/* Self-scoped usage, traces, per-key stats
/admin/v1/* Keys, policies, budgets, capture, routing

Details: docs/API_SURFACE.md.

Use it with a coding agent

Yodex is a coding CLI built on this gateway — it speaks the Anthropic wire and uses GET /v1/catalog to route sub-tasks to cheaper models (~10× lower sub-agent cost in its benchmarks):

npm install -g @mlpal/yodex
export YODEX_GATEWAY_URL=http://localhost:8000
export YODEX_API_KEY=mlpal_sk_...    # minted in the console
yodex "fix the failing test"

Repository layout

src/                 # FastAPI gateway: adapters, services, api, seams
console/             # admin UI (React + Vite): keys, traces, catalog, usage
docker-compose.yaml  # one-command local deployment
alembic/             # database migrations
paper/               # technical report + benchmark harness + raw results
enterprise/          # commercial add-ons (separate license, NOT Apache)
docs/                # API surface, positioning, figures

Auth and billing sit behind composition-root seams (api/mounting.py); the defaults (MLPAL_AUTH_BACKEND=local, MLPAL_BILLING_BACKEND=local) run fully standalone with no external dependencies. src/ never imports from enterprise/.

Telemetry

None by default. If you opt in to the hosted catalog feed, each daily pull sends exactly three things to models.mlpal.ai: the mlpal.ai API key you subscribed with (identity — links the install to your account), a random per-install UUID, and your gateway version. Feed pulls are free and never metered. No provider keys, no payloads, no usage data, ever. Stay in bundled mode (the default) and the gateway makes zero calls home.

License and contact

Apache-2.0, except the enterprise/ directory (commercial — see enterprise/LICENSE). Contributions welcome: CONTRIBUTING.md · security and everything else: contact@mlpal.ai

Metadata

Release files for mlpal-gateway 0.2.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mlpal-gateway 0.2.4
File Size Uploaded
mlpal_gateway-0.2.4.tar.gz 1.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for mlpal-gateway 0.2.4
File Interpreter ABI Platform
mlpal_gateway-0.2.4-py3-none-any.whl Python 3 none any Details

Total release size: 1.6 MB

Release files / mlpal_gateway-0.2.4.tar.gz

Download URL mlpal_gateway-0.2.4.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
3ebb3e36393a4c8fe0dfced6007d348b3b514665f8a8f8bb424f92ee86402d98
BLAKE2b-256 checksum
How to use checksums
cfefde96678c05064f082f4e624c2f9992ce23e22c2362b00c5fecb1c6fbabda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.9

Release files / mlpal_gateway-0.2.4-py3-none-any.whl

Download URL mlpal_gateway-0.2.4-py3-none-any.whl
Size 325.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5a45bd2d420a136c692aa1a25f1b5dbc25137fdab66a65f5439b3109ded5dd7
BLAKE2b-256 checksum
How to use checksums
9d0aee6cd73ec3150098377609bb4f8e8f481f6fef7264e4219a9fc2b2ed8c3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.9

Release history Release notifications | RSS feed

0.2.5

2 release files

This release

0.2.4 This release

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page