# Expose functions as MCP tools

Add an `mcp` facade to a function-mode AgentRuntime so other Omnia agents and
external MCP clients can call the function as a typed tool. The pod serves
Streamable HTTP MCP next to `POST /functions/{name}`, advertising one tool whose
`inputSchema` is the function's `spec.inputSchema`.

## Prerequisites

- A function-mode AgentRuntime. See [Define Functions](/how-to/agents/define-functions/).
- `spec.externalAuth` configured on it. Without it the external listener's
  validator chain is empty and rejects every request with a `401`. See
  [Configure Authentication](/how-to/security/configure-authentication/).

## Steps

### 1. Add the mcp facade

List an `mcp` facade beside the `rest` facade. The entry turns the MCP server
on, and `mcp.port` defaults to 9998.

```yaml
apiVersion: omnia.altairalabs.ai/v1alpha1
kind: AgentRuntime
metadata:
  name: weather-lookup
spec:
  mode: function
  promptPackRef:
    name: weather-pack
  facades:
    - type: rest
      port: 8080
    - type: mcp
      mcp:
        port: 9998
  inputSchema:
    type: object
    required: ["latitude", "longitude"]
    properties:
      latitude: { type: "number" }
      longitude: { type: "number" }
  outputSchema:
    type: object
    required: ["temperature_celsius", "conditions"]
    properties:
      temperature_celsius: { type: "number" }
      conditions: { type: "string" }
```

The Service exposes port 8080 for `POST /functions/{name}` and port 9998 for
MCP. The dashboard's `/functions` catalog shows an **MCP** badge on functions
that have an `mcp` facade.

If the function's `inputSchema` root uses `oneOf`, `anyOf`, `allOf`, `not`,
`$ref`, `if`, `enum`, `const` or a non-object `type`, callers send the input
under `arguments.input`. See
[Schema adaptation](/reference/platform/mcp-function-facade/#schema-adaptation).

### 2. Consume it from an Omnia agent

Add the endpoint as an `mcp` handler in a ToolRegistry, then reference that
registry from the consuming agent's `spec.toolRegistryRef`:

```yaml
apiVersion: omnia.altairalabs.ai/v1alpha1
kind: ToolRegistry
metadata:
  name: weather-tools
spec:
  handlers:
    - name: weather
      type: mcp
      mcpConfig:
        transport: streamable-http
        endpoint: http://weather-lookup.default.svc.cluster.local:9998/mcp
      auth:
        type: bearer
        secretRef:
          name: weather-token
          key: token
```

The consuming agent's PromptPack must list the tool in a prompt's `tools`.
See [Connect MCP servers](/how-to/tools/connect-mcp-servers/) for the handler
fields.

### 3. Consume it from an external client

Set `expose.enabled: true` on the `mcp` facade entry (it needs the chart's
`defaultExposure` Gateway, as for any agent). The operator creates an HTTPRoute
named `<agent>-mcp` on `<agent>-mcp.<namespace>.<baseDomain>`, routed to the
agent's Service on port 9998; set `expose.host` on that entry to override the
hostname. Without a default-exposure Gateway, create an HTTPRoute yourself
whose `backendRef` names the agent's Service on port 9998. Either way, once
the operator observes the route, `status.facade.endpoints` lists an entry with
`protocol: mcp`. Point the client at that URL with the Bearer token:

```json
{
  "mcpServers": {
    "weather-lookup": {
      "url": "<url from status.facade.endpoints>",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}
```

A tool call on the external listener is cancelled after 30 seconds. For longer
work, set `facades[].async` and call `POST /functions/{name}?mode=async`.

## Verify

Port-forward the Service and list the tools with a token your
`spec.externalAuth` accepts:

```bash
kubectl port-forward svc/weather-lookup 9998:9998
```

```bash
curl -s -X POST http://localhost:9998/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

The result holds one tool, named after the AgentRuntime in lower case, with
the `inputSchema` and `outputSchema` from the spec. To confirm the
management-plane twin:

```bash
kubectl get agentruntime weather-lookup \
  -o jsonpath='{.status.managementEndpoints.mcp}'
```

The command prints `19998`.

## Troubleshooting

| Symptom | Cause |
|---|---|
| `401` from an external client | `spec.externalAuth` is unset or does not accept the token |
| `403 origin not allowed` | A browser sent an `Origin` outside the allowed list. See [Origin check](/reference/platform/mcp-function-facade/#origin-check) |
| `isError: true` result | The text starts with the outcome. See [Errors](/reference/platform/mcp-function-facade/#errors) |
| Legacy SSE client cannot connect | The server supports Streamable HTTP only |
| Client needs several functions | Each pod serves one function as one tool; connect to each endpoint |

## Related pages

- [MCP function facade reference](/reference/platform/mcp-function-facade/)
- [Define Functions](/how-to/agents/define-functions/)
- [`facades` reference](/reference/core/agentruntime/#facades)
- [Configure Authentication](/how-to/security/configure-authentication/)