MCP function facade
The mcp facade serves one function of a function-mode AgentRuntime as one MCP
tool over Streamable HTTP. Facade fields are in the
AgentRuntime reference.
Endpoints
Section titled “Endpoints”| Endpoint | Port | Listener |
|---|---|---|
POST /mcp | facades[].mcp.port, default 9998 | External |
POST /mcp | 19998 (mcp-mgmt) | Management-plane twin |
/.well-known/oauth-protected-resource, /.well-known/oauth-protected-resource/mcp | 9998 | External, no credential |
/metrics | 8081 (health port) | Facade |
The twin runs unless the mcp facade sets managementPlane: false. When it
runs, status.managementEndpoints.mcp is 19998. The Service also exposes
port 8080 for POST /functions/{name}.
Protocol
Section titled “Protocol”| Aspect | Behaviour |
|---|---|
| Transport | Streamable HTTP, stateless: tools/list and tools/call need no prior initialize |
| Protocol versions | 2025-03-26 and 2025-06-18. initialize agrees to either version when asked and answers 2025-06-18 otherwise |
| JSON-RPC batches | Not supported. A JSON array body returns a parse error |
GET /mcp | 405 |
| Methods | prompts/* and resources/* are not supported. Legacy SSE clients cannot connect |
| Tools | One tool per pod, named after the AgentRuntime in lower case, with the inputSchema and outputSchema from the spec after the adaptation below |
Schema adaptation
Section titled “Schema adaptation”MCP requires a tool schema to have a "type": "object" root. The facade adapts
the function’s spec.inputSchema and spec.outputSchema.
| Root of the spec schema | Advertised schema |
|---|---|
| Object root | Unchanged |
Describes an object but omits type | "type": "object" added |
Has oneOf, anyOf, allOf, not, $ref, if, enum or const, or a non-object type | Wrapped in an object with one required property: input for the input schema, output for the output schema |
For a wrapped input schema, callers send the function input under
arguments.input. The facade unwraps it before it validates the input.
Call results
Section titled “Call results”A successful tools/call returns the function output as structuredContent
and as a text part. A tools/call with no arguments calls the function with
{}.
Errors
Section titled “Errors”| Condition | Result |
|---|---|
tools/call for an unknown tool | JSON-RPC error -32602 |
| A call that runs and fails | MCP result with isError: true |
The text of an isError result starts with one of the outcomes below.
| Outcome | Meaning |
|---|---|
input_invalid | The input failed validation |
output_invalid | The output failed validation. A second text part, prefixed raw_output:, carries the runtime output |
runtime_error | The runtime call failed. The facade logs the detail |
rate_limited | The agent’s spec.rateLimit refused the call before the runtime saw it |
function_not_found | The function does not exist |
payload_too_large | The input exceeds the facade’s maximum body size |
sync_timeout | The call exceeded the time limit |
internal_error | An internal failure. The facade logs the detail |
Time limit
Section titled “Time limit”| Listener | tools/call limit |
|---|---|
| External | 30 seconds, the same limit as a synchronous POST /functions/{name}. The call returns a sync_timeout error result |
| Management-plane twin | None |
POST /functions/{name}?mode=async runs longer work and requires
facades[].async.
Authentication
Section titled “Authentication”| Listener | Accepts |
|---|---|
| External | The validators built from spec.externalAuth, the same chain as POST /functions/{name} |
| Management-plane twin | Management-plane JWTs. It refuses every request it cannot authenticate |
An unauthenticated POST /mcp returns 401. An AgentRuntime with no
spec.externalAuth has an empty external chain, so its external listener
rejects every request with 401. Management-plane JWTs are never accepted on
the external listener.
The 401 response carries a WWW-Authenticate header:
spec.externalAuth.oidc | WWW-Authenticate | authorization_servers |
|---|---|---|
| Set | Carries resource_metadata | Lists its issuer |
| Unset | Bearer realm="omnia" alone | Not applicable |
The RFC 9728 metadata resource is the agent’s external MCP URL when the
operator observes one, else the in-cluster Service URL.
Origin check
Section titled “Origin check”A POST /mcp that carries a browser Origin header gets 403 with the body
origin not allowed unless the origin is the agent’s own external or
in-cluster URL. Requests with no Origin header are unaffected. Authentication
runs first, so an unauthenticated request with a bad Origin gets 401.
| Variable | Value |
|---|---|
OMNIA_MCP_ALLOWED_ORIGINS | Comma-separated list of additional allowed origins. * turns the check off |
Set the variable in the extraEnv of the rest entry. The operator copies
extraEnv from the primary facade only (the rest facade of a function), and
the API server rejects extraEnv on the mcp entry.
External exposure
Section titled “External exposure”facades[].expose is read from the primary facade only, and the operator’s
HTTPRoute targets only that facade’s port (8080). The API server rejects
expose on the mcp facade, and the operator creates no route for the MCP
port.
status.facade.endpoints gets an entry with protocol: mcp when an observed
HTTPRoute in the namespace has a backendRef to the agent’s Service on the MCP
port.
Recording and policy
Section titled “Recording and policy”A tools/call writes a sessions row when session-api is reachable, as the
HTTP route does. The session carries the agent, namespace and workspace
identity, so ToolPolicy rules on identity.agent and identity.workspace
apply.
Metrics and tracing
Section titled “Metrics and tracing”| Metric | Labels |
|---|---|
omnia_mcp_requests_total | method, status |
omnia_mcp_request_duration_seconds | method |
omnia_mcp_tool_invocations_total | function, outcome |
Every metric also carries agent and namespace. A failed tool call counts as
status="ok" on the request series and appears on the invocation series.
Spans named mcp-facade join the trace through the runtime gRPC call.