# Build a tool backend

Write a service that the runtime can call as a tool, register it as an `http`
or `grpc` handler, and confirm the registry accepts it.

## Prerequisites

- A ToolRegistry in the agent's namespace, or permission to create one.
- A service the agent pod can reach by cluster DNS name.
- Your tool's input as a JSON Schema. The model sees this schema, not your
  code.

## Steps

1. Pick the protocol. Use HTTP when the tool is a REST endpoint you already
   have. Use gRPC when you want a typed service that you generate from the
   Omnia proto.

2. Implement the backend. Both contracts are in the
   [Tool backend protocol](/reference/platform/tool-backend-protocol/).

   For HTTP:
   - Accept the arguments as the JSON body (or as query parameters for a
     `GET`).
   - Return a 2xx status with a JSON body. Any other status is a tool error,
     and the model sees only the first 512 bytes of the body, so keep error
     bodies short.
   - Read the `x-omnia-*` request headers if you need the caller's identity.

   For gRPC:
   - Generate a server for `omnia.tools.v1.ToolService` from
     `api/proto/tools/v1/tools.proto`, or import
     `github.com/altairalabs/omnia/pkg/tools/v1` in Go.
   - Implement `Execute`. Read `arguments_json`, and return the result in
     `result_json`. To report a tool failure, set `is_error` and
     `error_message`.
   - `ListTools` is not needed for a handler in a ToolRegistry.

3. Register the backend. Each handler needs a `tool` definition with a name,
   a description and an `inputSchema`:

   ```yaml
   apiVersion: omnia.altairalabs.ai/v1alpha1
   kind: ToolRegistry
   metadata:
     name: order-tools
   spec:
     handlers:
       - name: order-lookup
         type: http
         httpConfig:
           endpoint: http://orders.shop.svc.cluster.local:8080/lookup
           method: POST
         tool:
           name: lookup_order
           description: "Look up an order by ID"
           inputSchema:
             type: object
             properties:
               order_id:
                 type: string
             required: [order_id]
       - name: inventory
         type: grpc
         grpcConfig:
           endpoint: inventory.shop.svc.cluster.local:50051
         tool:
           name: check_stock
           description: "Check stock for a SKU"
           inputSchema:
             type: object
             properties:
               sku:
                 type: string
             required: [sku]
   ```

   The names and endpoints are illustrative. For TLS on a gRPC backend, set
   the `grpcConfig.tls*` fields. For credentials, add an `auth` stanza to the
   handler. See [Authenticate tools](/how-to/tools/authenticate-tools/).

4. Apply the registry:

   ```bash
   kubectl apply -f order-tools.yaml
   ```

5. Let the agent call the tool:
   - List `lookup_order` and `check_stock` in `tools` on the PromptPack prompt
     that should use them. The runtime offers the model only the tools a
     prompt lists.
   - Reference the registry from the AgentRuntime.
   - If the install runs the policy engine, add a ToolPolicy whose selector
     names the registry. The policy broker refuses every call to a registry
     that no policy selects.

## Verify

Check that the registry accepted the handlers:

```bash
kubectl get toolregistry order-tools
```

`Ready` is `True` and `Tools` is `2` when the configuration is valid. This
does not contact the backend. To check reachability, enable `spec.probe` (see
[Probing](/reference/core/toolregistry/#probing)). To send a real call, follow
[Test tools](/how-to/tools/test-tools/).

## Troubleshooting

| Symptom | Cause |
|---------|-------|
| `HandlersValid` is `False` | A `grpc` handler has no `tool`, or a handler has no endpoint. Read the condition message. |
| The model receives `{"result": "..."}` | The HTTP backend returned a 2xx body that is not valid JSON. Return JSON. |
| The model receives `HTTP 4xx: ...` | The backend rejected the request. Check the arguments against its schema. |
| Every call is denied with `no-matching-permit` | No ToolPolicy selects the registry. |

## Related pages

- [Tool backend protocol](/reference/platform/tool-backend-protocol/)
- [ToolRegistry reference](/reference/core/toolregistry/)
- [Advanced HTTP tools](/how-to/tools/advanced-http-tools/)
- [Authenticate tools](/how-to/tools/authenticate-tools/)
- [Test tools](/how-to/tools/test-tools/)