LLMs Technical Reviews

Klavis-AI/klavis

Apache-2.0 monorepo of ~100 self-hostable MCP servers plus Strata, an MCP router that hides them behind five meta-tools.

GitHub ↗★ 5.8kPythonApache-2.0commit 45c9f7d · 2026-06-01homepage ↗

Overview

Klavis is a monorepo of Model Context Protocol (MCP) servers and the tooling around them. It is not one service with a database. It is a set of independent parts that share a repository: about 100 MCP server directories under mcp_servers/ (Gmail, GitHub, Slack, Notion, Salesforce, Jira and others), a router called Strata (open-strata/, published to PyPI as strata-mcp), a Docker layer that gets OAuth tokens for those servers, and a set of chat bots (mcp-clients/) that connect Slack, Discord, WhatsApp and a web UI to MCP servers.

The main idea is in Strata. When an agent connects to many MCP servers, the full tool list can grow to hundreds of schemas. Strata does not show them. It shows five fixed meta-tools: discover actions, get action details, execute action, search documentation, and handle auth failure. The agent finds a tool with BM25 search and then calls it through the router. Use Klavis if you want MCP servers that you can run yourself, or one MCP endpoint in front of many servers. Do not use it if you need a multi-tenant credential store. The open code does not have one: the managed OAuth flow and the hosted SDK backend are at api.klavis.ai.

Architecture

flowchart LR
  A["Agent / IDE"] -->|"MCP stdio or HTTP"| S["Strata router"]
  S --> T["5 meta-tools (tools.py)"]
  T --> B["BM25 search"]
  T --> M["MCPClientManager"]
  M -->|"stdio"| L["Local MCP server process"]
  M -->|"HTTP / SSE"| R["Remote MCP server"]
  R --> X["Third-party API"]
  L --> X
  C["servers.json"] -.->|"watched"| M
  W["OAuth wrapper image"] -->|"AUTH_DATA"| R
  W -->|"create instance, poll"| K["api.klavis.ai"]
Component Path Role
Strata server open-strata/src/strata/server.py MCP server over stdio, SSE or streamable HTTP. It exposes only the meta-tools.
Meta-tools open-strata/src/strata/tools.py Tool schemas and the execute_tool dispatcher
Client manager open-strata/src/strata/mcp_client_manager.py Connects to each configured server and re-syncs when the config changes
Config open-strata/src/strata/config.py MCPServerConfig dataclass, servers.json loader, file watcher
Search open-strata/src/strata/utils/shared_search.py, bm25_search.py Field-weighted BM25 over tool names and descriptions
OAuth client open-strata/src/strata/mcp_proxy/auth_provider.py MCP-SDK OAuth provider with a localhost callback and token files
MCP servers mcp_servers/<name>/ One server per integration, each with its own Dockerfile
OAuth layer _oauth_support/ Wraps a server image. It fetches AUTH_DATA from the Klavis API before start-up.
Chat clients mcp-clients/src/mcp_clients/ Slack, Discord, WhatsApp and web bots that use MCP servers through an LLM
SDK codegen fern/ Fern config that builds Python and TS SDKs from the hosted API’s OpenAPI spec

How a request flows

  1. strata run (or strata run --port N) calls run_stdio_server or run_server (cli.py). In HTTP mode, Starlette mounts /sse, /messages/ and a stateless /mcp (server.py).
  2. config_watching_context calls initialize_from_config. This connects every enabled server from servers.json. Then it starts a watchgod watcher, which calls sync_with_config when the file changes (server.py, mcp_client_manager.py).
  3. _connect_server builds an HTTPTransport (for sse/http) or a StdioTransport (for a command) and opens an MCP ClientSession (mcp_client_manager.py).
  4. The agent calls list_tools. It receives the five meta-tools, and their server_names enum lists the connected servers (server.py, tools.py).
  5. discover_server_actions gets each server’s tool list (cached in MCPClient._tools_cache). Then it ranks the tools with UniversalToolSearcher and returns only the action names (tools.py). get_action_details returns one tool’s inputSchema.
  6. execute_action parses path_params, query_params and body_schema from JSON strings, merges them into one flat argument dict and calls client.call_tool (tools.py).
  7. MCPClient.call_tool sends the call to the downstream session. If the result has isError, it raises RuntimeError. The dispatcher catches the error and returns it as JSON text (client.py).
  8. The downstream server (for example Airtable) reads its token from AUTH_DATA or from a base64 x-auth-data header, puts it in a ContextVar and calls the vendor API (airtable/server.py).

Key components

Strata router

