# Adaptora

> Self-hosted Dynamic API Agent with an MCP layer — talk to any REST API in natural language. Bring-your-own-LLM (Ollama).

- **Type:** MCP server
- **Install:** `agentstack add mcp-guptayush02-adaptora`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [guptayush02](https://agentstack.voostack.com/s/guptayush02)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [guptayush02](https://github.com/guptayush02)
- **Source:** https://github.com/guptayush02/adaptora
- **Website:** https://www.linkedin.com/company/113237472/admin/page-posts/published/

## Install

```sh
agentstack add mcp-guptayush02-adaptora
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Adaptora

A self-hosted Dynamic API Agent with an MCP (Model Context Protocol) layer on top. Talk to any REST API in natural language — the agent discovers the docs, handles auth, plans the HTTP call, and executes it. Plug it into Claude Desktop, Cursor, Cline, n8n, or any MCP-compatible client to give your AI assistant access to **every API you can describe**.

> Bring-your-own-LLM. Runs locally with [Ollama](https://ollama.com) (default: `qwen2.5-coder:3b`). Optional Anthropic/OpenAI keys for tougher queries. No SaaS dependencies.

  
  
  
  
  

---

## Demo

https://github.com/user-attachments/assets/62dad55a-a0a3-46d8-a689-bca21e9007db

*Setting up a tool in Adaptora and running it on the Docker stack — plays right here on GitHub.* ▶️ **[Watch in HD on YouTube](https://youtu.be/BoGareRAZJk)**

```
> "list my open GitHub issues assigned to me"

[agent] identifying tool... github
[agent] loading docs... 122 endpoints cached
[agent] planning action... GET /issues?filter=assigned&state=open
[agent] executing...
[agent] You have 7 open issues. Top 3:
        1. #482 — Bug: cache invalidation race  (opened 2 days ago)
        2. #481 — Doc fetcher should support YAML specs
        3. #475 — Streaming endpoint for /tools/refresh
```

---

## Why Adaptora?

Connecting an LLM to real APIs usually breaks on the unglamorous parts: hunting
down docs, wiring up auth, hand-writing a JSON schema for every endpoint, and
one malformed argument silently killing the call. Adaptora owns that boundary
for you — point it at any API and it discovers the docs, stores your credentials
encrypted, turns every endpoint into a typed tool, and runs it from plain
language through **MCP, a REST API, or the web UI**.

---

## Key Features

- **Dynamic Tool Discovery** — Type a tool name (`github`, `stripe`, `shopify`, `notion`, …) or describe what you want to do, and the agent fetches its docs, OpenAPI spec, and rate limits automatically. Curated seed tools (github, aws, stripe, slack, notion, openai, razorpay, linear, gmail) ship pre-configured.
- **Multi-source doc fetching** — Web search + OpenAPI spec probing (24+ URL patterns) + native parsing + LLM extraction, merged with method/path deduplication. Refreshing `github` grows from 5 → 120+ endpoints; AWS uses local `boto3` introspection for 49+.
- **MCP Server** — Exposes the agent over the Model Context Protocol. Every connected tool's endpoints become typed MCP tools your AI assistant can call directly.
- **REST API + developer keys** — Mint a secret key on the dashboard and call Adaptora from any project in any language (`POST /api/v1/run` with `Authorization: Bearer adp_live_…`). Every call runs against your saved connections and is logged, tagged by key and tool, on the dashboard. A streaming variant (`POST /api/v1/run/stream`, Server-Sent Events) emits each pipeline step as it happens so you can render the agent's progress live in your own UI.
- **Live execution logs** — The dashboard **Logs** page tails every run from every source (Web UI, MCP, and `/api/v1`) in real time over SSE. In-flight runs appear as a live row at the top of the table that updates step-by-step, then settle into the completed-run history once done.
- **Authenticated chat UI** — React frontend with per-user encrypted credential storage (AES), conversation history, streaming SSE responses, and a "Cached Tools" page with live refresh progress.
- **Token tracking & caching** — Tracks every model call, caches identical prompts, routes simple queries to local Ollama and complex ones to Claude/GPT (optional).
- **One-command Docker deploy** — 3-container stack (app, Postgres, Redis) wired with healthchecks and persistent volumes; the LLM (Ollama) runs natively on the host so it can use your GPU.

---

## Quick Start

### Option 1 — Docker (recommended)

The app, Postgres and Redis run in containers. **The LLM (Ollama) runs natively on your host** — on macOS the Apple GPU can't be passed into Docker, so a containerised Ollama would be CPU-only and very slow (~100 s per call for 7b). Running Ollama on the host lets it use your GPU.

```bash
git clone https://github.com/guptayush02/adaptora.git
cd adaptora

# 1. Set up the LLM locally (on the host, not in Docker)
#    Install Ollama from https://ollama.com/download (or `brew install ollama`)
ollama serve &                     # start the daemon (uses your GPU)
ollama pull qwen2.5-coder:7b       # or qwen2.5-coder:3b for a smaller/faster one

# 2. Configure — point the app at your local model
cp .env.docker.example .env.docker
#    .env.docker already sets, and is the single source of truth for, both:
#      OLLAMA_MODEL=qwen2.5-coder:7b
#      OLLAMA_API_URL=http://host.docker.internal:11434   # container → host Ollama
#    Also set SECRET_KEY. Make sure OLLAMA_MODEL matches the model you pulled.

# 3. Bring up the stack (app + db + cache)
docker compose --env-file .env.docker up --build

# 4. Open the web UI
open http://localhost:8000
```

> **`host.docker.internal`** is how a container reaches a service on the Mac/Windows host. Keep `ollama serve` running on the host whenever you use the stack.

> **No Ollama container by default.** The `ollama` service sits behind the `with-ollama` compose profile, so `docker compose up -d --build` builds and starts **only** `app`, `db` and `cache` — it never builds or launches an Ollama container. The container is opt-in via `--profile with-ollama` (see below).

#### Running Ollama inside Docker instead (Linux / NVIDIA hosts)

On a Linux host with an NVIDIA GPU, a container *can* use the GPU. To run everything in one stack, point the app at the container service and enable the optional profile:

```bash
# in .env.docker:
#   OLLAMA_API_URL=http://ollama:11434
docker compose --env-file .env.docker --profile with-ollama up --build
```

For GPU passthrough, install the [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) and uncomment the `deploy.resources.devices` block on the `ollama` service in [docker-compose.yml](./docker-compose.yml).

### Option 2 — Local (no Docker)

Useful for development. You'll need Python 3.11+, Node 18+, Ollama, and Redis running on your host.

```bash
# Backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

# Install the headless browser used to render JS-heavy doc sites (one-time).
# Docker does this automatically; for a local install you must run it yourself,
# or doc rendering fails with "Executable doesn't exist … run playwright install".
playwright install chromium

# Pull the LLM
ollama pull qwen2.5-coder:3b

# Frontend
cd frontend && npm install && npm run build && cd ..

# Configure
cp .env.example .env   # edit OLLAMA_API_URL, REDIS_URL, etc.

# Run (DB auto-initialises on first start)
python -m uvicorn main:app --host 0.0.0.0 --port 8000
# open http://localhost:8000
```

---

## Using the MCP Server

The MCP server runs as a subprocess that any MCP client can talk to over JSON-RPC stdio — your AI assistant launches `python mcp_server.py`.

> **Important — the MCP server must talk to the *same* database as your web UI.** It reads credentials/connections by user, so if the two point at different databases, you'll see `User not found` and tools won't connect. Pick the launch style that matches how you run Adaptora:
>
> - **Running the full stack with Docker Compose?** The app stores everything in the Postgres container, *not* in a local `token_optimizer.db`. Launch the MCP server **inside the running container** with `docker exec` so it inherits the container's `DATABASE_URL`/`SECRET_KEY`. See [Docker stack](#quickest-path--claude-desktop-docker-stack) below.
> - **Running locally (no Docker)?** Launch host `python mcp_server.py` directly — it uses the same local SQLite DB the app does. See [Local install](#quickest-path--claude-desktop-local-install) below.
>
> A host `python mcp_server.py` started while the stack runs in Docker defaults to an empty local SQLite DB — that mismatch is the #1 cause of `User not found`.

### What you get

| Always-on meta-tools | What it does |
|---|---|
| `setup_new_tool` | Discover docs for any tool (web search → OpenAPI probe → LLM extract → merge) and seed it |
| `refresh_tool_docs` | Re-fetch the latest docs (equivalent to the UI's Refresh button) |
| `list_known_tools` | Every cached tool with endpoint counts |
| `list_connections` | Which tools you've authenticated |
| `run_action` | Natural-language dispatch through the full Dynamic Agent pipeline |

**Plus dynamic per-endpoint tools**: every endpoint of every connected tool becomes its own MCP tool with a typed input schema (`github_list_repos`, `stripe_create_charge`, etc.). Newly connected tools appear automatically — no restart required.

### Setup for various clients

Full step-by-step configs for 8+ clients are in [docs/MCP_CLIENTS.md](./docs/MCP_CLIENTS.md):

- **Claude Desktop** (macOS / Windows)
- **Claude Code** (Anthropic CLI)
- **Cursor** (IDE)
- **Cline** (VS Code extension)
- **Continue.dev** (VS Code / JetBrains)
- **Zed** (editor)
- **n8n / make.com** (workflow automation)
- **Custom Python / TypeScript clients**

Config file location:
- macOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

> On macOS, quote the path if you `cat`/`cp` it — it contains a space (`Application Support`). Unquoted, the shell splits it into two paths and reads/writes the wrong file.

#### Quickest path — Claude Desktop (Docker stack)

Use this when you brought the stack up with `docker compose up`. The MCP server runs **inside** the `adaptora-app` container, so it automatically inherits the same Postgres `DATABASE_URL` and `SECRET_KEY` as the web app — you only pass your email.

```jsonc
{
  "mcpServers": {
    "adaptora": {
      "command": "/usr/local/bin/docker",
      "args": [
        "exec", "-i",
        "-e", "MCP_USER_EMAIL=you@example.com",
        "adaptora-app",
        "python", "mcp_server.py"
      ]
    }
  }
}
```

Prerequisites: the `adaptora-app` container must be running (`docker ps`), and `MCP_USER_EMAIL` must match an email that exists in the Postgres DB:

```bash
docker exec -i adaptora-db psql -U tokopt -d tokopt -c "SELECT id, email FROM users;"
```

#### Adaptora running on a remote server (VPS / cloud) — connect over SSH

The configs above launch the MCP server on your **own computer**. But if you've
deployed Adaptora on a remote machine (a DigitalOcean droplet, an AWS EC2
instance, a Hetzner VPS, your office server…), your AI assistant still runs on
your laptop — and it can't reach the server's database directly. Launching a
**local** `mcp_server.py` would talk to an empty local database and fail with
`User not found`.

The fix: tell your assistant to start the MCP server **on the remote machine,
over SSH**. SSH is the standard, secure way to run a command on another
computer; it carries the MCP messages back and forth over the same encrypted
connection your assistant already needs. No code changes, no extra ports to
open — if you can `ssh` into the box, this works.

```jsonc
{
  "mcpServers": {
    "adaptora": {
      "command": "ssh",
      "args": [
        "user@your-server.com",
        "docker", "exec", "-i",
        "-e", "MCP_USER_EMAIL=you@example.com",
        "adaptora-app",
        "python", "mcp_server.py"
      ]
    }
  }
}
```

**What is `user@your-server.com`?** It's the exact same thing you type to log
into your server with SSH — `ssh user@your-server.com` — split into two parts:

| Part | What it means | Examples |
|---|---|---|
| `user` (before the `@`) | Your **login username** on the server | `ubuntu` (common on AWS), `root`, `ayush` |
| `your-server.com` (after the `@`) | The server's **address** — its domain name *or* its public IP address | `adaptora.mycompany.com`, `203.0.113.42` |

So if you log into your server with `ssh ubuntu@203.0.113.42`, then you'd write
`"ubuntu@203.0.113.42"` on that first line. Don't copy `user@your-server.com`
literally — replace it with your real values.

**Before this works, check three things:**

1. **You can SSH in without typing a password.** Your assistant runs `ssh`
   unattended, so it can't answer a password prompt. Set up key-based login
   ([GitHub's SSH key guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)
   works for any server) and confirm `ssh user@your-server.com` logs you in
   with no prompt.
2. **The `adaptora-app` container is running on the server.** SSH in and run
   `docker ps` — you should see `adaptora-app`.
3. **`MCP_USER_EMAIL` matches a real account.** Check on the server with the
   `psql` command shown just above.

> Not using Docker on the server? Replace the `docker exec …` part with the
> path to the remote Python and script, e.g.
> `"user@your-server.com", "/path/to/adaptora/venv/bin/python", "/path/to/adaptora/mcp_server.py"`,
> and move `MCP_USER_EMAIL` into an SSH-set env var or the command itself.

#### Quickest path — Claude Desktop (local install)

Use this when you run Adaptora directly on your host (no Docker) — the server shares the app's local SQLite DB.

```jsonc
{
  "mcpServers": {
    "adaptora": {
      "command": "/ABSOLUTE/PATH/TO/adaptora/venv/bin/python",
      "args": ["/ABSOLUTE/PATH/TO/adaptora/mcp_server.py"],
      "env": { "MCP_USER_EMAIL": "you@example.com" }
    }
  }
}
```

Restart Claude Desktop. The hammer icon now lists `setup_new_tool`, `run_action`, and every connected tool's endpoints.

### Quickest path — Claude Code (CLI)

```bash
# Find which email your web-UI account uses
/ABSOLUTE/PATH/TO/adaptora/venv/bin/python \
  /ABSOLUTE/PATH/TO/adaptora/mcp_server.py --list-users

# Register the server
claude mcp add adaptora \
  --scope user \
  --transport stdio \
  --env MCP_USER_EMAIL=you@example.com \
  -- \
  /ABSOLUTE/PATH/TO/adaptora/venv/bin/python \
  /ABSOLUTE/PATH/TO/adaptora/mcp_server.py
```

Verify:
```bash
claude mcp list
# adaptora: … - ✓ Connected
```

Start a session:
```bash
claude
> /mcp                              # confirms adaptora is listed
> List my open GitHub issues        # → calls run_action under the hood
> Set up shopify with the Admin API # → calls setup_new_tool
> Refresh the docs for stripe       # → calls refresh_tool_docs
```

---

## Using the REST API (developer keys)

Want to call Adaptora from your own app — a backend service, a script, a cron
job — instead of an MCP client? Mint a **developer secret key** on the dashboard
and hit the public REST API. The key authenticates as you, so every call runs
against the tools you've already connected.

### 1. Create a key

In the web UI, open **Developer Keys** in the sidebar → **New key** → give it a
name (e.g. `production-backend`). The secret (`adp_live_…`) is shown **once** —
copy it now; only its hash is stored, so it can never be retrieved again. Revoke
a key anytime from the same page (calls using it immediately start returning
`401`).

### 2. Call `POST /api/v1/run`

Send your prompt with the key as a bearer token. The agent identifies the right
service, plans the call, executes it against your saved credentials, and returns
the result:

```bash
curl -X POST http://localhost:8000/api/v1/run \
  -H "Authorization: Bearer adp_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "list my open github issues"}'
```

```python
# Python
import requests

resp = requests.post(
    "http://localhost:8000/api/v1/run",
    headers={"Authorization": "Bearer adp_live_YOUR_KEY"},
    json={"prompt": "list my open github issues"},
)
print(resp.json())
```

```javascript
// Node.js (fetch)
const resp = await fetch("http://localhost:8000/api/v1/run", {
  method: "POST",
  headers: {
    "Authorization": "Bearer adp_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.string

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [guptayush02](https://github.com/guptayush02)
- **Source:** [guptayush02/adaptora](https://github.com/guptayush02/adaptora)
- **License:** MIT
- **Homepage:** https://www.linkedin.com/company/113237472/admin/page-posts/published/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-guptayush02-adaptora
- Seller: https://agentstack.voostack.com/s/guptayush02
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
