# Mcpdeck

> Intelligent MCP (Model Context Protocol) router that selects tools via embeddings, semantic search, and RAG over a Qdrant vector database. Python · FastAPI · Qdrant · Docker.

- **Type:** MCP server
- **Install:** `agentstack add mcp-anirudhlath-mcpdeck`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [anirudhlath](https://agentstack.voostack.com/s/anirudhlath)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [anirudhlath](https://github.com/anirudhlath)
- **Source:** https://github.com/anirudhlath/mcpdeck

## Install

```sh
agentstack add mcp-anirudhlath-mcpdeck
```

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

## About

# Meta MCP

[](https://github.com/anirudhlath/meta-mcp/actions/workflows/ci.yml)

An intelligent MCP (Model Context Protocol) router. Meta MCP spawns your child
MCP servers, embeds their tools, and exposes them to an MCP client through a
single connection — either proxying every tool directly (namespaced) or, via
the `find_tools` meta-tool, letting the client ask "what tool should I use for
X?" and get back the most relevant ones instead of the whole list.

There are two ways to run it:

- **`meta-mcp serve`** — an MCP server over stdio for Claude Desktop / Claude
  Code (or any MCP client). This is the integration most people want.
- **`meta-mcp start`** — a standalone dashboard/router process with a Gradio
  web UI, useful for development, debugging tool selection, and inspecting
  child-server health outside of an MCP client.

Not on PyPI: the `meta-mcp` name is squatted there, so installation is
git-based via `uvx`/`uv tool install` as shown below.

## Prerequisites

- **Python 3.11+**
- **[uv](https://docs.astral.sh/uv/getting-started/installation/)** — provides
  the `uvx` and `uv` commands used throughout this README. If you only have
  `pipx`, run `pipx install uv` to get `uvx`.
- **Docker or [Apple Container](https://github.com/apple/container)** (macOS
  Apple Silicon) — needed to run Qdrant, which backs vector-based tool
  selection. Optional if you only ever use `--no-setup` against an
  already-running Qdrant, or don't need tool-selection routing at all.
- **[LM Studio](https://lmstudio.ai/)** (optional) — for local embeddings and
  LLM-based tool selection. Without it, Meta MCP falls back to a bundled
  `sentence-transformers` model automatically.

## Use with Claude Desktop / Claude Code

This is the `meta-mcp serve` path: an MCP server over stdio that exposes every
child tool as `{server}__{tool}` plus a `find_tools` meta-tool. `stdout` is
reserved for the JSON-RPC protocol — all logs and human-readable output go to
stderr, so this is safe to run under any MCP client's process supervisor.

Add to your MCP client config (Claude Desktop's
`claude_desktop_config.json`, or Claude Code's `.mcp.json`):

```json
{
  "mcpServers": {
    "meta-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/anirudhlath/meta-mcp",
        "meta-mcp",
        "serve",
        "--mcp-servers-json",
        "/absolute/path/to/mcp-servers.json"
      ]
    }
  }
}
```

`mcp-servers.json` uses the same `mcpServers` shape Claude Desktop itself
uses, so you can point `--mcp-servers-json` at your existing Claude Desktop
config to re-expose the same child servers through Meta MCP's tool-selection
layer:

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"]
    }
  }
}
```

Working from a local checkout instead of git+https (e.g. while developing)?
Point `uv run --project` at it instead of `uvx`:

```json
{
  "mcpServers": {
    "meta-mcp": {
      "command": "uv",
      "args": [
        "run",
        "--project",
        "/path/to/meta-mcp",
        "meta-mcp",
        "serve",
        "--mcp-servers-json",
        "/absolute/path/to/mcp-servers.json"
      ]
    }
  }
}
```

`serve` supports `--setup` (default `--no-setup`) if you want it to also
detect/start a container runtime and Qdrant before serving — see
`meta-mcp serve --help`. Restart Claude Desktop / Claude Code after editing
the config.

The Gradio web UI is **disabled on the `serve` path** even if your config sets
`web_ui.enabled: true` — Gradio's `launch()` prints to stdout, which would
corrupt the JSON-RPC channel. Use `meta-mcp start` when you want the dashboard.

### `find_tools` and tool namespacing

Every child tool is published under `{server_name}__{tool_name}` (dots aren't
legal in MCP tool names, so `server.tool` becomes `server__tool`; any other
disallowed character is replaced with `-`, and the name is truncated to the
MCP-mandated 64 characters). Call these directly like any other MCP tool.

`find_tools` is a built-in meta-tool, always listed first, that runs Meta
MCP's intelligent selection (vector / LLM / RAG, depending on config and what
initialized successfully) against a natural-language query:

```json
{"name": "find_tools", "arguments": {"query": "read a file from disk", "max_results": 5}}
```

It returns a JSON list of `{"name": ..., "description": ..., "server": ...}`
for the most relevant tools, which you then call directly by their namespaced
name. This is the main point of Meta MCP: instead of a client seeing every
tool from every child server at once, it can ask for just the ones relevant
to the current task.

## Quick Start (dashboard mode)

Run the dashboard/router (`start`) straight from this repository with `uvx`:

```bash
# Automatic setup: detects Docker/Apple Container, starts Qdrant, opens the
# web UI on http://localhost:8080
uvx --from git+https://github.com/anirudhlath/meta-mcp meta-mcp

# With explicit config
uvx --from git+https://github.com/anirudhlath/meta-mcp meta-mcp \
    --config my-config.yaml --mcp-servers-json my-servers.json

# Or install it as a persistent CLI tool
uv tool install git+https://github.com/anirudhlath/meta-mcp
meta-mcp
```

Running `meta-mcp` with no arguments (or with top-level flags like
`--config`/`--web-ui`, with no subcommand) runs `start`. On startup it will:

- Detect and set up a container runtime (Docker or Apple Container Framework)
- Start the Qdrant vector database (unless `--no-setup`)
- Auto-detect an existing `mcp-servers.json` or Claude Desktop config in
  standard locations (read-only — it does **not** write or modify your Claude
  Desktop config)
- Start the Meta MCP server with the web UI at `http://localhost:8080`

## Architecture

```mermaid
flowchart TD
    subgraph Server["Meta MCP server"]
        Engine["Routing engine(primary strategy + fallback)"]
        Vector["Vector search router"]
        LLM["LLM router"]
        RAG["RAG router"]
        Pipeline["RAG pipeline(doc chunking + retrieval)"]
        Emb["Embedding service"]
        Manager["Child server manager"]
        Engine --> Vector
        Engine --> LLM
        Engine --> RAG
        RAG --> Pipeline
        Vector --> Emb
        Pipeline --> Emb
        Engine -->|selected tools / proxied calls| Manager
    end

    Client["MCP client(Claude Desktop / Claude Code)"] -->|"MCP over stdio(meta-mcp serve)"| Engine

    Vector --> Qdrant[("Qdranttool + doc embeddings")]
    Pipeline --> Qdrant
    Emb -->|primary| LMS["LM Studioembeddings + local LLM"]
    Emb -.->|fallback| ST["sentence-transformers(local model)"]
    LLM --> LMS
    Pipeline --> LMS

    Manager --> C1["Child MCP server(e.g. filesystem)"]
    Manager --> C2["Child MCP server(e.g. github)"]
    Manager --> C3["Child MCP server(...)"]
```

Main components (all under `src/meta_mcp/`):

- **North-bound MCP server** (`server/mcp_stdio.py`): the `meta-mcp serve`
  entry point — wraps `MetaMCPServer` in the MCP stdio protocol, publishes
  `{server}__{tool}` names, and provides `find_tools`
- **Server core** (`server/meta_server.py`): initializes and owns every other
  component; resilient startup means a failed embedding/vector-store/LLM/RAG
  component is logged as a warning and left `None` rather than crashing —
  child tools are still exposed even with no Qdrant/LM Studio running
- **Routing strategies** (`routing/`): vector search (`vector_router.py`),
  LLM selection (`llm_router.py`), and RAG-based selection (`rag_router.py`)
- **RAG pipeline** (`rag/pipeline.py`): chunks and indexes child-server
  documentation, retrieves relevant context, and augments selection queries
- **Embedding service** (`embeddings/service.py`): LM Studio embeddings when
  available, with automatic sentence-transformers fallback and local caching
- **Vector store** (`vector_store/qdrant_client.py`): Qdrant-based storage and
  similarity search for tool and documentation embeddings
- **Child server manager** (`child_servers/`): spawns and manages the
  lifecycle of downstream MCP servers and proxies tool calls to them
- **Web interface** (`web_ui/`): Gradio-based real-time monitoring and
  configuration dashboard (`start` only; not used by `serve`)
- **Health / auto-setup** (`health/`): infrastructure detection, health
  checks, and automatic Docker/Apple Container + Qdrant setup

## Features

### Intelligent Tool Selection
- **Vector Search** (default): fast semantic similarity using embeddings
- **LLM Selection**: AI-powered tool selection using a local LLM (LM Studio)
- **RAG-Based Selection**: context-augmented selection using retrieved
  child-server documentation

### Automatic Setup (`start` / `--setup`)
- Container runtime detection: Apple Container Framework on Apple Silicon
  macOS, or Docker elsewhere
- Starts Qdrant automatically
- Auto-detects an existing `mcp-servers.json` or Claude Desktop config

### Web Dashboard (`start` only)
- Real-time server monitoring and logs
- Interactive configuration editor
- Tool usage analytics and metrics
- Child server status monitoring
- Optional HTTP basic auth (`web_ui.auth_enabled` + `username`/`password`;
  fails closed — the UI refuses to start if enabled without both credentials)

## Configuration

### Auto-Detection

`meta-mcp start` (and bare `meta-mcp`) looks for configuration files in these
locations when `--config`/`--mcp-servers-json` aren't given:

**Main Config (meta-server.yaml):**
- `./config/meta-server.yaml`
- `./meta-server.yaml`
- `~/.meta-mcp/config.yaml`
- `/etc/meta-mcp/config.yaml`

**MCP Servers Config (JSON), read-only — never written to:**
- `./mcp-servers.json`
- `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
- `~/.config/claude/claude_desktop_config.json` (Linux/Windows)
- `~/.claude/claude_desktop_config.json`

`meta-mcp serve` does not auto-detect a Claude Desktop `mcp-servers.json`
(pass `--mcp-servers-json` explicitly — see the Claude Desktop/Code section
above), but when `--config` is omitted it still searches the same main-config
locations as `start`, in order: `./config/meta-server.yaml`,
`./meta-server.yaml`, `~/.meta-mcp/config.yaml`, `/etc/meta-mcp/config.yaml`
(falling back to built-in defaults if none exist).

### Creating Custom Config

`mcp-servers.json` (Claude Desktop format):

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"]
    },
    "fetch": {
      "command": "uvx",
      "args": ["mcp-server-fetch"]
    }
  }
}
```

`meta-server.yaml` (every field is real and validated — unknown fields are
rejected; see `examples/simple-config.yaml` and `examples/advanced-config.yaml`
for complete, working examples):

```yaml
strategy:
  primary: "vector"      # vector, llm, or rag
  fallback: "vector"     # fallback strategy
  vector_threshold: 0.4  # similarity threshold
  max_tools: 10          # max tools to return

web_ui:
  enabled: true
  port: 8080
  auth_enabled: false    # set true + username/password for basic auth

embeddings:
  # Primary: LM Studio (optional). Canonical endpoint form ends in /v1 —
  # /v1/ and /v1/embeddings are also accepted and normalized.
  lm_studio_endpoint: "http://localhost:1234/v1"
  lm_studio_model: "nomic-embed-text-v1.5"

  # Fallback: local sentence-transformers model (automatic)
  fallback_model: "all-MiniLM-L6-v2"

vector_store:
  type: "qdrant"
  host: "localhost"
  port: 6333
```

Validate any config file before relying on it:

```bash
uv run meta-mcp validate-config path/to/meta-server.yaml
```

## Commands

```
meta-mcp [OPTIONS] COMMAND [ARGS]...
```

Running `meta-mcp` with no subcommand, or with a top-level flag (e.g.
`meta-mcp --config x.yaml --web-ui`), routes to `start`.

| Command | Purpose |
|---|---|
| `serve` | Run the MCP server over stdio for Claude Desktop/Code (see above) |
| `start` | Dashboard/full-stack mode with auto-setup + web UI (default command) |
| `run` | Start the server without auto-setup or config auto-detection |
| `validate-config FILE` | Validate a configuration file |
| `list-strategies` | List available tool-selection strategies |
| `debug-vector` | Run a test query against the vector search index |
| `regenerate-embeddings` | Recompute tool embeddings (`--force` to clear and rebuild) |
| `init-config` | Write a default `meta-server.yaml` |
| `health` | Check system health and dependencies |

Every command supports `--help` for its exact flags, e.g.
`meta-mcp serve --help`. When running via `uvx`, prefix these with
`uvx --from git+https://github.com/anirudhlath/meta-mcp`.

### `health`

```bash
uv run meta-mcp health                    # text output, exits non-zero on issues
uv run meta-mcp health --output-format json
uv run meta-mcp health --fix --setup-docker --download-models
```

## Docker

`docker-compose.yml` runs Qdrant plus the `meta-mcp` dashboard service
(built from the repo `Dockerfile`, using `config/docker.yaml` which binds the
web UI to `0.0.0.0:8080` and points `vector_store.host` at the `qdrant`
service):

```bash
docker-compose up -d
# Web UI: http://localhost:8080
# Qdrant: http://localhost:6333/collections
```

The container's `CMD` is `meta-mcp start --no-setup --config
/app/config/docker.yaml` (Qdrant is provided by compose, so setup is skipped);
its `HEALTHCHECK` curls `http://localhost:8080/` (the Gradio dashboard root —
there is no `/health` HTTP endpoint).

For running Qdrant via Apple's container framework instead of Docker, see
[`docs/apple-container-setup.md`](docs/apple-container-setup.md).

## Development

```bash
git clone https://github.com/anirudhlath/meta-mcp.git
cd meta-mcp

uv sync --extra dev
uv run pre-commit install

uv run pytest
uv run ruff check src/ tests/
uv run ruff format src/ tests/
uv run mypy src/
# or all at once:
./scripts/check-all.sh

# Run the stdio server against a local checkout:
uv run meta-mcp serve --no-setup --mcp-servers-json path/to/mcp-servers.json --log-level DEBUG

# Run dashboard mode against a local checkout:
uv run meta-mcp start --log-level DEBUG
```

Tests are marked `unit`, `integration` (may spawn real subprocesses; no
Docker/Qdrant required — resilient init is exercised directly), and `slow`.

## Troubleshooting

**Qdrant connection failed**
```bash
curl http://localhost:6333/collections
uv run meta-mcp health --setup-docker
```

**Upgrading from before v0.2.0**: vector-store point IDs and embedding cache
keys changed (the old scheme used a per-process salted hash that produced
duplicate points on every restart). Run this once after upgrading:
```bash
uv run meta-mcp regenerate-embeddings --force
```

**No MCP servers found**: create an `mcp-servers.json` file, or point
`--mcp-servers-json` at an existing Claude Desktop config.

**Web UI not accessible**: check the port isn't already in use
(`lsof -i :8080`) or pick another with `--port`.

**LM Studio not being used**: confirm the endpoint responds at
`http://localhost:1234/v1/models`, and that `lm_studio_endpoint` is set (it's
`null`/unset by default — the fallback `sentence-transformers` model is used
unless you configure it explicitly).

Logs: stderr in `serve` mode; `./logs/meta-server.log` and the web UI's log
viewer in `start`/`run` mode (path from `logging.file` in your config).

## Security Considerations

- Run child servers with minimal privileges
- Use environment variables for sensitive configuration (`${VAR}` expansion
  in child-server `env` blocks)
- Review child server configurations before use
- Enable `web_ui.auth_enabled` (+ `username`/`password`) if the dashboard is
  reachable beyond localhost

## Contributing

1. Fork the repository and clone your fork
2. `uv sync --extra dev && uv run pre-commit install`
3. Create a feature branch, make your changes with tests (pre-commit runs
   Ruff format/lint and mypy on commit)
4. `./scripts/check-all.sh` before opening a PR

## License

…

## Source & license

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

- **Author:** [anirudhlath](https://github.com/anirudhlath)
- **Source:** [anirudhlath/mcpdeck](https://github.com/anirudhlath/mcpdeck)
- **License:** MIT

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:** no
- **Environment & secrets:** no
- **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-anirudhlath-mcpdeck
- Seller: https://agentstack.voostack.com/s/anirudhlath
- 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%.
