Skip to main content

Tools — Cloud Function reference

Server-side dispatch of MCP or HTTP tools for a registered agent. See the Tools subsystem for the narrative.

registerTool

Caller: authenticated human (the owner of agentId) onCall — Firebase Callable

registerTool({
agentId: string;
name: string;
kind: 'mcp' | 'http';
url: string;
authToken?: string; // KMS-encrypted at rest; omit for anonymous tools
manifest?: unknown; // skip to let the server fetch it from `url`
}) => {ok: true}

Errors

CodeReason
invalid-argumentMissing agentId/name/kind/url or URL is unparseable
permission-deniedCaller does not own agentId

Side effects

  • Writes agents/{agentId}/tools/{name}
  • KMS-encrypts authToken via key projects/axy-ujex/locations/us-central1/keyRings/ujex/cryptoKeys/secrets
  • If kind === 'mcp' and manifest is not supplied, POSTs {jsonrpc: '2.0', id: 1, method: 'tools/list'} to url and stores the response
  • Audit: tool.register

listTools

Caller: authenticated agent onCall

listTools({}) => {
tools: Array<{name: string; kind: 'mcp' | 'http'; url: string; manifest: unknown}>
}

Returns only enabled tools. Credentials (authTokenEnc) are never included.


invokeTool

Caller: authenticated agent onCall

invokeTool({
name: string;
args?: unknown; // tool-defined; for MCP becomes `params.arguments`
timeoutMs?: number; // default 15_000, clamped to 60_000
sessionId: string; // stable id for this agent run
approvalId?: string; // approved retry for the exact name+args digest
}) => {status: number; result: unknown} | {status: 'waiting_approval'; approvalId: string; reason: string}

Errors

CodeReason
invalid-argumentname or sessionId missing
not-foundTool doesn't exist or is disabled
failed-preconditionapprovalId is missing, not approved, expired, or bound to a different action digest
resource-exhaustedtools.invoke quota exhausted for this owner/month
internalTool returned non-2xx or threw a network error. details.status = HTTP code (0 on network failure). Quota is credited back on network failure.

Behaviour

  • Server-side policy runs before fetch. Default-deny verbs or Rule-of-Two sessions return waiting_approval and do not call the remote URL.
  • Approved retries execute only when approvalId matches the exact name,args digest.
  • Budget preflight runs before quota/fetch and fails closed on budget overage.
  • Decrypts authTokenEnc transiently; injects Authorization: Bearer <token> if present
  • MCP: body {jsonrpc: '2.0', id: <rand>, method: 'tools/call', params: {name, arguments: args}}
  • HTTP: body args ?? {}
  • Audit: tool.invoke with {status, ok, error}

getToolCredential

Caller: authenticated agent onCall

getToolCredential({name: string}) => throws failed-precondition

Errors

CodeReason
failed-preconditionAgent-side plaintext credential access is disabled

This callable remains exported for short-term compatibility, but production servers deny agent-side plaintext credential access. Use invokeTool; Ujex injects credentials server-side so tokens never touch agent memory.


Firestore state written

PathWritten byContents
agents/{agentId}/tools/{name}registerToolFull tool record including authTokenEnc (Uint8Array) + kmsKey path
audit/{seq}all fourHash-chained audit events (actor, action, target, meta)

Quota bucket

BucketCharged byCredited by
tools.invokeinvokeTool success or HTTP-level failureinvokeTool network error

Retention

Tool registrations live until the owner deletes the agent or marks enabled: false. Audit entries are append-only and retained per the audit subsystem's own policy.