mcp

MCP resources vs tools: when to expose data with resources/list and resources/read

MCP servers can share context as **resources** and expose actions as **tools**. Per the resources spec (2026-07-28), resources "allow servers to share data that provides context to language models, such as files, database schemas, or application-specific information," each identified by a URI. Resources are application-driven: the host decides how to include them. Tools, by contrast, are model-controlled: the language model can discover and invoke them automatically (tools spec, User Interaction Model). This post is about that choice inside MCP. For packaging a workflow as written instructions versus an MCP tool, see skill vs MCP tool.

Resource or tool

All rows follow the resources and tools specs, 2026-07-28.

NeedPreferWhy
Readable context (file, schema, app data) for the host to includeResourceApplication-driven; host decides how to incorporate context
An action the model should choose to runToolModel-controlled; discovered and invoked automatically
Discover what's available`resources/list` or `tools/list`Servers that declare the capability MUST respond
Fetch content by URI`resources/read`Params include `uri`; servers MAY return multiple contents (e.g. a directory)
Run an operation with arguments`tools/call`Model invokes a named tool

Servers that support resources MUST declare the `resources` capability and MUST respond to `resources/list` with the set currently available to the requesting client. That set MAY be empty, MAY change over time, and MAY vary by the authorization on the request (resources spec, Capabilities).

What list and read return

From the resources Protocol Messages and Data Types sections (spec 2026-07-28):

  • `resources/list` returns resource objects with `uri`, `name`, and optional `title`, `description`, `mimeType`, `size`, and `icons`. Supports pagination and caching.
  • `resources/read` takes a `uri` and returns `contents`. Contents are text (`text`) or binary (`blob`, base64). Servers MAY return multiple contents for one read.

Common URI schemes on the resources page: `https://` (client may fetch directly when able), `file://` (filesystem-like; need not map to a physical filesystem), `git://`, plus custom schemes under RFC 3986.

If a resource URI does not exist, servers MUST return JSON-RPC error `-32602` (Invalid Params) and MUST NOT return an empty `contents` array. Servers SHOULD use `-32603` for internal errors (Error Handling).

Security rules from the spec

The resources Security Considerations section (2026-07-28) requires:

  • Servers MUST validate all resource URIs.
  • Access controls SHOULD apply to sensitive resources.
  • Servers MUST sanitize `file://` paths against directory traversal.

Optional pieces (templates, `listChanged` / `subscribe`, annotations such as `audience` / `priority` / `lastModified`) are in the same resources page; they are client hints, not the decision between resource and tool. Tool-behavior hints are covered in MCP tool annotations.

Pitfalls

  • Wrapping every read behind a tool. If the host only needs context, a resource matches the application-driven model; a tool invites the model to call it.
  • Returning an empty `contents` array for a missing URI. The spec forbids that; use `-32602`.
  • Skipping URI validation on `file://`. Path sanitization against directory traversal is a MUST.
  • Re-arguing skills here. Skills are written instructions; resources and tools are protocol primitives. Use skill vs MCP tool for that contrast.

How to check it

Call `resources/list` on your server and confirm the URIs you expect. Then `resources/read` a known URI and a missing one: the known path should return contents, and the missing one should be `-32602`, not an empty array.

Where the kit fits

The MCP Starter Kit ($27) is built for teams putting OAuth-protected remote MCP servers in front of Cursor and Claude Connect. Soft path: start at /free; Cheat Sheet for the skim checklist mindset; kit when you want the auth-ready layout.

Soft next step

List what your server currently exposes as tools, mark anything that is only readable context, and move those to `resources/list` + `resources/read` with URI validation. Soft ladder: /free, then the MCP Starter Kit ($27). Related: OAuth pillar, skill vs MCP tool, MCP tool annotations.

FAQ

What is the difference between an MCP resource and an MCP tool?+

A resource shares context such as files, schemas, or app data, identified by a URI, and is application-driven. A tool is an action the model can discover and call on its own (MCP specification 2026-07-28).

When should a server expose data as a resource instead of a tool?+

Use a resource when you're sharing context for the host to include, not an action for the model to run. Use a tool when the model should decide to invoke something.

What do resources/list and resources/read return?+

`resources/list` returns the resources currently available to that client. `resources/read` takes a `uri` and returns the contents, which may be text or binary, and a server MAY return multiple contents for one read (MCP specification 2026-07-28).

What URI schemes does the MCP resources page define?+

Common schemes in the spec include `https://`, `file://`, and `git://`, plus custom schemes allowed under RFC 3986. A `file://` URI need not map to a physical filesystem.

What error does a server return if a resource URI does not exist?+

A JSON-RPC error with code `-32602` (Invalid Params). The server MUST NOT return an empty `contents` array for a missing resource (MCP specification 2026-07-28).

How is this different from packaging a workflow as a skill?+

Resources and tools are MCP protocol primitives a server exposes. A skill is written instructions an agent reads. That packaging decision is a separate contrast; this page stays inside MCP.

Get the free starter

Value first, then a kit when you are ready. No fake urgency. Start with Harness Desk Starter at /free.