MCP Primitives: Tools, Resources, and Prompts

RoadmapsAI Engineering

Scenario

You want your AI assistant to automatically search your product database whenever a user asks about stock levels. You confidently expose the `search_inventory` function as an MCP Resource. A user asks 'Do we have any red shoes?', and the LLM just hallucinates an answer. It never runs your search.

A developer wants the LLM to search a database autonomously during a conversation and defines the search function as a Resource. Why does the LLM ignore it?

Mental model

Resources are files you drag-and-drop. Prompts are templates you click to start. Tools are buttons the LLM can press itself.

MCP exposes exactly three primitives. The technical distinction between them is entirely about *control*. Resources are application-controlled (you attach them before chatting). Prompts are user-controlled (you select 'Code Review Template' from a menu). Tools are model-controlled (the LLM decides to fire them mid-conversation). If you want the AI to do something autonomously, it must be a Tool.

Deep dive

A Server's capabilities are divided into three strict categories: Resources, Prompts, and Tools. When a Host connects, it explicitly asks the Server to list them via separate JSON-RPC calls (`resources/list`, `prompts/list`, `tools/list`). How the Host handles the response depends entirely on the primitive type.

A Server exposes capabilities as Resources, Prompts, or Tools.

Resources are static or dynamic data—like a local file, a database schema, or an API response. Crucially, Resources are *application-controlled*. The user or the Host application fetches the Resource and injects it into the context window *before* the LLM is invoked. The LLM cannot autonomously trigger a Resource fetch mid-thought.

Resources are data fetched by the application and loaded before the LLM acts.

Tools are functions the LLM can execute. Unlike Resources, Tools are *model-controlled*. The Host passes the tool schemas to the LLM, and the LLM autonomously decides if, when, and with what arguments to call the tool during its generation loop. If you need the AI to search a database based on a user's question, it must be a Tool.

Tools are functions the LLM autonomously chooses to execute during generation.

Because the word 'prompt' usually means 'system instructions', developers often assume MCP Prompts are used to set behavioral guardrails. They aren't. MCP Prompts are *user-controlled* workflow templates. The user explicitly selects a Prompt (e.g., 'Summarize Jira Ticket') from a UI menu to bootstrap a new conversation.

Prompts are user-selected templates to start workflows, not hidden system instructions.

The control boundary is why the distinction matters. If you expose a capability as the wrong primitive, the intended actor literally cannot see or use it. The LLM only sees Tools. The User sees Prompts and Resources.

Execution control determines the primitive: App controls Resources, User controls Prompts, Model controls Tools.

Code examples

The JSON-RPC lists: How the Host parses primitives

// 1. Host asks: "What Resources do you have?"
// Response: Data the user can attach (like files)
{
  "method": "resources/list",
  "result": {
    "resources": [
      { "uri": "file:///logs/app.log", "name": "Application Logs" }
    ]
  }
}

// 2. Host asks: "What Tools do you have?"
// Response: Functions the LLM can call autonomously
{
  "method": "tools/list",
  "result": {
    "tools": [
      { "name": "search_logs", "inputSchema": { ... } }
    ]
  }
}

The Host treats these payloads completely differently. It puts Resources into a UI menu for the user to attach. It passes Tools directly into the LLM's system payload so the AI can use them.

The Prompt Primitive: User-selected templates

// Host asks: "What Prompts do you have?"
{
  "method": "prompts/list",
  "result": {
    "prompts": [
      {
        "name": "review_code",
        "description": "Template for reviewing PRs",
        "arguments": [ { "name": "pr_number", "required": true } ]
      }
    ]
  }
}

This is not a system instruction. The Host renders this as a clickable button in the UI. When the user clicks it, they are asked for the `pr_number`, and the server returns the actual text to start the chat.

Common mistakes

Glossary

Tool
A capability exposed by the server that the LLM autonomously chooses to execute during generation based on context.
Resource
Data exposed by the server that the Host application (or user) loads directly into the context window *before* the LLM acts.
Prompt
A reusable, user-selected template or workflow provided by the server to bootstrap an LLM session, not a system instruction.

Recall questions

Questions & answers

What's the actual difference between tools, resources, and prompts?

The difference is execution control. Resources are data loaded by the Host/User before inference. Tools are functions autonomously executed by the Model during inference. Prompts are reusable conversation templates selected by the User to bootstrap a session.

Approach: Define each by *who* controls it: App/User controls Resources, Model controls Tools, User controls Prompts.

What kinds of resources can an MCP server expose?

An MCP server can expose both static resources (like a specific local file or a hardcoded database schema) and dynamic resources (using URI templates like `user://{id}` to generate content on the fly based on the Host's request).

Approach: Mention that resources can be both static files and dynamically generated data, as long as they are fetched by the Host prior to model execution.

Continue learning

Previous: MCP Architecture: Hosts, Clients, and Servers

Next: Building Servers: The FastMCP Framework

Return to AI Engineering Roadmap