ToolRegistry CRD
The ToolRegistry custom resource defines tool handlers available to AI agents. Handlers can expose one or more tools and come in two categories:
- Self-describing (MCP, OpenAPI): Automatically discover tools at runtime
- Explicit (HTTP, gRPC, client): Require a tool definition with name, description, and input schema
API version
Section titled “API version”apiVersion: omnia.altairalabs.ai/v1alpha1kind: ToolRegistryShort name: tr (e.g. kubectl get tr).
graph TB TR[ToolRegistry] --> H1[HTTP Handler] TR --> H2[gRPC Handler] TR --> H3[MCP Handler] TR --> H4[OpenAPI Handler] TR --> H5[Client Handler]
subgraph explicit["Explicit (schema required)"] H1 H2 H5 end
subgraph selfDesc["Self-Describing (auto-discovery)"] H3 H4 end
H1 --> T1[Single Tool] H2 --> T2[Single Tool] H3 --> T3[Multiple Tools] H4 --> T4[Multiple Tools] H5 --> T5[Browser Tool]Spec fields
Section titled “Spec fields”handlers
Section titled “handlers”List of handler definitions (at least one is required). Each handler connects to a tool source and exposes one or more tools.
spec: handlers: - name: calculator type: http httpConfig: endpoint: https://api.example.com/calculate method: POST tool: name: calculate description: "Perform mathematical calculations" inputSchema: type: object properties: expression: type: string required: [expression]Handler types
Section titled “Handler types”| Type | Category | Description |
|---|---|---|
http |
Explicit | HTTP REST endpoint |
grpc |
Explicit | gRPC service using the Omnia Tool protocol |
mcp |
Self-describing | Model Context Protocol server |
openapi |
Self-describing | OpenAPI/Swagger-documented service |
client |
Explicit | Browser-executed tool (runs in the connected client) |
Handler definition
Section titled “Handler definition”Common fields for all handler types:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique handler name (^[a-z0-9]([-a-z0-9]*[a-z0-9])?$, max 63 chars) |
type |
string | Yes | Handler type (http, grpc, mcp, openapi, client) |
tool |
object | Conditional | Tool definition — required for http, grpc, and client |
httpConfig |
object | Conditional | Required when type: http |
grpcConfig |
object | Conditional | Required when type: grpc |
mcpConfig |
object | Conditional | Required when type: mcp |
openAPIConfig |
object | Conditional | Required when type: openapi |
clientConfig |
object | No | Optional consent configuration for type: client |
auth |
object | No | How the runtime authenticates to the backend (see Authenticating tools) |
timeout |
string | No | Per-invocation wall-clock timeout. Defaults to 30s |
Tool definition (for explicit handlers)
Section titled “Tool definition (for explicit handlers)”http, grpc, and client handlers require a tool definition:
| Field | Type | Required | Description |
|---|---|---|---|
tool.name |
string | Yes | Tool name exposed to the LLM (^[a-z][a-z0-9_]*$, max 64) |
tool.description |
string | Yes | Human-readable description |
tool.inputSchema |
object | Yes | JSON Schema for input parameters |
tool.outputSchema |
object | No | JSON Schema for output (optional) |
HTTP handler
Section titled “HTTP handler”The endpoint URL lives in httpConfig.endpoint (required):
- name: search-api type: http httpConfig: endpoint: https://api.example.com/search method: POST headers: Content-Type: application/json contentType: application/json tool: name: search description: "Search the knowledge base" inputSchema: type: object properties: query: type: string description: "Search query" limit: type: integer default: 10 required: [query] timeout: "30s"HTTP configuration options
Section titled “HTTP configuration options”| Field | Type | Default | Description |
|---|---|---|---|
endpoint |
string | — | Required. HTTP endpoint URL |
method |
string | POST |
HTTP method |
headers |
map | — | Additional HTTP headers |
headersFromSecret |
map | — | Map of HTTP header name → secretRef ({name, key}). Value resolved from the Secret at call time; never stored in the CRD or the tools ConfigMap. Not for a header the auth stanza owns — Authorization, or a custom auth.workloadIdentity.header. See Advanced HTTP tools. |
contentType |
string | application/json |
Content-Type header |
retryPolicy |
object | — | Retry behaviour — see Advanced HTTP tools |
authType |
string | — | Deprecated — use the handler-level auth stanza. Auth type (bearer or basic). |
authSecretRef |
object | — | Deprecated — use the handler-level auth stanza. Reference to a Secret holding the credential. |
The HTTP handler also supports request/response shaping fields —
urlTemplate, queryParams, headerParams, staticQuery, staticBody,
bodyMapping, responseMapping, and redact. These are not exposed in the
dashboard UI; see Advanced HTTP tools.
Authenticating tools
Section titled “Authenticating tools”Authentication is configured with the handler-level auth stanza (a sibling
of httpConfig/openAPIConfig/…), so the same shape applies across handler
types:
handlers: - name: my-api type: http httpConfig: endpoint: https://api.example.com auth: type: bearer # none | bearer | basic | serviceAccount | workloadIdentity secretRef: name: my-tool-credentials # a Kubernetes Secret in the same namespace key: token # for basic, the value is "username:password" tool: name: my_tool description: "Call the authenticated API" inputSchema: type: object| Field | Type | Default | Description |
|---|---|---|---|
auth.type |
string | none |
Authentication mechanism: none, bearer, basic, serviceAccount, or workloadIdentity. |
auth.secretRef |
object | - | Secret holding the credential (required for bearer/basic). |
auth.serviceAccount.audience |
string | - | Audience the projected ServiceAccount token binds to (required for serviceAccount). |
auth.workloadIdentity |
object | - | Hosted same-cloud identity (cloud, audience). Required for workloadIdentity. Only cloud: azure is supported. |
The auth stanza applies to http, openapi, grpc, and mcp handlers (the
runtime attaches the credential as an HTTP Authorization header, gRPC
authorization metadata, or an MCP transport header). Auth is not supported on
a stdio MCP transport (no header channel) and is rejected.
bearer/basic— the operator resolvessecretRefinto an operator-managed<agentruntime>-tool-secretsSecret, mounted read-only into the runtime. The token value never enters the tools ConfigMap.serviceAccount— the operator projects an audience-bound Kubernetes ServiceAccount token into the runtime; the tool backend validates it via TokenReview. Sent asAuthorization: Bearer <token>.workloadIdentity— resolved by the runtime under the pod’s ambient Azure identity (core);cloudmust beazure. The runtime acquires a token foraudienceand sets it onheader(defaultAuthorization). Supported on http, grpc, and mcp (sse / streamable-http) and openapi handlers — the token is acquired per call (per request for mcp/openapi, so it survives token expiry). Not supported on stdio MCP (no header channel), which is rejected at reconcile. The pod’s identity must be granted every WIF tool’s API; per-tool identity separation is a future option.
For a secret header other than Authorization (a second API key or signing
token), use httpConfig.headersFromSecret — it reuses the same
<agentruntime>-tool-secrets companion Secret and never-in-ConfigMap guarantee.
A key there that collides with a header the auth stanza owns is rejected:
Authorization, or the custom auth.workloadIdentity.header when one is set.
A missing Secret/key, an unsupported type, or a stdio-MCP+auth combination fails
the AgentRuntime reconcile — it does not silently send an unauthenticated request.
A workloadIdentity handler whose token cannot be acquired at call time fails
that tool call rather than calling the backend unauthenticated.
For a task-oriented walkthrough (creating the credential Secret and verifying the
mounted <agentruntime>-tool-secrets), see the how-to:
Authenticating tools.
GRPC handler
Section titled “GRPC handler”The endpoint (host:port) lives in grpcConfig.endpoint (required):
- name: grpc-tools type: grpc grpcConfig: endpoint: tool-service.tools.svc.cluster.local:50051 tls: false tlsInsecureSkipVerify: false tool: name: process_data description: "Process data via gRPC" inputSchema: type: object properties: data: type: string required: [data]GRPC configuration options
Section titled “GRPC configuration options”| Field | Type | Default | Description |
|---|---|---|---|
endpoint |
string | — | Required. gRPC server address (host:port) |
tls |
bool | false |
Enable TLS |
tlsCertPath |
string | — | Path to TLS certificate |
tlsKeyPath |
string | — | Path to TLS key |
tlsCAPath |
string | — | Path to CA certificate |
tlsInsecureSkipVerify |
bool | false |
Skip TLS verification |
retryPolicy |
object | — | Retry behaviour (per gRPC status code) |
The backend behind grpcConfig.endpoint must implement the Omnia Tool
protocol defined by api/proto/tools/v1/tools.proto
(ToolService), not an arbitrary gRPC API. See
Build a tool backend for the full
contract, including when ListTools is required.
MCP handler (self-describing)
Section titled “MCP handler (self-describing)”Model Context Protocol handlers automatically discover tools from the MCP server. No tool definition is required.
SSE Transport (connect to MCP server via Server-Sent Events):
- name: mcp-server type: mcp mcpConfig: transport: sse endpoint: http://mcp-server.tools.svc.cluster.local:8080/sseStreamable HTTP Transport:
- name: mcp-http type: mcp mcpConfig: transport: streamable-http endpoint: http://mcp-server.tools.svc.cluster.local:8080/mcpStdio Transport (spawn MCP server as subprocess):
- name: filesystem-tools type: mcp mcpConfig: transport: stdio command: /usr/local/bin/mcp-filesystem args: - "--root=/data" workDir: /app env: LOG_LEVEL: infoMCP configuration options
Section titled “MCP configuration options”| Field | Type | Required | Description |
|---|---|---|---|
transport |
string | Yes | sse, streamable-http, or stdio |
endpoint |
string | For sse / streamable-http |
Server URL |
command |
string | For stdio |
Command to execute |
args |
[]string | No | Command arguments |
workDir |
string | No | Working directory |
env |
map | No | Environment variables |
toolFilter |
object | No | allowlist / blocklist of tool names to expose |
retryPolicy |
object | No | Retry behaviour for CallTool failures |
auth is supported on sse and streamable-http transports (the credential is
attached as a transport header). Auth on a stdio transport is rejected (no
header channel).
OpenAPI handler (self-describing)
Section titled “OpenAPI handler (self-describing)”OpenAPI handlers automatically discover tools from an OpenAPI/Swagger specification. Each operation becomes a tool.
- name: petstore type: openapi openAPIConfig: specURL: https://petstore.swagger.io/v2/swagger.json baseURL: https://petstore.swagger.io/v2 operationFilter: - getPetById - findPetsByStatusOpenAPI configuration options
Section titled “OpenAPI configuration options”| Field | Type | Required | Description |
|---|---|---|---|
specURL |
string | Yes | URL to OpenAPI spec (v2 or v3) |
baseURL |
string | No | Override the base URL from spec |
operationFilter |
[]string | No | Limit to specific operation IDs |
headers |
map | No | Additional headers for requests |
retryPolicy |
object | No | Retry behaviour (uses the HTTP retry policy shape) |
authType |
string | No | Deprecated — use the handler-level auth stanza. |
authSecretRef |
object | No | Deprecated — use the handler-level auth stanza. |
Client handler (browser-executed)
Section titled “Client handler (browser-executed)”client handlers are executed by the connected browser client over the
WebSocket facade, not by the runtime. They take an explicit tool definition
like HTTP/gRPC handlers, plus optional consent configuration. See
Client-side tools.
- name: geolocation type: client clientConfig: consentMessage: "Allow the assistant to read your location?" categories: [location] tool: name: get_location description: "Read the user's current location from the browser" inputSchema: type: objectStatus fields
Section titled “Status fields”Current phase of the ToolRegistry:
| Value | Description |
|---|---|
Pending |
Initial state before the first reconcile completes |
Ready |
Every discovered tool is Available |
Degraded |
Some tools Available, some Unavailable (only when probing is enabled) |
Failed |
A handler failed validation, or no tools were discovered |
Probing
Section titled “Probing”By default a tool’s status reflects configuration validity only. Set
spec.probe.enabled: true to have the controller periodically TCP-dial each
tool’s resolved endpoint and mark it Available or Unavailable, which drives
the registry phase (Ready when all reachable, Degraded when some are not,
Failed when none are). It is a reachability check (a TCP connect), not a tool
invocation, so it has no side effects on the backend.
spec: probe: enabled: true interval: "60s" # how often to re-probe (default 60s) timeout: "5s" # per-endpoint dial timeout (default 5s) handlers: - name: order-lookup # …| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Turn on reachability probing |
interval |
string | 60s |
How often endpoints are re-probed |
timeout |
string | 5s |
Per-endpoint TCP dial timeout |
Client tools (client://browser) and stdio MCP handlers have no network
address and are never probed (they stay Available). Probing checks that the
port accepts a TCP connection — it does not verify the tool actually works;
Test a tool exercises the real call.
discoveredToolsCount
Section titled “discoveredToolsCount”Total number of tools discovered across all handlers.
discoveredTools
Section titled “discoveredTools”List of discovered tools with their status:
status: discoveredTools: - handlerName: calculator name: calculate status: Available endpoint: https://api.example.com/calculate - handlerName: petstore name: petstore status: Available endpoint: https://petstore.swagger.io/v2/swagger.jsonconditions
Section titled “conditions”| Type | Description |
|---|---|
HandlersValid |
True when every handler passed validation; False (with the errors) otherwise |
ToolsDiscovered |
Reports how many tools were discovered from how many handlers |
Complete example
Section titled “Complete example”ToolRegistry with multiple handler types:
apiVersion: omnia.altairalabs.ai/v1alpha1kind: ToolRegistrymetadata: name: agent-tools namespace: agentsspec: handlers: # Explicit HTTP tool with schema - name: calculator type: http httpConfig: endpoint: https://api.example.com/calculate method: POST tool: name: calculate description: "Perform mathematical calculations" inputSchema: type: object properties: expression: type: string description: "Mathematical expression to evaluate" required: [expression] timeout: "10s"
# gRPC tool service - name: user-service type: grpc grpcConfig: endpoint: user-grpc.internal.svc.cluster.local:50051 tool: name: get_user description: "Retrieve user information" inputSchema: type: object properties: user_id: type: string required: [user_id]
# Self-describing MCP server - name: code-tools type: mcp mcpConfig: transport: sse endpoint: http://mcp-code.tools.svc.cluster.local:8080/sse
# Self-describing OpenAPI service - name: external-api type: openapi openAPIConfig: specURL: https://api.example.com/openapi.json operationFilter: - searchProducts - getProductDetailsStatus after reconcile:
status: phase: Ready discoveredToolsCount: 4 discoveredTools: - handlerName: calculator name: calculate status: Available - handlerName: user-service name: get_user status: Available - handlerName: code-tools name: code-tools status: Available - handlerName: external-api name: external-api status: Available conditions: - type: HandlersValid status: "True" - type: ToolsDiscovered status: "True"