Relay — Local AI Gateway as an MCP Server

I wanted to use my local models (Ollama, vLLM) with tools that only speak OpenAI or Anthropic API formats — Claude Code, OpenCode, Cursor, and custom agents. Running LiteLLM felt overkill. So I built Relay: a single Go binary (~12 MB, static) that bridges any local backend to the API formats your tools already speak.

Relay is a local AI gateway that exposes endpoints compatible with OpenAI Chat Completions and Anthropic Messages while connecting to your local models.


Architecture

                       ┌──────────────────────┐
  curl ─┐              │                      │
  opencode ─┤          │        relay         ├──→ Ollama
  Claude Code ─┤       │   (local AI gateway) │──→ OpenAI-compat (vLLM/LiteLLM)
  Cursor ─┘            │                      │──→ CLI agent (claude/opencode)
                       └──────────────────────┘

The idea is simple: a network-level adapter that sits between your tools and your models. No config files needed to get started, no Python runtime, no containers.


Key Features

Dual-Protocol API

Single binary serves both API formats:

ProtocolEndpointExample
OpenAIPOST /api/v1/chat/completionsWorks with any OpenAI SDK
OpenAI (legacy)POST /api/v1/generateSimplified generation
AnthropicPOST /v1/messagesAnthropic Messages API
ModelsGET /api/v1/modelsList available models
HealthGET /api/v1/healthNo auth required

Interchangeable Backends

BackendUse Case
ollamaLocal models via Ollama API
openai-compatvLLM, LiteLLM, or any OpenAI-compatible server
claudeUse your claude CLI subscription as a backend
opencodeUse OpenCode CLI as a backend
echoTesting backend — always replies with ECHO: <message>

MCP Server Mode

Relay also exposes 5 MCP tools via stdio:

  • generate_key, revoke_key, list_keys — API key management
  • list_models — query available backends
  • health — check server status

Perfect for agents that need to spin up a local inference endpoint dynamically.

Streaming SSE

Real-time streaming for both OpenAI SSE and Anthropic SSE event formats.


Tech Stack

ComponentChoiceWhy
LanguageGo 1.26+Single static binary, no runtime deps
API Servernet/http + gorilla/muxStandard, well-tested
ConfigYAML + CLI flagsQuick overrides without editing files
AuthAuto-generated API keysZero-config security
Persistence~/.localmcp/keys.jsonKeys survive restarts
Size~12 MB static binaryNo Python, no Node, no containers
TestsGo test suiteCore API and backend tests

Quick Start

git clone https://github.com/fxckcode/relay.git
cd relay
make build
./bin/localmcp

That’s it. The API key auto-generates on first run. Default listen is 127.0.0.1:8080.

# Test it
KEY=$(./bin/localmcp --show-key)
curl -X POST http://127.0.0.1:8080/api/v1/chat/completions \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"echo","messages":[{"role":"user","content":"Hello"}]}'

The echo backend replies immediately — perfect for testing. With Ollama running, switch to "model":"llama3.2".

Why Not LiteLLM / Ollama Built-in?

LiteLLM is a full Python project with heavy dependencies. Relay is a single Go binary — no pip install, no virtualenv, no Python version management. It also adds the CLI agent backend (use your claude CLI subscription as an API), which neither LiteLLM nor Ollama can do.

Ollama’s built-in OpenAI compatibility is solid but limited to Ollama models. Relay chains to any backend.


The project is MIT licensed and open on GitHub. Contributions welcome.

Share
D
Diego Duran
@fxckcode

Backend engineer who ships agentic CLI tooling. NestJS, Go, Django, AWS.

Relay — Gateway de IA Local como Servidor MCP

Quería usar mis modelos locales (Ollama, vLLM) con herramientas que solo hablan los formatos de API de OpenAI o Anthropic — Claude Code, OpenCode, Cursor y agentes personalizados. Ejecutar LiteLLM me parecía excesivo. Así que construí Relay: un solo binario Go (~12 MB, estático) que conecta cualquier backend local con los formatos de API que tus herramientas ya entienden.

