How is an integration / connector defined?
Manifest or schema format; code vs config; codegen from OpenAPI; versioning; how many integrations ship.
Verdict
The two projects define an integration in opposite ways. In ACI, an integration is data. Each of the 98 apps is an app.json (metadata and security schemes, with secrets as Jinja placeholders) plus a functions.json. That file describes each REST endpoint (method, path, server URL) and its parameters as JSON Schema split into header, path, query and body, with a visible list that decides what the LLM sees. The CLI commands upsert-app and upsert-functions validate the definitions, embed them and load them into Postgres. Of the 987 functions, 971 are pure config. The other 16 are routed by name to Python connector classes. Every definition is written by hand; there is no OpenAPI import.
In Klavis, an integration is code. Each of the roughly 100 mcp_servers/ directories is a separate MCP server in Python, TypeScript or Go, with its own Dockerfile. Tools are declared in list_tools() and dispatched by hand in call_tool(). There is no shared manifest. Fern generates SDKs, but only for the hosted API.
Choose ACI’s model when you want to add many REST endpoints cheaply and the same way each time. Choose Klavis when you want a normal MCP server per service, which you can run alone and which may contain any custom logic.
More projects in this category are being researched.
Per-project answers
Klavis-AI/klavis
answeredEach 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).
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).aipotheosis-labs/aci
answeredAn integration (called an App) is defined declaratively as two JSON files in backend/apps/{app_name}/. The app.json file contains metadata: name, display_name, provider, version, description, categories, visibility, active status, security_schemes (with OAuth2 URLs, scopes, and placeholder client_id/client_secret as Jinja2 template variables), and default_security_credentials_by_scheme (apps/github/app.json:1-27). The functions.json file is an array of function definitions, each specifying name, description, tags, visibility, active, protocol ("rest" or "connector"), protocol_data (e.g. {"method": "GET", "path": "/repos/...", "server_url": "..."} for REST), and parameters as a JSON Schema (apps/github/functions.json:1-80). Parameters have visible and invisible properties — invisible params inject security defaults at execution time. The upsert-app CLI command (cli/commands/upsert_app.py:44-47) renders templates with environment-specific secrets, validates the JSON via AppUpsert Pydantic model, generates an OpenAI embedding for semantic search, and upserts into the apps and functions tables (upsert_app.py:84-103). There are 98 integrations in backend/apps/ (from accredible to zoho_desk). Most REST integrations are pure config; 10 have custom Python connector code in server/app_connectors/ (base.py, gmail.py, e2b.py, etc.). Versioning is a free-form string field per app; there is no automated OpenAPI codegen — integrations are manually authored.
upsert-app registers the app only. Functions are loaded by a separate upsert-functions command.← How is third-party authentication implemented? · How are integrations exposed to LLM agents? →