Strata is about 3,000 lines of Python. It has no database. Its only state is the in-memory client map and the config file. Search uses bm25s with a stemmer. Each field (server name, tool name, description, parameters) is indexed as a separate document and gets a weight (shared_search.py). strata tool add writes the router into the MCP config of Cursor, VS Code, Claude Code or Gemini CLI (utils/tool_integration.py).

MCP servers

Each directory in mcp_servers/ is its own project. Most are Python or TypeScript, and a few are Go (github, and forks such as github_official and slack_atlas). There is no shared manifest or base class. A Python server registers @app.list_tools() and @app.call_tool() on a low-level MCP Server. Then it dispatches on the tool name in a long if/elif chain (airtable/server.py), and serves SSE and streamable HTTP from the same app (L711-L752). The repo also has several benchmark variants (*_toolathlon, *_mcpmark, *_atlas), so the number of separate SaaS products is smaller than the number of directories.

Auth

There are two separate paths. Server images: CI builds an -oauth variant from Dockerfile.template. Its entrypoint sources oauth_acquire.sh. This script creates an instance at api.klavis.ai, prints the OAuth URL and polls until authData arrives. Then the wrapper writes the result to .env. This flow needs a KLAVIS_API_KEY. Strata: a server with auth: "oauth" gets an MCP-SDK OAuthClientProvider with dynamic client registration, a callback on localhost:3030, and tokens saved as plaintext JSON under .tokens/<server>/tokens.json relative to the working directory (auth_provider.py, L160-L199).

Chat clients

mcp-clients gives one MCPClient to all the bots. It converts MCP tools to Anthropic or OpenAI tool formats (mcp_client.py). For each call, it finds the server that owns the tool and sends a progress message every 30 seconds while the call runs (L331-L386). The production path (USE_PRODUCTION_DB=true) imports mcp_clients.database, but that package is an empty directory at this SHA. Self-hosters get the local path, which reads local_mcp_servers.json (base_bot.py).

Extending it

  • New integration: add mcp_servers/<name>/ with a server and a Dockerfile (see MCP_SERVER_GUIDE.md). To build an OAuth image, add the name to _oauth_support/server_name.json. The mcp-servers-build.yml workflow builds only the changed servers.
  • New server in Strata: run strata add or edit servers.json. The fields are type, url/command, headers, env, auth and enabled (config.py). A running router picks up the change by itself.
  • Framework examples: examples/ has small integrations for LangChain, LlamaIndex, CrewAI, Mastra, Google ADK, OpenAI and others. These call the hosted Klavis SDK.

Running it

  • Router: pip install strata-mcp, then strata add ..., then strata run (stdio) or strata run --port 8080. Config lives at ~/.config/strata/servers.json (from platformdirs).
  • A single server: build its Dockerfile from the repo root, or run the published GHCR image. Pass the token with AUTH_DATA or the x-auth-data header. You can also use the -oauth image with KLAVIS_API_KEY.
  • Bots: use the Dockerfile.slack, .discord, .web or .whatsapp file in mcp-clients/. Each needs LLM API keys and server URLs.

Strengths and caveats

  • Strength: Strata keeps the agent’s tool list at five, however many servers sit behind it, and it works with any MCP server, not only Klavis servers.
  • Strength: each integration is a normal, separate MCP server that runs without the router.
  • Caveat: handle_auth_failure is a stub. save_auth_data returns “success” but stores nothing (tools.py).
  • Caveat: the router has no retries or rate limits, and it sets no timeout for a tool call. Tool lists stay cached until a reconnect. Each server handles pagination and errors in its own way.
  • Caveat: execute_action merges path, query and body params into one dict, so a key that appears in two of them is overwritten.
  • Caveat: strata run --config-path only sets MCP_CONFIG_PATH. The router’s global MCPClientManager is created at import time with the default path, and no code reads that variable.
  • Caveat: the OAuth image depends on the hosted Klavis API. In oauth_acquire.sh, the timeout check reads $? after rm, so it never sees the timeout’s exit code, and the message says 5 minutes while the limit is 600 s.
  • Caveat: the code has no multi-tenant credential store, encryption at rest, scheduled sync or webhook triggers. Those features are in the hosted product, if anywhere.

Sources: code at 45c9f7d, deepwiki-open wiki (12 pages), verified Q&A.

How it answers the API layer & connectors questions

Each answer was drafted by a code-reading agent at commit 45c9f7d. Its citations were checked mechanically. Compare with the other api layer & connectors →

How is third-party authentication implemented?

answered

