Blog · 2026-06-18

MCP resources and prompts, beyond tools

MCP is more than tools. Resources give assistants reference data to load, prompts ship reusable instructions. When to use each, with runnable code.

An MCP server can expose three things, and tools are only one of them. Resources are reference data the assistant loads into context, a policy document, a dataset, a config. Prompts are reusable, parameterized instructions the user invokes by name. On DenkOps you declare all three in the same defineMcp call, and the connector serves them from one /mcp endpoint.

What is a resource?

A resource is something the client reads, not something the model calls with arguments. It has a stable uri the client lists and fetches, an optional description and mimeType, and a read function that returns the contents as { text } (or { blob } for binary data):

  • uri: the identifier, like docs://support/returns-policy.
  • read(): returns the current contents each time it is fetched.

Because reading has no side effects and no arguments, clients can show resources to users directly, attach them to a conversation, and refresh them cheaply. A resource is a noun.

What is a prompt?

A prompt is a recipe with blanks. It has a description, an optional input schema for the blanks, and a build function that turns the arguments into messages, each { role: "user" | "assistant", content }. Clients surface prompts as named commands the user picks, so your best "here is exactly how to ask for this" phrasing ships with the server instead of living in a wiki.

What does all three together look like?

A small support kit, complete and deployable:

import { z } from "zod";
import { defineMcp } from "@denkopsai/sdk/mcp";

const POLICY = `Refunds within 30 days of delivery.
Store credit up to 90 days. No returns on custom items.`;

export default defineMcp({
  name: "support-kit",
  version: "1.0.0",
  tools: {
    lookup_order: {
      description: "Fetch the status of one order by id.",
      input: z.object({ id: z.string() }),
      handler: ({ id }) => ({ id, status: "shipped" }),
    },
  },
  resources: {
    returns_policy: {
      uri: "docs://support/returns-policy",
      description: "The current returns policy.",
      mimeType: "text/markdown",
      read: () => ({ text: POLICY }),
    },
  },
  prompts: {
    refund_reply: {
      description: "Draft a reply to a refund request.",
      input: z.object({ orderId: z.string() }),
      build: ({ orderId }) => [
        {
          role: "user",
          content: `Look up order ${orderId} with lookup_order, check it against the returns policy resource, and draft a short, friendly reply.`,
        },
      ],
    },
  },
});

Note how the three reference each other: the prompt tells the assistant to use the tool and the resource. That composition is the payoff of not forcing everything into tools.

When do I use a tool, a resource, or a prompt?

  • Tool: the model decides to act. Anything with arguments, side effects, or a computed answer. lookup_order must be a tool, and its inputs deserve a real schema.
  • Resource: stable reference data with no arguments. Serving the policy as a resource beats a get_policy tool: no tool-call round trip, and the user can read the exact text the model saw.
  • Prompt: the human decides to start a workflow. If you keep pasting the same instructions into a chat, that text is a prompt definition waiting to happen.

Rule of thumb: verbs are tools, nouns are resources, recipes are prompts.

Deployment is unchanged: this file is a complete server, and one deploy puts it at a live HTTPS URL. Every MCP client that supports remote servers discovers resources and prompts through the same listing calls it uses for tools, so there is nothing extra to configure.

FAQ

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

A tool is invoked by the model with arguments and may have side effects. A resource is read-only reference data at a stable URI, fetched without arguments by the client. If the assistant should load it rather than do it, make it a resource.

How do MCP prompts reach the user?

The client lists your server's prompts and shows them as named commands. When the user picks one and fills in the arguments, the server's build function returns ready-made messages that start the conversation, so the phrasing is consistent every time.

Can one DenkOps MCP server expose tools, resources, and prompts at once?

Yes. defineMcp takes tools, resources, and prompts maps in a single config, and serves them all from the same /mcp endpoint. Clients discover each kind through standard listing requests, with no extra routing or configuration on your side.

Ship it yourself: bunx denkops deploy or say "deploy on DenkOps" from your coding agent.

Start on DenkOps →

← Use your MCP connector with OpenAI Codex · Auth by default: closed until you open it →