Skip to main content
Glama
schniggie

openapi-anything

by schniggie

openapi-anything

CI

Agentic system that, given a natural language request describing "anything" to connect, writes/tests/deploys live code for a REST API wrapper around the target.

Goal

  • Input: Free-form NL description (e.g. "wrap the CLI from this github repo into a REST API", "expose this web-only online service via proper REST API")

  • Output: Unique deployed FastAPI service instance serving correct auto-generated openapi.json at /services/{id}/openapi.json

  • Consuming agents fetch the openapi.json and use the REST endpoints to interact with the wrapped target.

  • Full web hub + central API gateway proxying to isolated per-wrapper Docker containers.

Related MCP server: swaggbot

Quickstart

# Install
pip install -e .

# Generate a wrapper (CLI) — runs the full pipeline + deploys
openapi-anything generate "wrap the ls command as a REST API"

# Undeploy a wrapper (stops+removes its container and image)
openapi-anything delete <wrapper_id>

# Run the hub/gateway
openapi-anything serve

# Or with the compose stack (Podman or Docker)
podman compose up --build      # or: docker compose up --build

The compose stack exposes the gateway on http://localhost:8800 (host port 8800 maps to container port 8000). Visit the hub UI in your browser.

API

The gateway serves both an HTML hub and a JSON API for agent clients:

Method

Path

Body

Purpose

POST

/api/generate

{"description": "...", "wrapper_id": "...", "secrets": {"ENV": "val"}}

JSON async generate+deploy: returns 202 {"job_id", "poll"} immediately. secrets become wrapper env vars (values never enter generated code/LLM prompts/registry — names only)

GET

/jobs/{job_id}

Poll a generation job (status + live phase + result)

GET

/jobs

List generation jobs (newest first)

POST

/jobs/{job_id}/cancel

Cancel a queued/running job (409 if finished)

GET

/services/{id}/_logs?tail=100

Wrapper container logs (gateway meta route, not proxied)

GET

/services/{id}/_source

Generated app.py of the wrapper

POST

/services/{id}/_regenerate

{"description": "..."} (optional)

Re-run the pipeline for an existing wrapper (409 while a job is active); previous verification feeds the new design

POST

/mcp

JSON-RPC

MCP server (Streamable HTTP): every wrapper's endpoints as tools + list_apis/generate_api/regenerate_api/job_status meta tools

POST

/services/{id}/mcp

JSON-RPC

MCP server scoped to one wrapper (no meta tools)

POST

/generate

form: description, wrapper_id

Hub form generate — starts a job, hub auto-refreshes (returns HTML)

GET

/

Hub UI

GET

/registry

List deployed wrappers

GET

/metrics

Per-wrapper traffic: requests, errors, avg latency, last used

GET

/services/{id}/openapi.json

Wrapper's OpenAPI spec (proxied)

GET/POST/...

/services/{id}/{path}

Reverse-proxy to the wrapper container

DELETE

/services/{id}

Undeploy a wrapper (container+image removed)

POST

/services/{id}/delete

