Interfaces
MCP
Connect an MCP host to A8, and judge, teach and retract from inside a conversation with three tools.
This page as Markdown: https://u22a8.ai/docs/a8-mcp.md. The index of every docs page: https://u22a8.ai/llms.txt.
A8’s Model Context Protocol (MCP) server lets an MCP host, such as Claude, ChatGPT or Cursor, judge, teach and retract from inside a conversation. It is the way to teach A8: your assistant writes the request, and your approval of the tool call is the commit.
The server is named A8 and served at https://api.u22a8.ai/mcp, over Streamable HTTP.
§1Connect a host
Hosts that support sign-in take you through it: you sign in with your account and pick an organization, and the server acts with your role’s permissions in it. Hosts that take a header send an API key as Authorization: Bearer, and the server acts with the key’s permissions in its organization. Each tool needs the permission listed in Table 1.
In Claude, open Settings → Connectors and select Add custom connector. Name it A8, enter the URL below and sign in when Claude asks.
https://api.u22a8.ai/mcp
In ChatGPT, turn on Settings → Apps & Connectors → Advanced settings → Developer mode. Then select Create, name the connector A8, enter the URL below and sign in when ChatGPT asks.
https://api.u22a8.ai/mcp
Add the server to .cursor/mcp.json in your project, or to ~/.cursor/mcp.json for every project. Cursor reads the key from your environment:
{
"mcpServers": {
"a8": {
"url": "https://api.u22a8.ai/mcp",
"headers": {"Authorization": "Bearer ${env:U22A8_API_KEY}"}
}
}
}
Add the server with a key from your environment:
$ claude mcp add --transport http a8 https://api.u22a8.ai/mcp \
--header "Authorization: Bearer $U22A8_API_KEY"
To sign in with your account, add the server with the URL alone, then run /mcp in Claude Code.
§2Tools
The server has three tools, one for each thing you do with A8:
| Tool | Does | Permission | Annotations |
|---|---|---|---|
judge | Returns a verdict, an abstention or recalled examples | models:infer; recall models:explain | Read-only |
teach | Records the answer a request should get, or proposes one | models:train | Idempotent |
retract | Removes a taught answer from the next version | models:train | Destructive, idempotent |
The three tools. Precedents also need models:explain, and recall needs models:explain alone. Permissions are on API keys, and on your role when you sign in.
All three take a request the same way: input, a string or a list of messages, and an optional format. A list carries a whole conversation: assistant messages are A8’s earlier responses, and A8 answers the latest user message. A8 finds the criterion and the subject in it as it does in every interface. See API overview. The three input schemas share these definitions:
{
"$defs": {
"request": {
"description": "A string, or messages as in the Responses API.",
"oneOf": [
{"type": "string"},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"enum": ["system", "developer", "user", "assistant"]
},
"content": {"type": "string"}
},
"required": ["role", "content"]
}
}
]
},
"format": {
"type": "object",
"description": "A JSON Schema for the verdict."
}
}
}
§2.1Approval
An MCP host asks before it calls a tool that changes something. judge is read-only, so a host calls it freely. Approving a teach that carries an answer, or a retract, changes your model. A teach with the input alone returns a proposal, and your assistant records it with a second call once you agree.
§3judge
judge returns the verdict for a request, an abstention, or your taught examples when the request asks what you taught.
{
"type": "object",
"properties": {
"input": {"$ref": "#/$defs/request"},
"format": {"$ref": "#/$defs/format"},
"model": {
"type": "string",
"default": "a8",
"description": "The model, its minimum accuracy as a tag: a8:95."
}
},
"required": ["input"],
"additionalProperties": false
}
model names the model and the minimum accuracy in its tag, as in every interface: a8:95 asks for 95, and the default is 90. A pinned identifier, such as a8-1-1:95@20260715t140322z, holds the version and the minimum accuracy still, so a test runs against the same model every time. See Model identifiers.
The result’s structured content follows this output schema, and its text content carries the same object as JSON:
{
"type": "object",
"properties": {
"verdict": {"description": "The verdict, in the shape format gives."},
"model": {"type": "string", "description": "The version that answered."},
"min_accuracy": {"type": "integer"},
"abstention": {"type": "object"},
"precedents": {"type": "object"}
},
"required": ["model"]
}
A verdict:
{
"verdict": {"queue": "shipping"},
"model": "a8-1-1:95@20260715t140322z",
"min_accuracy": 95
}
Recorded from a8-1-1@20260715t140322z on 2026-10-22.
An abstention is a successful result. verdict is null, and abstention names the check the evidence failed:
{
"verdict": null,
"model": "a8-1-1:95@20260715t140322z",
"abstention": {
"kind": "unfamiliar_subject",
"asked": 95,
"answerable_at": 0,
"earned": 97,
"missing": null
}
}
Recorded from a8-1-1@20260715t140322z on 2026-10-22.
When the request asks for precedents, the result adds a precedents object. A question about what you taught, such as “What have I taught you about refunds?”, returns precedents alone, holding up to ten of your taught examples word for word.
§3.1The judge tool’s description
The tool’s description tells the host how to examine A8, so “check that A8 learned our refund rule” is enough for your assistant to run a fair test. This is the description, word for word:
Judge a request with A8. Returns the verdict, or an abstention where the
evidence falls below the minimum accuracy.
To check what A8 has learned, test it. Write untaught variations of the
request, edge cases included, each with the answer it should get. Judge
each one, and report the misses and the abstentions separately: a miss
lowers accuracy, and an abstention lowers coverage.
A question about what was taught, such as "What have I taught you about
refunds?", returns the taught examples.
Your assistant writes the variations, and A8 judges them. See Testing.
§4teach
teach records the answer a request should get, or proposes a request and answer from your own words.
{
"type": "object",
"properties": {
"input": {"$ref": "#/$defs/request"},
"format": {"$ref": "#/$defs/format"},
"answer": {
"description": "The verdict to record. Leave it out to get a proposal."
}
},
"required": ["input"],
"additionalProperties": false
}
With an answer, the example is recorded once you approve the call:
{
"input": [
{"role": "system", "content": "Which queue does the ticket belong in?"},
{"role": "user", "content": "It arrived crushed. I want a refund."}
],
"format": {
"properties": {"queue": {"enum": ["billing", "shipping", "account"]}}
},
"answer": {"queue": "billing"}
}
{
"recorded_at": "2026-07-16T09:11:40Z",
"replaced": false
}
recorded_atis when the teach was recorded. Every version whose horizon is at or after that time includes it. See Horizons.replacedistruewhen the same request held a different answer, which this one replaces. See Teaching.
With the input alone, or an input that states what A8 should learn, teach returns a proposal: the request and answer A8 would record. recorded_at is null, and your assistant teaches the proposal with a second call. For a key that also holds models:explain, A8 frames the proposal beside the requests you taught nearest it, and reuses their criterion and format; for any other key, from the input alone.
{
"input": "Double-charge tickets go to billing, even when the order came late."
}
{
"proposal": {
"input": [
{"role": "system", "content": "Which queue does the ticket belong in?"},
{
"role": "user",
"content": "I was charged twice for an order that arrived late."
}
],
"format": {
"properties": {"queue": {"enum": ["billing", "shipping", "account"]}}
},
"answer": {"queue": "billing"}
},
"recorded_at": null
}
Recorded from a8-1-1@20260715t140322z on 2026-10-22.
The tool’s description, word for word:
Teach A8 the answer a request should get. Call it when the user says a
verdict was wrong, or states something A8 should learn.
With an answer, the example is recorded and the next version learns it.
Teaching the same request again replaces its answer. With the input alone,
it returns a proposal: show the proposal to the user, and teach it with a
second call once they agree.
Confirm the request and the answer with the user before you call it.
§5retract
retract removes a taught example. It takes the request alone, word for word as it was taught.
{
"type": "object",
"properties": {
"input": {"$ref": "#/$defs/request"},
"format": {"$ref": "#/$defs/format"}
},
"required": ["input"],
"additionalProperties": false
}
{
"retracted": true
}
The next version is fitted from your remaining examples. Versions fitted before keep the retracted example, so a pinned version answers as it did. retracted says whether the request held a taught answer to remove. To find the exact request, ask judge what you taught; recall lists it.
The tool’s description, word for word:
Remove a taught example, so the next version is fitted from the examples
that remain. Call it when the user says an example was taught by mistake.
Find the exact request first: ask judge what was taught, and use the
example word for word.
Confirm the request with the user before you call it.
§6Errors
A call that fails returns a result with isError set to true. Its text names the field, the rule it broke and the value that passes:
{
"isError": true,
"content": [
{
"type": "text",
"text": "This request needs the models:train permission."
}
]
}
Each condition matches a status code of the other interfaces:
| Condition | Status elsewhere |
|---|---|
| The key lacks the permission the tool needs | 403 |
| The organization lacks access to A8 | 403 |
model names a version outside your organization’s horizons | 404 |
input is empty, or model’s tag is outside 0 to 99 | 400 |
| The pinned version is still being fitted | 503 |
| A8 filtered the request for harmful content | 200, in each interface’s filter slot |
Tool errors and the status each matches. The bodies of those statuses are on Errors.
With reasoning on, A8 filters some requests whose text is harmful, such as hate speech, violence or self-harm. MCP reports a filtered request as a failed call: judge and teach return a result with isError set and the text This request was filtered for harmful content. A filtered teach leaves your examples as they were.