Core Concepts: Tools, Resources, Templates, And Prompts
This document explains the server-owned objects that make up most ZCP and MCP integrations.
Overview
Most application design questions reduce to one choice:
- is this an operation
- is this content
- is this prompt scaffolding
In ZCP and MCP terms, that means choosing between:
- tools
- resources and resource templates
- prompts
Making that choice correctly matters for token efficiency, client discovery, auth boundaries, and long-term API stability.
Tools
Tools are callable server-side operations. They are the right fit when the client needs to ask the server to do something, not just read something.
Typical tool metadata includes:
nametitledescriptioninputSchemaoutputSchemaannotationsiconsexecution_meta
In the Python SDK, tools are usually registered with FastZCP.tool(...).
from zcp import FastZCP
app = FastZCP("Operations Backend")
@app.tool(
name="incident.create",
description="Create an incident ticket.",
input_schema={
"type": "object",
"properties": {
"title": {"type": "string"},
"severity": {"type": "string", "enum": ["sev1", "sev2", "sev3"]},
},
"required": ["title", "severity"],
"additionalProperties": False,
},
output_schema={
"type": "object",
"properties": {
"incidentId": {"type": "string"},
"url": {"type": "string"},
},
"required": ["incidentId", "url"],
},
output_mode="scalar",
inline_ok=True,
)
def create_incident(title: str, severity: str, ctx=None):
return {"incidentId": "INC-123", "url": "https://ops.example.com/INC-123"}When To Use A Tool
Use a tool when the server is expected to:
- perform a query with arguments
- cause a side effect
- execute a workflow
- validate structured input
- enforce policy before work happens
Examples:
- search a ticketing system
- send an email
- start a deployment
- fetch a scoped record from a backend API
Tool Output Modes
ZCP supports both MCP-facing structured outputs and native runtime-oriented optimizations.
Use inline structured output when:
- results are small
- the client or model needs them immediately
- output schema validation matters
Prefer handle-oriented or off-context storage when:
- results are large
- the full payload should not be repeated into prompt context
- clients can retrieve or reference the artifact later
This is one of the main places where native ZCP can be more token efficient than plain MCP-style usage.
Execution Metadata
Tool execution metadata is where runtime behavior becomes explicit. Common examples include:
- task support
- approval requirements
- scheduling hints
- other implementation-specific runtime metadata
If a tool can run as a task, document that. Do not force clients to infer it.
Tool Design Guidance
Prefer:
- stable names such as
domain.action - narrow JSON schemas
- explicit descriptions of side effects
- output schemas when structured content matters
- one tool per clear business operation
Avoid:
- giant "do everything" tools
- weakly typed argument bags
- descriptions that contain policy hidden in prose
- pushing static reference data through tool calls
Resources
Resources are readable server-owned content addressed by a URI.
Examples:
weather://citiesfile:///workspace/README.mddb://schemas/public/userstenant://acme/config
In the Python SDK, resources are registered with FastZCP.resource(...).
@app.resource(
"tenant://acme/config",
name="Tenant Config",
mime_type="application/json",
)
def tenant_config():
return {"region": "us-east-1", "features": ["alerts", "audit"]}When To Use A Resource
Use a resource when the primary action is:
- read
- inspect
- browse
- subscribe to updates
Examples:
- generated reports
- source files
- schemas
- tenant settings
- inventories
Resource Content Shapes
The runtime can project different handler outputs into MCP-compatible content:
- text-like output becomes text content
- JSON-like output becomes structured or serialized content
- binary output becomes blob content
This lets one resource model cover both simple and rich content.
Subscriptions
If a resource can change and clients care about updates, make that explicit with subscriptions and notifications/resources/updated. Use subscriptions for content that behaves like data, not for workflows that should really be tasks.
Resource Templates
A resource template advertises a parameterized family of URIs without listing every concrete instance.
Example:
@app.resource_template(
"repo://{owner}/{name}/issues/{id}",
name="Repository Issue",
mime_type="application/json",
)
def repo_issue(uri: str):
return {"uri": uri}Use templates when:
- the URI space is large
- instances are predictable
- discovery matters more than pre-enumeration
Templates are especially useful for file-like and entity-like data where a client can fill in parameters after discovery.
Prompts
Prompts are server-owned prompt templates that return messages, not executable logic. They centralize prompt construction so clients do not have to rebuild the same structure themselves.
In the Python SDK, prompts are registered with FastZCP.prompt(...).
from zcp import PromptArgument
@app.prompt(
name="incident.summary",
description="Build a handoff prompt for an on-call engineer.",
arguments=[
PromptArgument(name="incident_id", required=True),
PromptArgument(name="audience"),
],
)
def incident_summary_prompt(incident_id: str, audience: str | None = None):
return [
{"role": "system", "content": "You write concise incident summaries."},
{
"role": "user",
"content": f"Summarize incident {incident_id} for {audience or 'an engineer'}.",
},
]When To Use A Prompt
Use a prompt when:
- prompt construction should be owned by the backend
- many clients need the same template
- arguments should be discoverable
- prompt structure is part of the product surface
Examples:
- report summarization
- code review scaffolding
- incident handoff prompts
- domain-specific investigation templates
Prompts Are Not Tools
A prompt should not be used to smuggle executable logic or validation rules.
Tools do work. Resources expose content. Prompts define reusable prompt scaffolding.
If the output must be validated or executed, the prompt probably should not be the primary abstraction.
Choosing The Right Primitive
Use this rule:
- choose a tool for an operation
- choose a resource for readable content
- choose a prompt for reusable prompt assembly
When in doubt, ask what a client is trying to do:
- "run something" means tool
- "read something" means resource
- "build messages" means prompt
ZCP-Specific Advantage
The MCP projection intentionally looks familiar. The underlying runtime is not limited to the same prompt-visible overhead.
ZCP can:
- keep canonical validation out of prompt context
- avoid repeatedly resending large registries in native flows
- store large outputs behind handles or runtime state
- preserve official MCP response shapes at the compatibility boundary
That is the practical reason this distinction matters in ZCP instead of being just an abstract taxonomy exercise.