# Describing Capabilities

> How to describe what your MCP server can do, so AI models use it well. Tools, schemas, results, resources, prompts and apps.

Source: https://frontmcp.dev/learn/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](https://frontmcp.dev/learn/your-first-tool)
- [How schemas act as the contract between the model and your code](https://frontmcp.dev/learn/schemas-are-contracts)
- [How to shape tool results so clients can use them](https://frontmcp.dev/learn/shaping-tool-results)
- [How to expose data with resources](https://frontmcp.dev/learn/exposing-data-with-resources)
- [How to write prompts users can reuse](https://frontmcp.dev/learn/reusable-prompts)
- [How to group capabilities into apps](https://frontmcp.dev/learn/grouping-capabilities-into-apps)
- [How to write descriptions agents understand](https://frontmcp.dev/learn/writing-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.

Read more: [Your First Tool](https://frontmcp.dev/learn/your-first-tool)
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.

```ts schedule.tool.ts
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 };
  }
}
```

Read more: [Schemas Are Contracts](https://frontmcp.dev/learn/schemas-are-contracts)
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](https://frontmcp.dev/learn#returning-structured-results) shows an example.

Read more: [Shaping Tool Results](https://frontmcp.dev/learn/shaping-tool-results)
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}`.

```ts policy.resource.ts
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." }],
    };
  }
}
```

Read more: [Exposing Data with Resources](https://frontmcp.dev/learn/exposing-data-with-resources)
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.

Read more: [Reusable Prompts](https://frontmcp.dev/learn/reusable-prompts)
Learn how to declare a prompt and its arguments, return several messages, and bring ticket data into the conversation.

## Grouping 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](https://frontmcp.dev/learn#grouping-capabilities-into-an-app-and-a-server) shows the three files involved.

Read more: [Grouping Capabilities into Apps](https://frontmcp.dev/learn/grouping-capabilities-into-apps)
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.

## Writing 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.

Read more: [Writing Descriptions Agents Understand](https://frontmcp.dev/learn/writing-descriptions-agents-understand)
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](https://frontmcp.dev/learn/your-first-tool). After it, [Talking to Clients](https://frontmcp.dev/learn/talking-to-clients) covers what happens during a call: asking the user for input and reporting progress.
