Describing Capabilities
An MCP server is only as useful as a model's understanding of it. Models can't read your code; they read the names, descriptions and schemas you give them. This chapter is about describing capabilities so that models call the right one, with the right arguments, and understand the answer.
In this chapter
- How to write a tool a model can use
- How schemas act as the contract between the model and your code
- How to shape tool results so clients can use them
- How to expose data with resources
- How to write prompts users can reuse
- How to group capabilities into apps
- How to write descriptions agents understand
Your first tool
A tool is a function the model can choose to call. Its name, description and input schema are all the model knows about it, so a tool with a vague name and no description is nearly invisible, however good the code is.
Ready to learn this topic?
Learn the four parts of a @Tool, what FrontMCP checks before your code runs, and how to return errors the model can act on.
Schemas are contracts
Every argument you declare with Zod becomes part of the JSON Schema the model reads, and every call is checked against it before execute() runs. Constraints belong in the schema, not in if statements, because the model can see a schema and can't see your code.
import { Tool, ToolContext, z } from "@frontmcp/sdk";
@Tool({
name: "schedule_callback",
description: "Schedule a phone call back to a customer",
inputSchema: {
phone: z.string().min(7).describe("Phone number with country code"),
when: z.enum(["today", "tomorrow_morning", "tomorrow_afternoon"]),
note: z.string().max(200).optional(),
},
})
export class ScheduleCallback extends ToolContext {
async execute(input: { phone: string; when: "today" | "tomorrow_morning" | "tomorrow_afternoon"; note?: string }) {
return { scheduled: true, ...input };
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
Ready to learn this topic?
Learn what the model reads from a Zod schema, why rules belong in the schema instead of if statements, and how optional fields and defaults appear in tools/list.
Shaping tool results
A tool can return plain values or objects. Declaring outputSchema tells clients the shape of the result before they call, and the result arrives as structuredContent that programs can use directly. The Quick Start shows an example.
Ready to learn this topic?
Learn what content and structuredContent carry, when to declare outputSchema, how to return only what the model needs, and how to fail in a way the model can act on.
Exposing data with resources
Not everything should be a tool. Data that an application attaches to a conversation, like a document, a record or a policy, is a resource: addressed by a URI and read with resources/read. @ResourceTemplate covers a family of URIs such as ticket://{id}.
import { Resource, ResourceContext } from "@frontmcp/sdk";
@Resource({
name: "refund-policy",
uri: "docs://refund-policy",
mimeType: "text/markdown",
description: "When customers can get a refund",
})
export class RefundPolicy extends ResourceContext {
async execute(uri: string) {
return {
contents: [{ uri, mimeType: "text/markdown", text: "# Refunds\n\nFull refund within 30 days of purchase." }],
};
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
Ready to learn this topic?
Learn when data should be a resource instead of a tool, how fixed resources and URI templates work, and what clients see in resources/list and resources/read.
Reusable prompts
A prompt is a message template that a user picks, often from a slash menu in their client, with arguments they fill in. Prompts are how you package the instructions that work best with your tools.
Ready to learn this topic?
Learn how to declare a prompt and its arguments, return several messages, and bring ticket data into the conversation.
Read Reusable PromptsGrouping capabilities into apps
An @App bundles related tools, resources, prompts and providers, and a @FrontMcp server can host several apps on one endpoint. The Quick Start shows the three files involved.
Ready to learn this topic?
Learn how apps group capabilities, how a server composes several apps, what happens when two apps use the same name, and how apps share a provider.
Read Grouping Capabilities into AppsWriting descriptions agents understand
Descriptions are prompts. They decide whether a model picks your tool, which of two similar tools it picks, and how it fills in arguments.
Ready to learn this topic?
Learn what to put in a tool's description and its arguments' descriptions, how to say when not to use a tool, and how to test descriptions in tools/list.
What's next?
Start the chapter with Your First Tool. After it, Talking to Clients covers what happens during a call: asking the user for input and reporting progress.