MCP
4.8 MCP Platform
Kroov exposes a full MCP control plane: remote HTTP MCPs, catalog install, Kubernetes-backed managed runtimes, per-user OAuth vault, federation entitlements, definitions/diagnostics, and an internal runtime proxy.
| Surface | Auth |
|---|---|
api/mcp-servers, definitions, credentials | JWT + org Owner/Admin of active tenant (X-AINexus-Tenant); servers scoped by TenantId |
api/mcp-catalog, api/mcp-runtime | JWT platform Admin (+ hosted runtime attribute); control-plane only, not org catalogue |
api/mcp-instances | JWT or delegation; requires hosted MCP runtimes |
api/integrations | JWT (OAuth connect for end users) |
api/mcp-runtime-proxy | X-Mcp-Controller-Token (AllowAnonymous + token check) |
api/delegations/exchange | Project API key + service/user tokens |
| Chat with MCP tools | Project API key (+ optional user/delegation headers) |
Concepts
Transport types (transportType):
| Value | Name | Usage |
|---|---|---|
0 | HttpOpenApi | Deprecated — OpenAPI bridge |
1 | McpStreamableHttp | Native MCP over HTTP (preferred) |
2 | McpStdio | Stdio profile (catalog custom images; not JSON-importable) |
Credential types (credentialType): None, Passthrough, OAuth, Pat, EnvVar.
Remote vs managed: Remote MCPs call a vendor URL. Managed MCPs run as isolated Kubernetes worker pods; chat targets mcpInstanceId whose endpoint is routed through the internal proxy.
MCP servers — McpServerController (api/mcp-servers)
Organization Owner/Admin manage servers for the active organization. New servers receive the
active tenant’s TenantId. Platform Admin without org membership cannot list or mutate org
servers. Catalog/runtime Kubernetes endpoints remain platform AdminOnly.
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/mcp-servers | Org Owner/Admin | List servers for active tenant |
GET | /api/mcp-servers/{id} | Org Owner/Admin (same tenant) | Detail + tools |
POST / PUT / DELETE | /api/mcp-servers[/{id}] | Org Owner/Admin | CRUD (create binds TenantId) |
PUT | /api/mcp-servers/{id}/tools/{toolId} | Org Owner/Admin | Enable/disable tool |
POST | /api/mcp-servers/import/preview | Org Owner/Admin | Preview JSON config |
POST | /api/mcp-servers/import | Org Owner/Admin | Install from JSON (+ optional one-shot credential) |
POST | /api/mcp-servers/{id}/sync-tools | Org Owner/Admin | Native MCP tool discovery |
POST | /api/mcp-servers/{id}/import-openapi | Org Owner/Admin | Legacy HttpOpenApi |
GET / PUT | /api/projects/{projectId}/mcp-servers | Project access / Org Owner/Admin | List assignments / replace (same-tenant servers only) |
PUT | /api/mcp-servers/{id}/projects | Org Owner/Admin | Set this server’s projects (same-tenant; non-destructive) |
Profile fields: name, baseUrl, description, transportType, remoteEndpointUrl, registryServerName, registryVersion, stdioCommand, stdioArgsJson, stdioEnvVarKeysJson, authMode, contextMode, requireCredential, credentialType, oauthProviderKey, authHeaderName, authHeaderTemplate (must contain {credential} when required), allowedHosts, allowedPathPrefix, defaultMaxToolRounds, defaultMaxToolCalls, isActive.
Remote Streamable HTTP create:
curl -X POST https://your-kroov-host/api/mcp-servers \
-H "Authorization: Bearer $ORG_ADMIN_JWT" \
-H "X-AINexus-Tenant: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "SerpAPI",
"baseUrl": "https://mcp.serpapi.com/{credential}/mcp",
"transportType": 1,
"remoteEndpointUrl": "https://mcp.serpapi.com/{credential}/mcp",
"credentialType": 3,
"requireCredential": true,
"authMode": 2
}'
JSON import (Claude Desktop / Cursor / VS Code mcpServers shape). Stdio/npx entries are rejected for JSON import — use Catalog → Custom for containerised MCPs.
{
"json": "{ \"mcpServers\": { \"gmail\": { \"serverUrl\": \"https://gmailmcp.googleapis.com/mcp/v1\", \"oauth\": { \"clientId\": \"…\", \"clientSecret\": \"…\" } } } }",
"credential": "optional-one-shot-pat"
}
Sync tools:
curl -X POST .../api/mcp-servers/12/sync-tools \
-H "Authorization: Bearer $ORG_ADMIN_JWT" \
-H "X-AINexus-Tenant: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{ "credential": "sk-live-..." }'
→ { "synced": 15 }
Catalog — McpCatalogController (api/mcp-catalog) — AdminOnly
source query: github (default) or custom (pre-built K8s images).
| Method | Path | Purpose |
|---|---|---|
GET | /api/mcp-catalog?search=&source=&page=&pageSize= | Search (auto-sync) |
GET | /api/mcp-catalog/{serverName}?source= | Detail |
POST | /api/mcp-catalog/refresh?source= | Force sync |
POST | /api/mcp-catalog/{serverName}/install?source= | Install (+ tool sync for remote) |
Custom install may return managedRuntime: true, runtimeProfileId, requiresPairing.
Definitions & credentials — McpDefinitionController
Under /api/mcp-servers/{id}/…:
| Method | Path | Purpose |
|---|---|---|
GET / PUT | /definition | Canonical definition |
POST | /definition/validate | Validate |
GET | /definition/export?format= | Export |
GET | /definition/revisions[/{rev}] | History |
POST | /definition/revisions/{rev}/restore | Restore |
GET | /credential-requirements | What creds are needed |
GET | /credential-status | Status for account/project |
PUT / DELETE | /credentials/{accountName} | Vault set/delete |
POST | /diagnostics/{validate|discover-oauth|test-connection|list-tools} | Admin diagnostics |
Managed instances — McpInstanceController (api/mcp-instances)
Requires hosted MCP runtimes (Kubernetes:Enabled). Attribute [RequiresHostedMcpRuntimes] → 503 otherwise.
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/mcp-instances | List / create (Idempotency-Key optional) |
GET | /{id} | Detail + availableActions |
GET | /{id}/pairing | WhatsApp QR (Cache-Control: no-store) |
POST | /{id}/restart | /suspend | /resume | /reassociate | Lifecycle |
GET / POST / DELETE | /{id}/grants[/{grantId}] | Instance grants |
DELETE | /{id} | Delete worker + row |
POST | /{id}/runtime-status | AllowAnonymous — worker → API status callback |
{ "mcpServerId": 5, "projectId": 1, "ownerUserId": 2, "ownerExternalPrincipalId": null }
Statuses: Requested, Provisioning, AwaitingPairing, Ready, Degraded, Suspended, PairingRejected, Deleting, Deleted.
Federated callers use X-AINexus-Delegation with scopes such as mcp:pair, mcp:invoke, mcp:manage.
Runtime profiles — McpRuntimeController (api/mcp-runtime) — Admin + hosted runtimes
| Method | Path | Purpose |
|---|---|---|
POST | /api/mcp-runtime/analyze | Preview npx/stdio → generic runtime |
POST | /api/mcp-runtime/register | Register (hostingMode: container | subprocess Dev-only) |
GET | /api/mcp-runtime/{id} | Profile status |
POST | /api/mcp-runtime/{id}/rebuild | Kaniko rebuild |
Runtime proxy — McpRuntimeProxyController (api/mcp-runtime-proxy)
Internal data-plane proxy to the worker pod via the Kubernetes API:
GET|POST|DELETE /api/mcp-runtime-proxy/{instanceId}/mcp/
Auth: header X-Mcp-Controller-Token must equal Kubernetes:ControllerToken / McpRuntime:ControllerToken.
User OAuth / PAT integrations — IntegrationAuthController (api/integrations)
| Method | Path | Purpose |
|---|---|---|
GET | /api/integrations/mine | User’s stored credentials |
GET | /api/integrations/available | Connectable MCP servers + connected? |
GET | /api/integrations/{mcpServerId}/connect?returnTo= | { "authorizeUrl" } |
GET | /api/integrations/{provider}/callback | OAuth callback → SPA |
PUT | /api/integrations/{mcpServerId}/token | Store PAT { "token": "…" } |
DELETE | /api/integrations/{mcpServerId}/disconnect | Revoke |
Provider keys include Google and GitHub. Client secrets are never returned in API responses.
Chat credential resolution order
- Inline
delegation.credential - OAuth / PAT vault for the authenticated user (
/api/integrations) - Managed instance via
delegation.mcpInstanceId(phone match enforced for WhatsApp federated users)