> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompts and Resources

> Build MCP prompts and resources as workspace objects in Xano, attach them to your MCP servers, and give clients argument autocomplete.

An MCP server offers clients three kinds of things:

| | What it is | Who uses it |
| - | - | - |
| **Tools** | Actions the model can take, like querying a table or calling an API. | The model decides when to call them. |
| **Prompts** | Reusable message templates with arguments, like "Review this code" or "Summarize this order." | The user picks one, usually from a slash command or menu in their client. |
| **Resources** | Data the client can read as context, addressed by a URI, like `docs://readme` or `orders://{order_id}`. | The client or user attaches them to the conversation. |

In Xano, prompts and resources are **workspace objects**, just like tools. You build each one
once, with its own function stack, then attach it to one or more MCP servers. They're under
Agents & MCP → Prompts
and Resources in the sidebar.

Because they're workspace objects, prompts and resources work everywhere tools do: version
history, publishing, branching and merges, [Git sync](/xano-features/workspace-settings/git-sync),
`xano workspace push` and `pull`, the [Metadata API](/xano-features/metadata-api), and
[request history](/maintenance-monitoring-and-logging/request-history).

## Prompts

A prompt's **inputs** are its arguments, and its **response** is the list of messages the
client receives.

### Create a prompt

**Builder**

**Step 1**

### Add the prompt

From the sidebar, go to Agents & MCP →
Prompts and click Add Prompt.

* **Name**: what MCP clients use to request the prompt, such as `code_review`. Letters,
  numbers, dashes and underscores only.
* **Description**: an internal-only field for documenting the prompt's purpose.
* **Tags**: for organizing your prompts.

**Step 2**

### Add arguments

Under **Arguments**, add an input for each argument a client passes. A required input
with no default is a required argument, and the client is refused before your stack
runs if it's missing. Each input's description is sent to the client too.

**Step 3**

### Build the messages

Add functions under **Function Stack** to build the prompt's messages, then return
them under **Response**, for example:

```json theme={null}
[{"role": "user", "content": "Review this code: ..."}]
```

**Step 4**

### Publish and attach

