Every MCP server you've configured in Claude Code exposes two different kinds of things: tools it can do, and resources it can show you. Tool calls are actions with side effects — run a query, send a message, create a file. Resources are just data: a config file, a log, a database schema, a URI-addressable chunk of content that doesn't need an argument list to make sense of. Most people never notice the distinction because Claude Code handles it automatically. But if you're building or debugging an MCP server, or wondering why some servers show up with a resource browser and others don't, the two-primitive split is the thing to understand.
ListMcpResourcesTool and ReadMcpResourceTool are the built-in pair that make that split usable inside a session. One discovers what's available. The other reads it.
Tools vs. Resources vs. Prompts
MCP defines three primitives a server can expose, and they map to three different jobs:
- Tools — callable actions with typed parameters.
slack_send_message,execute_sql,create_event. Claude decides when to call them based on your request. - Resources — addressable, mostly-static data identified by a URI. A file, a database table's schema, a config blob. No parameters to fill in — you just ask for the URI.
- Prompts — reusable prompt templates a server can offer, often parameterized, meant to be inserted directly into a conversation.
Tools dominate because most useful MCP servers are wrappers around APIs that take actions. But plenty of servers — especially ones backing a database, a documentation set, or a filesystem — also expose resources, and that's where these two tools come in.
What ListMcpResourcesTool Does
ListMcpResourcesTool asks a connected MCP server (or all of them) what resources it currently exposes. The response is a list of URIs, each with a name, an optional description, and a MIME type. Nothing is fetched yet — this is pure discovery, the same way ls shows you filenames without opening any of them.
This matters because resource lists can be dynamic. A database-backed server might expose one resource per table; a project-management server might expose one per active ticket. The list reflects the server's current state, not a fixed manifest, so re-listing after the underlying data changes is normal and expected.
What ReadMcpResourceTool Does
ReadMcpResourceTool takes a specific resource URI (from a list call, or one you already know) and returns its content. Depending on the MIME type, that content might be plain text, JSON, or binary data encoded for transport. This is the equivalent of cat-ing a specific file once you know its path.
The two-step pattern — list, then read — exists because resource sets can be large or expensive to fully materialize. Listing is cheap and tells you what exists; reading is where the actual data transfer happens, and you only pay for it on the resources you actually need.
Why This Is a Separate Tool Pair, Not Automatic
Unlike a lot of Claude Code's built-in behavior, resource access isn't something the model does invisibly in the background the way skills auto-trigger. Resources are explicit: Claude has to decide to list, then decide to read, the same way it decides to call any other tool. That's a deliberate design choice — resource sets can be large, and blindly ingesting every resource on every configured server would blow through context for no reason. Explicit list-then-read keeps resource access purposeful instead of automatic.
Not Every MCP Server Exposes Resources
Most of the MCP servers people actually install — Slack, Notion, Supabase, Vercel — are tool-heavy and resource-light or resource-free, because their job is taking actions, not serving static data. If you run ListMcpResourcesTool against a server like that, you'll typically get an empty or near-empty list, and that's correct behavior, not a bug. Resources show up more often in servers built around a body of content: a docs server, a filesystem bridge, a knowledge base. Check the MCP server setup guide if you're still configuring your first server, or the best MCP servers roundup for ones worth trying.
Exposing Resources From Your Own Server
If you're building an MCP server, adding resources alongside tools is a matter of implementing the resources/list and resources/read handlers in the MCP SDK for your language. The pattern that works well: expose one resource per logical unit of content (one file, one table, one document) rather than trying to cram everything into a single monolithic resource. That keeps individual reads cheap and lets Claude request only what a given task actually needs, instead of pulling an entire dataset to answer a narrow question.
Resources are also a good fit for content that changes independent of any action — a live schema, a status page, a changelog — where a tool call with no parameters would be an awkward substitute for something that's really just "give me the current state of X."
The Practical Takeaway
You'll rarely reach for ListMcpResourcesTool or ReadMcpResourceTool directly — Claude calls them when a task needs data from a resource-exposing server. What's worth knowing is that they exist as a separate lane from tool calls, so if a server you've configured seems to be "hiding" data that isn't behind an explicit action, it's probably sitting in its resource list, one ListMcpResourcesTool call away.