MCP servers expose three capability types to clients: tools, resources, and prompts. These three types are not interchangeable — they represent fundamentally different interaction patterns, and choosing the right one for each capability you want to expose is a core design decision when building an MCP server. Getting this wrong leads to servers that are awkward to use, inefficient, or that misuse the protocol in ways that break client compatibility.
Tools: Callable Actions
Tools are the most familiar MCP capability — they are directly analogous to function calling. A tool is a named, callable function with a defined input schema. The client asks the model whether to call a tool, the model requests a tool invocation with specific arguments, the client sends the invocation to the server, the server executes it and returns a result, and the client passes the result back to the model. Tools are designed for operations that have side effects or that perform computation: running a search query, executing a database write, sending a notification, calling an external API, running code. The defining characteristic of a tool is that calling it does something — it produces a result that depends on the inputs and potentially changes external state. Examples: search_web(query), create_file(path, content), execute_sql(query), send_email(to, subject, body).
Resources: Readable Data
Resources are data sources that the client can read — they are closer to files or database records than to functions. A resource has a URI (like file:///path/to/document or db://mydb/table/record-id) and returns content when read. Resources are designed for data access that does not have side effects: reading a file, retrieving a record, accessing a document. The model can request that a specific resource be loaded into its context without “calling” it like a function — the client fetches the resource content and provides it to the model as context. Resources support two access patterns: direct reading (the client fetches the resource by URI) and subscription (the client can subscribe to a resource and receive updates when its content changes, useful for live data feeds). Examples: file:///project/README.md, db://users/user-123, github://repo/main/src/app.py.
The Key Distinction
The clearest way to distinguish tools from resources: if the operation takes input parameters and produces output that depends on those parameters, it is a tool. If the operation retrieves a piece of content identified by a stable URI, it is a resource. A search function that takes a query string is a tool. A document that can be read at a stable path is a resource. A function that creates a new database record is a tool. An existing database record readable by its ID is a resource. The distinction matters for how clients handle each type: tools require the model to decide when and how to call them; resources can be loaded proactively by the client without model involvement, or exposed to the model as selectable context items.
Figure 1 — MCP capability types: when to use each
Prompts: Reusable Templates
Prompts are the third MCP capability type and the least commonly used. An MCP prompt is a named, parameterised prompt template stored on the server that clients can list and invoke. When a user invokes a prompt by name, the server returns the prompt text (potentially with arguments filled in), which the client inserts into the conversation. This mechanism allows server operators to define standardised workflows for common tasks: a code review server might expose a “review-code” prompt that applies a consistent review methodology; a documentation server might expose a “summarise-document” prompt. Prompts are not executed like tools — they return text that is used to guide the conversation, not results that are processed programmatically. In practice, prompts are less widely implemented than tools and resources, partly because the same outcome can often be achieved by including prompt templates in the user interface rather than serving them from the MCP server.
Common Design Mistakes
Several recurring design mistakes appear when developers first build MCP servers. Modelling read operations as tools: a function that retrieves a user record by ID should be a resource (db://users/user-id), not a tool. Using tools for reads is technically functional but misuses the protocol — clients may treat tool calls differently from resource reads, and the model is asked to “decide” to call a retrieval operation rather than simply having the data available. Over-splitting tools: creating one tool per database table or one tool per API endpoint produces a very large tool list that overwhelms the model’s tool selection. Better to create general-purpose tools with flexible parameters (query_database(sql)) that cover many operations, and reserve specific tools for the most common or most constrained operations. Under-using resources: documents, files, and configuration that could be served as resources are often wrapped in tools unnecessarily. Clients that support resource browsing give users a cleaner experience with resources than with tool calls.
Client-Side Handling Differences
MCP clients handle tools and resources differently in their user interfaces. In Claude Desktop, tools appear as capabilities the model can invoke autonomously — the user approves tool calls. Resources appear as items the user can browse and attach to the conversation — the user selects which resources to include. This distinction matters for user experience design: operations the model should initiate on its own judgement belong as tools; data sources the user should be able to browse and select belong as resources. A document management server that exposes all documents as tools (one tool per document type, callable with a document ID) creates a poor user experience compared to exposing documents as browsable resources with a search tool for discovery.
Building a Well-Structured MCP Server
A well-structured MCP server typically has a small number of general-purpose tools (5–15), a potentially large collection of resources (organised by URI hierarchy), and zero to a few prompts. The tools cover actions and computations; the resources cover data access. For a GitHub MCP server: tools include create_issue, create_pull_request, merge_pull_request, run_workflow; resources include github://repo/issues/123, github://repo/pulls/456, github://repo/main/file.py. The read operations are resources; the write and action operations are tools. This structure makes the server’s capability model clear and works correctly with clients that handle tools and resources through different UI patterns.
The tools-resources-prompts distinction is not just a naming convention — it shapes how clients present server capabilities to users and how the model interacts with them. Implement tools for actions and computations, resources for data access, and prompts for reusable workflow templates. The investment in getting this right is modest, and the payoff is a server that integrates cleanly with the full range of MCP clients rather than one that works with some and has awkward behaviour with others.
Tool Annotations: Communicating Safety Properties
MCP’s tool definition supports annotations that communicate important safety properties to clients, helping them decide whether to execute tools automatically or require user confirmation. The readOnlyHint annotation signals that a tool does not modify external state — clients can safely execute it without user confirmation for every call. The destructiveHint annotation signals that a tool may permanently delete or modify data — clients should always prompt the user before executing. The idempotentHint signals that calling the tool multiple times with the same arguments produces the same result — safe to retry on failure. The openWorldHint signals that the tool interacts with external services beyond the local system. These annotations are hints, not enforced constraints — a misbehaving server could annotate a destructive tool as read-only — but well-implemented servers use them correctly, and clients that understand these annotations provide significantly better safety UX than those that treat all tools identically.
Resource URI Design
Resource URIs should follow consistent, hierarchical patterns that are legible to both the model and human users. A well-designed URI scheme for a database server might be db://databasename/tablename/record-id for individual records and db://databasename/tablename for table-level access. A filesystem server uses file:///absolute/path/to/file. A GitHub server uses github://owner/repo/branch/path. Inconsistent or opaque URI schemes make resources harder for models to reason about and harder for users to understand in clients that display resource URIs. The URI scheme (the part before ://) should be unique to your server type — using generic schemes like https:// for non-HTTP resources creates ambiguity. Resources should also implement listResources so clients can browse available resources, not just access them by known URI — discoverability is part of the resource contract.