Relay es un gateway de IA local que expone endpoints compatibles con OpenAI Chat Completions y Anthropic Messages mientras se conecta a tus modelos locales.


Arquitectura

                       ┌──────────────────────┐
  curl ─┐              │                      │
  opencode ─┤          │        relay         ├──→ Ollama
  Claude Code ─┤       │   (gateway IA local) │──→ OpenAI-compat (vLLM/LiteLLM)
  Cursor ─┘            │                      │──→ CLI agent (claude/opencode)
                       └──────────────────────┘

La idea es simple: un adaptador a nivel de red que se sienta entre tus herramientas y tus modelos. Sin necesidad de archivos de configuración para empezar, sin runtime Python, sin contenedores.


Características Clave

API de Protocolo Dual

Un solo binario sirve ambos formatos de API:

ProtocoloEndpointEjemplo
OpenAIPOST /api/v1/chat/completionsFunciona con cualquier SDK OpenAI
OpenAI (legacy)POST /api/v1/generateGeneración simplificada
AnthropicPOST /v1/messagesAnthropic Messages API
ModelosGET /api/v1/modelsLista modelos disponibles
HealthGET /api/v1/healthSin autenticación

Backends Intercambiables

BackendCaso de Uso
ollamaModelos locales vía API de Ollama
openai-compatvLLM, LiteLLM o cualquier servidor compatible con OpenAI
claudeUsa tu suscripción de claude CLI como backend
opencodeUsa OpenCode CLI como backend
echoBackend de prueba — siempre responde ECHO: <mensaje>

Modo Servidor MCP

Relay también expone 5 herramientas MCP via stdio:

  • generate_key, revoke_key, list_keys — gestión de API keys
  • list_models — consulta backends disponibles
  • health — estado del servidor

Perfecto para agentes que necesitan levantar un endpoint de inferencia local dinámicamente.

Streaming SSE

Streaming en tiempo real compatible con formatos de eventos SSE de OpenAI y Anthropic.


Stack Tecnológico

ComponenteElecciónPor qué
LenguajeGo 1.26+Binario estático único, sin deps de runtime
Servidor APInet/http + gorilla/muxEstándar, bien probado
ConfigYAML + flags CLIOverrides rápidos sin editar archivos
AuthAPI keys auto-generadasSeguridad zero-config
Persistencia~/.localmcp/keys.jsonKeys sobreviven reinicios
Tamaño~12 MB binario estáticoSin Python, sin Node, sin contenedores
TestsGo test suiteTests de API core y backends

Inicio Rápido

git clone https://github.com/fxckcode/relay.git
cd relay
make build
./bin/localmcp

Eso es todo. La API key se auto-genera en el primer inicio. Default escucha en 127.0.0.1:8080.

# Probarlo
KEY=$(./bin/localmcp --show-key)
curl -X POST http://127.0.0.1:8080/api/v1/chat/completions \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"echo","messages":[{"role":"user","content":"Hola"}]}'

El backend echo responde inmediatamente — perfecto para probar. Con Ollama corriendo, usa "model":"llama3.2".

¿Por Qué no LiteLLM / Ollama?

LiteLLM es un proyecto Python completo con dependencias pesadas. Relay es un solo binario Go — sin pip install, sin virtualenv, sin gestión de versiones de Python. Además añade el backend CLI agent (usa tu suscripción de claude CLI como API), que ni LiteLLM ni Ollama pueden hacer.

La compatibilidad con OpenAI de Ollama es sólida pero limitada a modelos de Ollama. Relay se encadena a cualquier backend.


El proyecto tiene licencia MIT y está abierto en GitHub. Contribuciones bienvenidas.

Compartir
D
Diego Duran
@fxckcode

Ingeniero backend que construye herramientas CLI agentivas. NestJS, Go, Django, AWS.