Files
claude-plugins-official/plugins/mcp-server-dev/skills/build-mcp-server/references/resources-and-prompts.md
Den Delimarsky 48a018f27a fix(plugin): mcp-server-dev — correct APIs against spec, add missing primitives
Corrects fabricated/deprecated APIs: ext-apps App class model (not embedded
resources), real MCPB v0.4 manifest (no permissions block exists), registerTool
(not server.tool), @anthropic-ai/mcpb package name, CIMD preferred over DCR.

Adds missing spec coverage: resources, prompts, elicitation (with capability
check + fallback), sampling, roots, tool annotations, structured output,
instructions field, progress/cancellation.
2026-03-18 22:53:38 +00:00

4.0 KiB

Resources & Prompts — the other two primitives

MCP defines three server-side primitives. Tools are model-controlled (Claude decides when to call them). The other two are different:

  • Resources are application-controlled — the host decides what to pull into context
  • Prompts are user-controlled — surfaced as slash commands or menu items

Most servers only need tools. Reach for these when the shape of your integration doesn't fit "Claude calls a function."


Resources

A resource is data identified by a URI. Unlike a tool, it's not called — it's read. The host browses available resources and decides which to load into context.

When a resource beats a tool:

  • Large reference data (docs, schemas, configs) that Claude should be able to browse
  • Content that changes independently of conversation (log files, live data)
  • Anything where "Claude decides to fetch" is the wrong mental model

When a tool is better:

  • The operation has side effects
  • The result depends on parameters Claude chooses
  • You want Claude (not the host UI) to decide when to pull it in

Static resources

// TypeScript SDK
server.registerResource(
  "config",
  "config://app/settings",
  { name: "App Settings", description: "Current configuration", mimeType: "application/json" },
  async (uri) => ({
    contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(config) }],
  }),
);
# fastmcp
@mcp.resource("config://app/settings")
def get_settings() -> str:
    """Current application configuration."""
    return json.dumps(config)

Dynamic resources (URI templates)

RFC 6570 templates let one registration serve many URIs:

import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";

server.registerResource(
  "file",
  new ResourceTemplate("file:///{path}", { list: undefined }),
  { name: "File", description: "Read a file from the workspace" },
  async (uri, { path }) => ({
    contents: [{ uri: uri.href, text: await fs.readFile(path, "utf8") }],
  }),
);
@mcp.resource("file:///{path}")
def read_file(path: str) -> str:
    return Path(path).read_text()

Subscriptions

Resources can notify the client when they change. Declare subscribe: true in capabilities, then emit notifications/resources/updated. The host re-reads. Useful for log tails, live dashboards, watched files.


Prompts

A prompt is a parameterized message template. The host surfaces it as a slash command or menu item. The user picks it, fills in arguments, and the resulting messages land in the conversation.

When to use: canned workflows users run repeatedly — /summarize-thread, /draft-reply, /explain-error. Near-zero code, high UX leverage.

server.registerPrompt(
  "summarize",
  {
    title: "Summarize document",
    description: "Generate a concise summary of the given text",
    argsSchema: { text: z.string(), max_words: z.string().optional() },
  },
  ({ text, max_words }) => ({
    messages: [{
      role: "user",
      content: { type: "text", text: `Summarize in ${max_words ?? "100"} words:\n\n${text}` },
    }],
  }),
);
@mcp.prompt
def summarize(text: str, max_words: str = "100") -> str:
    """Generate a concise summary of the given text."""
    return f"Summarize in {max_words} words:\n\n{text}"

Constraints:

  • Arguments are string-only (no numbers, booleans, objects) — convert inside the handler
  • Returns a messages[] array — can include embedded resources/images, not just text
  • No side effects — the handler just builds a message, it doesn't do anything

Quick decision table

You want to... Use
Let Claude fetch something on demand, with parameters Tool
Expose browsable context (files, docs, schemas) Resource
Expose a dynamic family of things (db://{table}) Resource template
Give users a one-click workflow Prompt
Ask the user something mid-tool Elicitation (see elicitation.md)