Third-party auth uses two approaches. OAuth2 via Klavis cloud (_oauth_support/oauth_acquire.sh:1-93): Docker wrapper calls api.klavis.ai to create OAuth instance, shows URL, polls until authorized. Strata OAuth provider (open-strata/src/strata/mcp_proxy/auth_provider.py:160-200): OAuthClientProvider with authorization_code/refresh_token grants. LocalTokenStorage (auth_provider.py:27-54) persists tokens to .tokens/{name}/tokens.json. CallbackServer on port 3030 (auth_provider.py:110-154). HTTPTransport (transport/http.py:46-80) passes provider when auth=oauth. Multi-tenant: per-server OAuth instances. Servers like Airtable (mcp_servers/airtable/server.py:43-70) extract tokens from AUTH_DATA or x-auth-data header.

How is an integration / connector defined?

answered

Each integration is an MCP server in mcp_servers/. 105 servers ship with the repo. No single manifest format; servers in Python (Airtable: mcp_servers/airtable/server.py:1-80), Go (GitHub: mcp_servers/github/server.go:1-80), or TypeScript, each with Dockerfile. Code-defined via app.list_tools() and app.call_tool(). Strata config (open-strata/src/strata/config.py:13-87): MCPServerConfig dataclass with name, type, url/command, headers, env, auth, enabled. Stored in ~/.config/strata/servers.json. OpenAPI codegen (fern/generators.yml:1-69): Fern generates Python and TypeScript SDKs from openapi.json. Versions: Fern v3.5.0 (fern/fern.config.json:1-4); strata-mcp 1.0.2 (open-strata/pyproject.toml:3).

Editor's note. Correction: mcp_servers/ holds 101 server directories, not 105. The other entries are README and package files, and several directories are benchmark variants (*_toolathlon, *_mcpmark, *_atlas).

How are integrations exposed to LLM agents?

answered

Two layers. Strata (open-strata/src/strata/server.py:1-206): single MCP server exposing 5 meta-tools (tools.py:22-145): discover_server_actions, get_action_details, execute_action, search_documentation, handle_auth_failure. list_tools() (server.py:81-90) returns only these 5. BM25 search (shared_search.py:47-151): UniversalToolSearcher with weighted indexes. MCP Clients (mcp_client.py:271-304): list_all_tools() converts to Anthropic/OpenAI formats. Per-LLM (llms/openai.py, llms/anthropic.py): streaming with tool calls, unified ChatMessage model. Platform bots: Slack, Discord, Web, WhatsApp. Formats (LLM.md:242-250): OpenAI, Anthropic, Gemini, MCP native.

How is a tool call executed?

answered

Layered proxy. Strata (tools.py:246-286): execute_action looks up MCPClient, merges params, calls client.call_tool(). MCPClient (mcp_proxy/client.py:97-122): session.call_tool() on MCP ClientSession; result.isError raises RuntimeError. Transport (mcp_client_manager.py:82-118): HTTPTransport or StdioTransport. Base (transport/base.py:32-56) uses AsyncExitStack. Direct client (mcp_client.py:331-386): find_server_for_tool(), 30s progress updates. Error mapping: exceptions caught/logged, returned as TextContent (tools.py:288-292). No sandboxing (process/container isolation). No rate limiting/retries. Sensitive params redacted (mcp_client.py:109-139). Pagination is server-specific.

How are data sync, webhooks and triggers implemented?

insufficient evidence

No centralized webhook or sync framework found. MCP servers are stateless request-response. Slack event routes (mcp-clients/src/mcp_clients/slack/event_routes.py:1-50) handle incoming Slack events (POST /slack/events) and interactive components (POST /slack/interactive) -- platform-specific message routing, not a generic webhook system. No scheduled syncs, incremental cursors, or event triggers for agents. Pagination handled internally by servers. These features may exist in the hosted Klavis cloud.

How is it self-hosted and what is open vs proprietary?

answered

License: Apache 2.0 (LICENSE, open-strata/LICENSE). Open in repo: (1) 105 MCP server integrations; (2) Strata (open-strata/) with CLI, config, OAuth provider, BM25 search; (3) Docker OAuth wrapper (_oauth_support/); (4) MCP clients for Slack/Discord/Web/WhatsApp (mcp-clients/); (5) Fern codegen config. Self-host: pip install strata-mcp, configure ~/.config/strata/servers.json. No external database. Cloud-dependent: Klavis API for OAuth (oauth_acquire.sh:25-30, line 49). Managed Strata and SDKs are hosted. But Strata's own OAuth provider (auth_provider.py:160-200) works with standard OAuth independently.