Hub-friendly undeploy (browsers can't DELETE)

Note: POST /generate is form-encoded for the browser hub; agents should use the JSON /api/generate endpoint. They intentionally live on distinct paths. Generation is asynchronous: both endpoints return immediately and the pipeline runs in the background — agents poll GET /jobs/{job_id} until status is completed (result includes openapi_path) or failed (includes error).

MCP (Model Context Protocol)

Agents can skip OpenAPI parsing entirely and connect via MCP:

claude mcp add --transport http openapi-anything http://localhost:8800/mcp

Every deployed wrapper's endpoints appear as tools ({wrapper_id}__{method}_{path}), alongside meta tools: list_apis, generate_api (submit a new wrapper build, get a job_id), and job_status. An agent can literally ask for a new API and use its tools once the job completes. Tool schemas are derived live from each wrapper's openapi.json (cached MCP_SPEC_TTL s).

Architecture

Podman users: podman compose up --build (or podman-compose). The DockerManager auto-detects the Podman socket; no docker.sock mount needed.

  • Central gateway (openapi_anything.gateway):

    • Proxies /services/{wrapper_id}/* → the correct backend container.

    • Provides POST /api/generate (JSON) + POST /generate (hub form) and the web hub UI.

    • Runs generation asynchronously as in-memory jobs (GET /jobs, GET /jobs/{id}); the hub shows a jobs table and auto-refreshes while jobs are active.

    • Manages wrapper lifecycle: DELETE /services/{id} undeploys.

  • Generator pipeline (openapi_anything.generator, LLM-driven via LiteLLM/GLM-5.1):

    1. Inspect target (git, subprocess, http + LLM analysis), enriched with web research via a SearxNG instance (SEARXNG_BASE_URL, default https://searxng.schnigg.ie; JSON API required). Results flow into both the inspection analysis and the design prompt; search outages degrade gracefully.

    2. Design REST API — the LLM produces title, description, endpoints, Pydantic models, and per-endpoint handler bodies.

    3. Generate code — a deterministic assembler turns the design into a complete app.py. The whole design is consumed (title/description/models/endpoints are never hardcoded by the generator).

    4. Test — generated pytest smoke (health + openapi).

    5. Fix loop — on failure, errors are fed back to the LLM and the app is regenerated (up to 5 retries), with a deterministic safe fallback that always works.

    6. Build + deploy — per-wrapper Docker image + container on a free port.

    7. Verify — pre-deploy (TestClient health/openapi) and post-deploy (live health + openapi + every designed endpoint exercised); the report is persisted into the registry entry.

  • Tech: Python + FastAPI (auto OpenAPI), Docker SDK, httpx, openai (LiteLLM), pytest, Jinja2.

Example NL Requests

  • "wrap the ls command as a REST API"

  • "make a REST wrapper for httpbin.org that exposes /get /post"

  • "wrap the todo web app at example.com/todos into CRUD REST endpoints"

Each produces a distinct service with its own openapi.json usable by agents.

Auth

Opt-in: unset GATEWAY_API_KEY (default) and the gateway is fully open, as before. Set it and admin routes require credentials — hub UI, generate/regenerate, jobs, delete, /registry, /metrics, /services/{id}/_logs, /services/{id}/_source, and the gateway-wide /mcp (which carries generate_api/regenerate_api).

Two ways to authenticate:

  • X-API-Key: <key> header — for API/MCP clients (curl, agents).

  • HTTP Basic auth, any username, the key as the password — browsers prompt for this natively when you open the hub; no login page needed.

Deployed-wrapper traffic is never gated, even with a key set: the /services/{id}/* proxy and a wrapper's own /services/{id}/mcp stay open, so other systems/agents can use a generated API without holding the gateway's admin key. /health is also always open (container health probes).

Configuration

All knobs are environment variables (set them in docker-compose.yml or a .env file; values are read at runtime, not import time):

Variable

Default

Purpose

LITELLM_BASE_URL

https://litellm.xn--8pr.xyz/v1

OpenAI-compatible LLM proxy

LITELLM_API_KEY

(required, no default)

Proxy API key — set via .env, never commit it

LLM_MODEL

GLM-5.2

Model id (must match proxy /v1/models)

LLM_REQUEST_TIMEOUT

120

Per-request timeout (s)

LLM_JSON_MAX_TOKENS

8000

JSON-mode budget — reasoning models burn hidden thinking tokens against it

SEARXNG_BASE_URL

https://searxng.schnigg.ie

SearxNG instance for inspector web research (JSON API)

SEARXNG_TIMEOUT

10

Search request timeout (s)

SEARXNG_MAX_RESULTS

5

Research hits fed into inspection/design

PIPELINE_MAX_RETRIES

5

LLM fix-loop attempts before the safe fallback

WRAPPER_OUTPUT_BASE

/tmp/openapi-anything-wrappers

Generated wrapper code directory

PROXY_TIMEOUT

30

Gateway → wrapper proxy timeout (s)

MCP_SPEC_TTL

30

Seconds MCP tool schemas are cached per wrapper

GATEWAY_API_KEY

unset (open)

Opt-in auth for admin routes — see ## Auth below

REDIS_URL

unset (in-memory)

Job persistence backend; compose sets redis://redis:6379/0. History survives restarts; interrupted jobs are marked failed

JOBS_HISTORY_MAX

200

Terminal jobs kept in history before pruning oldest

METRICS_FLUSH_INTERVAL

30

Seconds between metric flushes to redis

HEALTH_SWEEP_INTERVAL

30

Seconds between registry health sweeps

HEALTH_PROBE_TIMEOUT

2

Per-wrapper /health probe timeout (s)

GATEWAY_PROXY_HOST

127.0.0.1

Host wrappers are reachable on from the gateway

DOCKER_HOST

podman socket autodetect

Container runtime socket

Development

python -m pytest tests/ -v
ruff check .

(Full pipeline implementation per plan phases.)

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/schniggie/openapi-anything'

If you have feedback or need assistance with the MCP directory API, please join our Discord server