When to Use Resources vs Tools

Resources and tools both provide data to AI clients, but they serve fundamentally different purposes. Understanding when to use each leads to cleaner designs and better AI behavior, and in building domain specific MCP servers.

The Key Distinction

AspectResourcesTools
PurposeProvide stable dataPerform actions
IdentityAddressable by URIInvoked by name
Side effectsNoneMay have side effects
CachingOften cached by clientsNot cached
AI perceptionContext/reference dataOperations to perform

Think of it this way:

  • Resources are nouns: "the customer schema", "the configuration"
  • Tools are verbs: "query the database", "update the record"

Decision Framework

Use this flowchart to decide:

┌─────────────────────────────────────────────────────────────┐
│ Does the operation have side effects?                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   YES ──► Use a TOOL                                        │
│           - Database modifications                          │
│           - External API calls that mutate                  │
│           - Sending notifications                           │
│           - Creating files                                  │
│                                                             │
│   NO ──► Does the data have a stable identity?              │
│          │                                                  │
│          ├─ YES ──► Use a RESOURCE                          │
│          │          - Schema definitions                    │
│          │          - Configuration                         │
│          │          - Reference data                        │
│          │          - Static documentation                  │
│          │                                                  │
│          └─ NO ──► Does it require computation?             │
│                    │                                        │
│                    ├─ YES ──► Use a TOOL                    │
│                    │          - Complex queries             │
│                    │          - Aggregations                │
│                    │          - Reports                     │
│                    │                                        │
│                    └─ NO ──► Use a RESOURCE                 │
│                               - Simple lookups              │
│                               - Cached data                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Resources: Best Use Cases

1. Schema and Structure Information

Schemas rarely change and are essential context:

#![allow(unused)]
fn main() {
// Database schema - AI reads to understand what queries are valid
Resource::new("db://schema/customers")
    .name("Customers Table Schema")
    .description("Column names, types, and relationships for customers table")
    .mime_type("application/json")

// API schema - AI reads to construct valid requests
Resource::new("api://openapi/v1")
    .name("API Specification")
    .description("OpenAPI specification for the REST API")
    .mime_type("application/json")
}

2. Configuration and Settings

Current configuration that guides tool usage:

#![allow(unused)]
fn main() {
// Feature flags - AI reads to know what's enabled
Resource::new("config://features")
    .name("Feature Flags")
    .description("Currently enabled features and experiments")

// Limits and quotas - AI reads to stay within bounds
Resource::new("config://limits")
    .name("Service Limits")
    .description("Rate limits, quotas, and maximum values")
}

3. Reference Data

Static or slowly-changing reference data:

#![allow(unused)]
fn main() {
// Region codes - AI reads when constructing queries
Resource::new("reference://regions")
    .name("Sales Regions")
    .description("Region codes, names, and territories")

// Product catalog - AI reads for lookups
Resource::new("reference://products")
    .name("Product Catalog")
    .description("Product IDs, names, categories, and attributes")
}

4. Documentation and Help

In-context documentation:

#![allow(unused)]
fn main() {
// Query syntax help
Resource::new("docs://sql-guide")
    .name("SQL Query Guide")
    .description("Supported SQL syntax with examples")

// Best practices
Resource::new("docs://best-practices")
    .name("API Best Practices")
    .description("Recommended patterns for using this API")
}

Tools: Best Use Cases

1. Data Queries with Parameters

Queries that need runtime input:

#![allow(unused)]
fn main() {
// Query tool - parameters determine what's returned
Tool::new("sales_query")
    .description("Query sales data with filters")
    .input_schema(json!({
        "properties": {
            "date_range": { ... },
            "region": { ... },
            "product_category": { ... }
        }
    }))
}

2. Write Operations

Any operation that modifies state:

#![allow(unused)]
fn main() {
// Create operations
Tool::new("order_create")
    .description("Create a new order")

// Update operations
Tool::new("customer_update")
    .description("Update customer information")

// Delete operations
Tool::new("record_delete")
    .description("Delete a record")
}

3. External API Calls

Interactions with external services:

#![allow(unused)]
fn main() {
// Third-party integrations
Tool::new("send_email")
    .description("Send email via SendGrid")

// Payment processing
Tool::new("process_payment")
    .description("Process payment via Stripe")
}

4. Computed Results

Operations requiring significant computation:

#![allow(unused)]
fn main() {
// Aggregation
Tool::new("sales_report")
    .description("Generate sales report with totals and averages")

// Analysis
Tool::new("trend_analysis")
    .description("Analyze trends in historical data")
}

Common Mistakes

Mistake 1: Read Operations as Tools

#![allow(unused)]
fn main() {
// WRONG: This is just reading data
Tool::new("get_schema")
    .description("Get the database schema")

// RIGHT: Stable data should be a resource
Resource::new("db://schema")
    .description("Database schema")
}

Mistake 2: Dynamic Data as Resources

#![allow(unused)]
fn main() {
// WRONG: This data changes based on parameters
Resource::new("sales://today")
    .description("Today's sales data")
// What if user needs yesterday's data?

// RIGHT: Parameterized queries should be tools
Tool::new("sales_query")
    .description("Query sales data for a date range")
    .input_schema(json!({
        "properties": {
            "date": { "type": "string", "format": "date" }
        }
    }))
}

Mistake 3: Actions as Resources

#![allow(unused)]
fn main() {
// WRONG: Has side effects
Resource::new("notifications://send")
    .description("Send a notification")

// RIGHT: Side effects require tools
Tool::new("send_notification")
    .description("Send a notification to a user")
}

Hybrid Patterns

Some scenarios benefit from both resources and tools:

Resource for Context, Tool for Action

#![allow(unused)]
fn main() {
// Resource: schema for understanding
Resource::new("db://schema/orders")
    .description("Order table structure")

// Tool: query for action
Tool::new("order_query")
    .description("Query orders. See db://schema/orders for available columns.")
}

The AI reads the resource to understand the schema, then uses the tool to query.

Resource Templates for Entities

#![allow(unused)]
fn main() {
// Template resource for specific entities
Resource::new("customers://{customer_id}")
    .name("Customer Details")
    .description("Read-only view of a specific customer")

// Tool for modifications
Tool::new("customer_update")
    .description("Update customer fields")
}

Reading customer details is a resource; modifying them is a tool.

Cached Resources for Performance

#![allow(unused)]
fn main() {
// Expensive computation cached as resource
Resource::new("analytics://daily-summary")
    .name("Daily Summary")
    .description("Pre-computed daily analytics (updated hourly)")

// Real-time query as tool
Tool::new("analytics_query")
    .description("Real-time analytics query (slower, but up-to-date)")
}

AI Behavior Differences

Resources and tools trigger different AI behaviors:

Resources

  • AI may read proactively to gather context
  • Clients often cache resource contents
  • AI doesn't count resource reads as "actions"
  • Multiple reads don't concern the AI

Tools

  • AI calls tools deliberately to accomplish goals
  • Each call is an "action" the AI considers
  • AI may hesitate to call tools repeatedly
  • Tool calls may require user confirmation

Design with these behaviors in mind:

  • Put context-setting data in resources (AI reads freely)
  • Put consequential operations in tools (AI considers carefully)

Summary

Use Resources ForUse Tools For
Schemas and structureParameterized queries
ConfigurationWrite operations
Reference dataExternal integrations
DocumentationComputed results
Stable, addressable dataActions with side effects
Context AI reads proactivelyOperations AI performs deliberately

The rule of thumb: if you'd bookmark it, it's a resource. If you'd submit a form, it's a tool.