Skip to content

AI agents

An agent that judges in free text (“this looks like a billing issue, fairly sure”) can’t be routed on or audited. Give it Curva as a tool and it gets typed answers with calibrated probabilities instead, and an abstain flag when it should hand over to a person.

Every way in goes through a Curva server, so answers are cached, calibrated by feedback and audit-logged:

Agent setup Use
MCP clients (Claude Desktop, Claude Code, Cursor and other MCP-capable agents) curva mcp, see MCP server
Any tool-calling API or agent framework, in Python curva.integrations: the tool’s JSON Schema, description and decide function
Any language /openapi.json: generate a client, or hand the operation to your framework

Nothing extra to install: pip install curva-ai includes all of it.

For agents that speak the Model Context Protocol, run curva mcp next to (or pointing at) your Curva server; it exposes a decide tool:

Terminal window
claude mcp add curva -- curva mcp --url http://127.0.0.1:7777

Setup for other clients is in MCP server.

Three plain helpers, no framework required:

from curva import Curva, Choice, Noul
from curva.integrations import decide, description, input_schema
questions = {
"department": Choice("Which team should handle this", ["billing", "technical", "sales"], min_confidence=0.8),
"refund": Noul("The customer explicitly asks for a refund"),
}
schema = input_schema(questions) # JSON Schema of the tool's arguments (only `state` here)
text = description(questions) # tells the model when to call the tool
result = decide(Curva(), {"ticket": "..."}, questions, project="support") # JSON text for the agent

Register schema and text as a tool with your model provider or framework, and call decide when the model uses it. With fixed questions (above, recommended for production) you decide what gets asked and the agent only passes the state. Call input_schema() and description() without questions to let the agent write its own questions in the /v1/decide shape: flexible, but every new wording starts a fresh calibration.

decide returns compact JSON:

{"decision_id": "dec_…", "answers": {
"department": {"choice": "billing", "probabilities": {"billing": 0.97, "technical": 0.02, "sales": 0.01, "none_of_these": 0.0},
"confidence": 0.97, "abstain": false, "calibrated": false},
"refund": {"noul": 0.93, "calibrated": false}}}

Curva errors (a 422 for a malformed question, a 429) come back as text instead of raising, so the agent can fix the call or wait.

Keep the decision_id from the tool output. When the outcome is known, send it back:

Curva().feedback(decision_id, "department", "billing")

From 30 labels per question, the agent’s answers are calibrated whenever that makes them more accurate. See Calibrate with feedback.

© 2026 Tarkova Private Limited.