MCP Tools, Resources and Prompts: The Three Building Blocks
An MCP server can offer three kinds of thing: tools the model calls, resources the application reads in, and prompts the user picks. What each one is, who decides when it is used, and how hosts put them in front of you.
Updated 7 min read
An MCP server can offer three kinds of building block. Tools are actions the AI model may decide to call. Resources are pieces of data, each with a URI, that the application decides to put in front of the model. Prompts are ready-made templates the user chooses to run, often as a slash command. The difference that matters is not what they contain but who decides when each one is used: the model, the application or the user. Tools get most of the attention, but the other two solve problems tools handle badly.
Everything below comes from the current Model Context Protocol specification. If MCP itself is new to you, start with what MCP is or MCP for beginners, then come back.
Who controls what
The server overview in the specification (opens in a new tab) sums the three up as a control hierarchy:
- Tools are model-controlled: functions exposed to the model so it can take actions. The examples given are API POST requests and writing files.
- Resources are application-controlled: contextual data attached and managed by the client. The examples are file contents and git history.
- Prompts are user-controlled: interactive templates invoked by the user’s choice. The examples are slash commands and menu options.
For each one, the specification also says that hosts are free to present it however suits them; the protocol does not mandate a user interface. So “model-controlled” describes the intended design, not a guarantee of what every app on your machine does.
Tools: what the model may do
A tool is a named action with a description and a JSON Schema for its inputs. A client asks the server for the list with tools/list, shows the list to the model, and when the model picks one, sends tools/call with the name and arguments. The tools page of the specification (opens in a new tab) lists the fields: name, an optional display title, description, inputSchema, an optional outputSchema for structured results, and optional annotations describing the tool’s behaviour.
{
"name": "move_task",
"title": "Move a task",
"description": "Move one task to another lane. Needs permission to move tasks.",
"inputSchema": {
"type": "object",
"properties": {
"ref": { "type": "string", "description": "The task ref, e.g. BUG-031" },
"lane": { "type": "string", "enum": ["backlog", "next", "doing", "done"] }
},
"required": ["ref", "lane"]
}
}Three rules in the tools section shape how they behave in practice:
- A person should stay in charge. For trust and safety there should always be a human in the loop able to deny a tool call, and applications should show which tools are exposed, show when one is invoked, and ask for confirmation.
- Annotations are hints, not promises. Clients must treat annotations as untrusted unless they come from a trusted server, so a tool labelled read-only is only as honest as whoever wrote it.
- Two kinds of error. A malformed request or an unknown tool is a protocol error. A failure the model could fix — bad input, an API refusal, a business rule — comes back as a normal result with
isError: true, so the model can read it and correct itself.
The second kind of error is where a well-built server earns its keep. A result that says what went wrong and why lets the assistant recover or explain; how to debug MCP tools shows how to read one when it does not.
Resources: what the application may read in
A resource is data with an address: a file, a database schema, a page of documentation, identified by a URI. The client lists them with resources/list and fetches one with resources/read, which returns text or base64 binary content. Servers can also publish resource templates, parameterised URIs such as file:///{path}, and can offer change notifications for a list or for a single resource the client has subscribed to.
The resources page (opens in a new tab) calls them application-driven and gives three ways a host might use them: a tree or list view to pick from, search and filters, or automatic inclusion based on heuristics or the model’s own choice. Resources can carry annotations too: an intended audience (the user, the assistant or both), a priority from 0 to 1, and lastModified, which a client can use to decide what earns a place in a limited context window.
{
"uri": "file:///project/docs/release-checklist.md",
"name": "release-checklist.md",
"title": "Release checklist",
"mimeType": "text/markdown",
"annotations": { "audience": ["assistant"], "priority": 0.8 }
}The spec names https://, file:// and git:// as common schemes and allows custom ones that follow RFC 3986. It asks servers to use https:// only when the client could fetch the resource from the web by itself.
Prompts: what the user may run
A prompt is a template the server offers for the user to start: a name, a description and a list of arguments. The client lists them with prompts/list; when the user picks one, it calls prompts/get with the arguments and gets back a list of messages, each with a role (user or assistant) and content, which can include text, images, audio and embedded resources.
The prompts page (opens in a new tab) is careful about what “user-controlled” means: it refers to who decides when the prompt is used, not who writes its content, which the server defines. It gives slash commands as the typical way to expose them.
{
"name": "weekly_status",
"title": "Weekly status",
"description": "Summarise what finished, what is in progress and what is stuck.",
"arguments": [
{ "name": "project", "description": "Project name", "required": true }
]
}How a host puts them in front of you
Claude Code is a useful example because it supports all three, and its MCP documentation (opens in a new tab) shows each one’s control model in the interface:
- Tools are offered to the model, which decides when to call them. You can require approval per tool.
- Resources appear when you type
@, alongside files, and are referenced as@server:protocol://resource/path; a referenced resource is fetched and attached. Claude Code also gives the model tools to list and read resources itself when a server supports them. - Prompts appear when you type
/, listed as/servername:promptname (MCP), and/mcp__servername__promptnameruns one, with arguments separated by spaces.
Other hosts may present them differently, or not at all; the specification leaves that to each host. Before building a resource or a prompt, check that the clients your users actually run will show it.
Which one to build
- Build a tool when the model needs to act, or to look something up with parameters it chooses: create a task, search, run a query.
- Build a resource when there is a document or dataset worth attaching as it is, and the user or the application should decide when it goes in: a schema, a runbook, a changelog.
- Build a prompt when there is a workflow people start on purpose and want run the same way each time: a review, a status report, a release checklist.
The security considerations differ too. For tools, servers must validate inputs, apply access controls and rate limits, and sanitise outputs. For resources, servers must validate URIs and guard file:// paths against directory traversal. For prompts, both sides must validate inputs and outputs against injection. MCP security risks covers what goes wrong when those are skipped.
What fenbs’s MCP server offers
Tools only. When a client connects, the fenbs server declares the tools capability and nothing else, so there are no resources or prompts to list. Its tools cover reading and changing tasks, comments, projects, decisions and the board’s AI context — fenbs_whoami, fenbs_list_items, fenbs_create_item, fenbs_get_context and the rest. A refusal comes back as a tool result with isError: true, naming the permission that was missing and the role held, which is the spec’s second kind of error used as intended.
The jobs that resources and prompts would do elsewhere are handled differently. What an assistant should know before it starts is AI context, which it reads with the fenbs_get_context tool, and repeatable procedures live in your assistant, as a skill or a saved prompt, rather than on the server.
More on MCP
What MCP means for a project board: what is MCP. Building your own server: how to build an MCP server. Connecting fenbs: the MCP guide.