CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
MCP Has Three Primitives, Not One: Add Resources and Prompts to Make Your Server Actually Useful

MCP Has Three Primitives, Not One: Add Resources and Prompts to Make Your Server Actually Useful

Chris Harper

3 min read

Jul 5, 2026 · 20:03 UTC

AI
Tutorial
MCP
Agents
Best Practices

TL;DR: MCP has three primitives — tools (model-controlled), prompts (user-triggered), and resources (app-injected) — and using all three lifts multi-step workflow reliability from ~60% to 90%+.

What you'll be able to do after this:

  • Know when to use a tool, prompt, or resource — and why the control-plane split changes reliability
  • Define @mcp.resource() URI templates and @mcp.prompt() workflows in FastMCP Python
  • Structure deterministic steps server-side and let the LLM handle only language tasks

The three control planes

Most MCP servers only implement tools. But the spec defines two more:

PrimitiveControlled byBest for
ToolsThe modelSingle actions: search, API calls, file writes
PromptsThe userRepeating workflows: weekly reports, incident runbooks
ResourcesThe host appStatic context: schemas, docs, config, templates

The reliability difference is measurable. When the LLM orchestrates a multi-step report using only tools, it gets the sequence right ~60–70% of the time — it picks the wrong step order, recalculates things the server should have computed, or skips a step entirely. When you encode the data-fetch steps as a prompt (the server runs them deterministically, the LLM handles only the summary), compliance rises to 85–95%.

Adding resources in FastMCP

A resource is a URI-addressable, read-only data source. The host app decides when to inject it; the model never has to ask.

from fastmcp import FastMCP

mcp = FastMCP(name="MyServer")

# Static resource — same content every time
@mcp.resource("docs://schema/sales")
def sales_schema() -> str:
    """Sales database schema for context injection."""
    return "# Sales Schema\n## tables: orders, customers, products..."

# Dynamic resource — URI template maps path params to function args
@mcp.resource("config://{env}/limits")
def rate_limits(env: str) -> dict:
    return {"env": env, "requests_per_min": 1000 if env == "prod" else 100}

Use URI scheme prefixes (docs://, config://, data://) to organize by type. Resources can be text or binary (base64) and support RFC 6570 URI templates for dynamic lookup.

Adding prompts in FastMCP

A prompt is a reusable workflow template the host surfaces as a slash command. When a user triggers it, the server runs deterministic steps first and passes the results to the LLM.

@mcp.prompt
def weekly_sales_report(week: str) -> str:
    """Weekly sales report — server fetches data, LLM summarizes."""
    # In production: fetch + aggregate data here before returning
    return (
        f"Summarize sales data for week {week}. "
        "Focus on top SKUs and week-over-week percentage changes."
    )

# Multi-turn prompt with explicit messages
from fastmcp.prompts import Message

@mcp.prompt
def incident_runbook(service: str, severity: str) -> list[Message]:
    return [
        Message(f"Service: {service} | Severity: {severity}"),
        Message(
            "Logs and deployment history are pre-fetched above. "
            "Draft a mitigation summary and list the three highest-priority next steps."
        ),
    ]

Steps 1–3 (fetch service status, pull logs, get deployment history) execute server-side. Step 4 (write the summary) goes to the LLM. Data flows explicitly — the model never has to track workflow state.

The bridge pattern for today

Most MCP clients support resources/list and resources/read but lack a native resource-picker UI. Pragmatic workaround: also expose critical resources as tools so the model can request them directly:

@mcp.tool
def get_sales_schema() -> str:
    """Returns the sales database schema."""
    return sales_schema()   # same function, two surfaces

Once clients add native resource pickers, the tool wrapper disappears. Build the resource now; the bridge costs nothing to remove later.

Sources: MCP Prompts and Resources: The Primitives You're Not Using — DEV Community, Prompts — FastMCP docs, Resources — MCP official docs