# MCP Server Examples: A Tool, a Resource, and a Prompt

> MCP server examples in one Python file: a tool, a resource, and a prompt on mcp 2.3.0. unit_price(250, 3) returned 750.

By Tayyab Javed, freelance AI agent developer (https://hireagentic.dev) · Published October 19, 2026 · Tutorial · 5 min read
Canonical URL: https://hireagentic.dev/blog/mcp-server-examples

An MCP server example worth copying registers three things in one file: a tool the model calls, a resource the host reads, and a prompt the host fills in. The notes echo already lives in [how to build an MCP server](https://hireagentic.dev/blog/how-to-build-an-mcp-server). This page is the other three, tested on the Python SDK.

By Tayyab Javed, AI agent developer

## Quick answer

Install `mcp[cli]==2.3.0` on Python 3.11 or newer. Decorate one function with `@mcp.tool()`, one with `@mcp.resource()`, and one with `@mcp.prompt()`. I connected an in-process client to the server below. `unit_price(250, 3)` returned `750`. A call missing `quantity` came back as an error before the function ran.

## What does one MCP server example contain?

Tools are functions. Resources are data, read by URI. Prompts are reusable message templates. A server that only echoes a string teaches the tool and hides the other two. The file below is the set I actually imported. More of this cluster is on the [MCP servers hub](https://hireagentic.dev/topics/mcp).

```bash
pip install "mcp[cli]==2.3.0"
```

```python
from mcp.server import MCPServer

mcp = MCPServer("examples")

@mcp.tool()
def unit_price(cents: int, quantity: int) -> str:
    """Return the line total in cents."""
    return str(cents * quantity)

@mcp.resource("policy://returns")
def returns_policy() -> str:
    """The return rule the model should quote."""
    return "Returns are accepted within 30 days. Refunds go to the original payment method."

@mcp.prompt()
def explain_charge(sku: str) -> str:
    """Ask the model to explain one charge in plain language."""
    return f"Explain the charge for {sku} in two sentences. Do not offer a refund."

if __name__ == "__main__":
    mcp.run()
```

You do not write a JSON Schema. `cents: int` is the schema. The docstring is the description. On mcp 2.3.0, `list_tools` named the tool `unit_price` and required both integers. Calling it with `{"cents": 250, "quantity": 3}` returned the text `750`. Reading `policy://returns` returned the 30-day sentence as `text/plain`. `explain_charge` with `sku` set to `SKU-9` returned one user message: "Explain the charge for SKU-9 in two sentences. Do not offer a refund."

## How do you run this MCP server example?

`mcp.run()` speaks stdio. A host such as Claude Desktop or Cursor starts the process and owns its lifetime. Log to stderr if you add logs. stdout is the protocol. I did not leave a process running. I connected `mcp.Client` to the server object in the same Python process, which is the SDK's in-process path, and called the three primitives from there.

A call with `quantity` missing did not reach `unit_price`. The client received `is_error` true and the text `Error executing tool unit_price`, naming `quantity` as a missing field. That is the check you want before a model is in the loop. Wiring a host, and the Inspector command, is the build guide linked above. When the tool should stay inside one program instead of a server, read [MCP vs function calling](https://hireagentic.dev/blog/mcp-vs-function-calling).

## What should you not copy from an MCP server example?

Copy the three registrations. Do not copy a toy tool onto a refund, a file write, or a database update and call it done. This example only multiplies two integers and returns text. A write needs a person, a timeout, and a credential the model cannot see. The reference servers that already do those jobs are on the [MCP server list](https://hireagentic.dev/blog/mcp-server-list).

## In practice

I check the three registrations before I care which host will start the process. A tool is the only thing the model should call. A resource holds a rule the model should quote, not invent. A prompt is the template, and the constraint belongs in that template. The mistake is one function that tries to be all three, or a toy multiplier later pointed at a refund or a file write. My default is one of each, returning text, with the credential kept where the model cannot see it. I call them from an in-process client first, including a call that drops a required argument. I wire a host only after that error comes back before the function runs.

## Frequently Asked Questions

### Where is a minimal MCP server example?

The file on this page is one tool, one resource, and one prompt on mcp 2.3.0. `unit_price(250, 3)` returned 750. The notes server, which is a single echo tool in Python and TypeScript, is a separate post.

### Do MCP server examples include authentication?

Not this one. Stdio has no network, so there is nothing to authenticate. Put bearer-token checks on Streamable HTTP before anyone else can call the process.

### Want an example turned into a server?

Free 30-minute scoping call. We will pick the tool, the resource, and where a write has to stop for a person.

[Book a Scoping Call](https://cal.com/tayyab-javed-ubhldo/30min)
