An MCP server also serves
prompt() and resource() objects, and an agent or MCP server can
have a connection trigger (agentTrigger, mcpServerTrigger) that decides what each connection
sees.
A tool
An agent, called from an endpoint
Agents have no public endpoint of their own. You run one from any stack:- The answer is at
.result.ref("answer")is the whole run envelope (finishReason,stepsand more). llmpicks the provider:anthropic,openai,google-genaiorxano-free, each with its own typed fields.- Structured output. Give the agent
output: { schema: { ... } }withinput.*fields and.resultis typed from it at every call site. - Prompts are templates. String settings resolve
{{ $args.NAME }}and{{ $env.NAME }}at run time.
Control each connection: agent triggers
AnagentTrigger runs when a client connects to the agent it is bound to. t.toolset is the
agent (t.toolset("name") reads one field) and t.tools is its list of tools, each
{ id, name, instructions }. What the trigger returns is the toolset and tools that connection
gets, so the trigger can gate the connection, or log and annotate it on the way through:
- The stack is a callback. A trigger has no
input; its inputs arrive ont, typed to the trigger, so a wrong name is a compile error. - Bind with the handle. Pass the
agent()def, not an id. A trigger bound to nothing deploys and never fires. - Omit
responseand the connection gets every tool unchanged.
An MCP server
An MCP server exposes tools, prompts and resources to any MCP client, such as Claude, ChatGPT or another agent. Prompts and resources are their own kinds: define them, then list them on the server.A prompt
A prompt is a reusable message a client can ask for. Itsinput is the prompt’s arguments; an
enum’s values also answer the client’s completion requests:
{ role: "user" | "assistant", content }.
Resources
A resource is data a client reads byuri. A literal uri is a static resource. A uri with a
{variable} is a template: each variable is one input field, and a client reads a concrete
URI such as blog://posts/42.
The server, with sign-in
List the tools, prompts and resources on the server. Addoauth to make every MCP request carry
a signed-in user from your auth table:
- Entries.
tools,promptsandresourceseach take handles, or a{ tool | prompt | resource, enabled?, auth? }wrapper.authnames the auth table and is what gives that entry’s stack a caller forauth(). A bare handle is public. blogMcp.getUrl(HOST)returns the Streamable HTTP URL a client connects to.- Names. An
mcpServerand anagentwith the same name collide, because both are stored as toolsets.
Hosted sign-in
Withmode: "hosted", Xano is the authorization server. A client that connects is sent to your
loginUrl with an mcp_request parameter. That page is also the consent screen: it shows who is
asking, signs the user in, then calls an endpoint that completes the sign-in and redirects the
browser to the URL it returns. Two endpoints back the page:
MCP_LOGIN_URL in workspaceConfig({ env: { MCP_LOGIN_URL: "" } }) and set its value
per environment in xano/.env (see Env and secrets).
s.mcp.oauth.revoke ends a user’s sign-ins on a server.
Your own identity provider
To accept tokens from Auth0, Clerk, WorkOS, Entra, Okta or Cognito instead, usemode: "external". The token’s claim (default sub) is matched against a column in your auth
table, here an auth0_id text column on users that holds each user’s provider id:
Control each connection: MCP server triggers
AnmcpServerTrigger runs when an MCP client connects to the server it is bound to, and its
response decides what that one connection lists. t carries the server’s toolset, tools,
prompts and resources. Return a list filtered to narrow it; a key you leave out lists
everything the server has. This one hides the resources from every connection:
t.authis the signed-in user when the server hasoauth:{ dbo, id, extras }of the auth-table row, read ast.auth("id"). It is null on a server without sign-in, so check it before reading a field.- An entry you return can change its description. A returned prompt or resource’s
descriptionreplaces the listed one for that connection. - Omit
responseand the connection lists all four unchanged.
Knowledge
Aknowledge() item is a markdown file that Xano’s own AI reads before it acts: the
workspace’s builder agent, and outside agents that read the workspace through the Meta API or
MCP. It does not reach an agent() you run with s.ai.agent.run. Put what that agent must know
in its llm.systemPrompt.
mode: "always" sends the whole body on every request, and a type: "agents.md" item is
always sent in full. Write the description of an auto item to match the requests it should
answer.
Register them
Next
- Every
llmfield, MCP prompts and resources, elicitation and background runs: object kinds reference. - Run work on a schedule or on Xano platform events: Tasks and platform events.
- Call code the typed surface cannot express, from a tool or anywhere else: Custom code.