Publish the prompt, then [attach it to an MCP server](#attach-to-an-mcp-server).

To give the prompt a display name or icons, open ⋮ →
Settings and fill in **Title** and **Icons**. See [Tool
metadata](/ai-tools/mcp-builder#tool-metadata) for how icons work.

**XanoScript**

Prompts live in `ai/prompt/`.

```xs ai/prompt/code_review.xs theme={null}
prompt code_review {
  title = "Code review"

  input {
    // The code to review
    text code

    // The language of the code
    enum language? {
      values = ["php", "typescript"]
    }
  }

  stack {
    var $messages {
      value = [
        {role: "user", content: "Review this " ~ $input.language ~ " code: " ~ $input.code}
      ]
    }
  }

  response = $messages
  tags = ["mcp", "review"]
}
```

| Field | Required | What it does |
| - | - | - |
| `input` | ✅ | The prompt's arguments. May be empty. |
| `stack` | ✅ | The logic that builds the messages. |
| `response` | ✅ | The messages. A prompt with no response fails every request. |
| `title` | no | A display name clients may show instead of the name. |
| `icons` | no | Icons clients may display. Same format as [tool icons](/ai-tools/mcp-builder#tool-metadata). |
| `description`, `tags`, `history`, `docs` | no | The same as on a tool. |

### What a prompt can return

| Response | What the client gets |
| - | - |
| A string or number | One `user` message with that text. |
| A `{role, content}` object | One message. |
| A list of `{role, content}` objects | Those messages, in order. |

`role` is `user` or `assistant`. `content` is a string, or a single MCP content block:
`text`, `image`, `audio`, `resource_link` or `resource`. Anything else is an error that names
the bad value.

## Resources

A resource has a **URI** that clients use to read it. Its **response** is the content they
get back.

A resource is either:

* **Static**, with a literal URI such as `docs://readme`. It has no inputs.
* **A template**, with variables in the URI, such as `orders://{region}/{order_id}`. Each
  variable becomes an input, and your stack sees the values from the URI the client read.

### Create a resource

**Builder**

**Step 1**

### Add the resource

From the sidebar, go to Agents & MCP →
Resources and click Add Resource.

* **Name**: the resource's name, such as `readme`.
* **URI**: a literal URI (`docs://readme`) for a static resource, or a template with
  `{variables}` (`orders://{order_id}`). Each template variable is added as a `text`
  input. Change its type afterward if you need to.
* **Description** and **Tags**: internal fields for organizing your resources.

**Step 2**

### Build the contents

Template variables are listed under **URI Variables**. Add functions under
**Function Stack** to build the resource's contents, and return them under
**Response**.

**Step 3**

### Publish and attach

Publish the resource, then [attach it to an MCP server](#attach-to-an-mcp-server).

Open ⋮ → Settings for the
optional fields: **Title**, **MIME Type**, **Annotations** and **Icons**.

**XanoScript**

Resources live in `ai/resource/`.

```xs Static theme={null}
resource readme {
  uri = "docs://readme"
  mime_type = "text/markdown"

  stack {
  }

  response = "# Readme"
}
```

```xs Template theme={null}
resource regional_order {
  title = "Regional order"
  uri = "orders://{region}/{order_id}"
  mime_type = "application/json"
  annotations = {
    audience     : ["user", "assistant"]
    priority     : 0.5
    last_modified: "2025-01-12T15:00:58Z"
  }

  input {
    enum region {
      values = ["us", "eu"]
    }

    int order_id
  }

  stack {
    db.get order {
      field_name = "id"
      field_value = $input.order_id
    } as $order
  }

  response = $order
}
```

| Field | Required | What it does |
| - | - | - |
| `uri` | ✅ | The URI clients read. A literal URI, or a template with `{variables}`. |
| `stack` | ✅ | The logic that builds the contents. |
| `response` | no | The contents. |
| `input` | no | One input per template variable. A static resource has none. |
| `mime_type` | no | The MIME type of the contents. Leave it out to derive it from the response. |
| `annotations` | no | Hints for how clients present the resource. See below. |
| `title`, `icons` | no | A display name and icons, as on a tool. |
| `description`, `tags`, `history`, `docs` | no | The same as on a tool. |

### URI rules

* A URI must start with a scheme, such as `docs://` or `orders://`, and can't contain
  whitespace.
* Template variables are simple `{name}` placeholders. Operators and modifiers like
  `{+path}`, `{#x}`, `{x*}`, `{x:3}` and lists like `{a,b}` aren't supported.
* Each variable can appear once, two variables can't sit side by side, and each matches
  exactly one path segment.
* Every variable needs a matching input of type `text`, `int`, `decimal`, `bool`, `enum`,
  `email` or `uuid`, as a single value rather than a list. Every input must be a variable.
* Values are converted to the input's type before your stack runs. A client reading
  `orders://eu/abc` where `order_id` is an `int` gets an error.
* When a literal URI and a template both match, the literal one wins.

### What a resource can return

| Response | What the client gets |
| - | - |
| A text string | Text contents. |
| A binary string, or a file | A base64 `blob`. |
| An object or list | JSON text. |
| A number, boolean or `null` | Text. |
| `{text}` or `{blob}`, optionally with `mime_type` and `uri`, or a list of these | Used as they are. A `blob` must already be base64. |

The MIME type comes from the item's own `mime_type`, then the resource's **MIME Type**, then
the file's type, and finally `text/plain`, `application/json` or `application/octet-stream`.

### Annotations

Resource annotations are hints clients may use to decide how to present a resource. Leave
any of them unset to make no claim.

| Annotation | XanoScript | What it says |
| - | - | - |
| **Audience** | `audience` | Who the contents are for: `user`, `assistant`, or both. |
| **Priority** | `priority` | How important the resource is, from `0` (least) to `1` (most). |
| **Last Modified** | `last_modified` | When the contents last changed, as an ISO 8601 timestamp. |

> [!NOTE]
>
> Before prompts and resources were workspace objects, you could expose a tool as a resource by
> setting its **Tool Type** to **Resource** in **Connection Settings**. Those legacy resource
> tools keep working, and you can still view or convert them to a regular tool. New resources
> should be resource objects. If both share a URI, the resource object wins.

## Attach to an MCP server

A client only sees, reads and completes the prompts and resources attached to the server it
connected to.

**Builder**

Open the MCP server and click Connect →
Connect Prompt or Connect Resource.
Pick one from the list, or click **Create a new Prompt** to build one and attach it in one
step.

The server page has **Tools**, **Prompts** and **Resources** tabs. On the Prompts or
Resources tab, click the pencil icon on a row to open **Manage MCP Server Connection**:

* **Allow Connections**: turn the prompt or resource on or off for this server.
* **Authentication**: **Public**, or an auth-enabled table whose users must be signed in.

These settings apply only to this server. Click the trash icon to remove the prompt or
resource from the server. The prompt or resource itself is kept.

**XanoScript**

List them in the server's `prompts` and `resources` fields. Each entry takes the object's
`name`, plus optional `active` (default `true`) and `auth`, the name of an auth-enabled
table. Leave `auth` out to make the entry public.

```xs ai/mcp_server/orders.xs theme={null}
mcp_server "Orders" {
  canonical = "67Dx5RNL"
  tools = [{name: "search_orders"}]
  prompts = [
    {name: "summarize_order", auth: "user"}
    {name: "old_prompt", active: false}
  ]
  resources = [{name: "regional_order"}]
}
```

Two resources attached to the same server can't share a URI. Xano refuses the save or push.

The server's [connection trigger](/building/logic/triggers/mcp-servers) also receives the
attached prompts and resources, and can narrow them per client.

## Argument autocomplete

When a client asks for completions while a user fills in a prompt argument or a resource
template variable, Xano suggests values for **`enum`** inputs. Matching is a case-insensitive
prefix match on the enum's values, up to 100 suggestions, and no stack runs. Other input
types return no suggestions.

To give an argument autocomplete, make it an `enum`. In the `code_review` example above, a
client that supports completions suggests `php` and `typescript` for `language`.

## Ask the user and report progress

Prompt and resource stacks can use the same MCP functions as tools: **Ask the User (Elicit)**
to request input from the client's user mid-request, and **Report Progress** to send progress
updates. See [MCP Functions](/ai-tools/mcp-builder/mcp-functions).

## Test and debug

Use Run & Debug on a prompt or resource to run it with test
inputs and see the messages or contents it returns. If the stack uses **Ask the User
(Elicit)**, choose a simulated answer for each elicit under **Simulated elicitation**. The
stack runs for real, so any writes it makes happen.

Prompt and resource runs are logged on their own **Prompts** and **Resources** tabs in
[Request History](/maintenance-monitoring-and-logging/request-history).

## Metadata API

| Operation | Route |
| - | - |
| List or create prompts | `GET` / `POST /workspace/{workspace_id}/prompt` |
| Get, update or delete a prompt | `GET` / `PUT` / `DELETE /workspace/{workspace_id}/prompt/{prompt_id}` |
| Run a prompt | `POST /workspace/{workspace_id}/prompt/{prompt_id}/debug` |
| Resources | The same routes, with `/resource/{resource_id}` |

Create and update take a raw XanoScript body with `Content-Type: text/x-xanoscript`. They
need the same permissions as tools.


## Related topics

- [MCP Builder](/ai-tools/mcp-builder.md)
- [MCP Server Triggers](/building/logic/triggers/mcp-servers.md)
- [XanoScript for MCP Servers](/xanoscript/mcp-servers.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.