mirror of
https://github.com/mcp-use/mcp-use.git
synced 2026-09-14 18:06:01 +08:00
8348c59a53
* docs: reorganize navigation and clean up content - Remove 'Misc' group with misplaced blog posts - Remove 'Libraries' redirect group from Home nav - Simplify 'Dev Tools' group (flatten Inspector, CLI, Tunneling) - Remove individual changelog versions from Python nav (keep summary) - Remove changelog from TypeScript 'Get Started' group - Remove tunneling duplicate from Python Development group - Rewrite mcp101 as clean MCP concepts page (was pitch deck) - Delete typescript/blog posts (not technical docs) - Add redirects for deleted blog post URLs * docs: fix content accuracy and remove sloppy language - Fix broken python/server/mcp-apps link in home page - Remove informal pitch-speak from python/server/index.mdx - Fix grammar error in typescript/server/index.mdx - Update typescript/client/logging.mdx: remove fake 'coming soon' API code - Fix non-existent model name gpt-5.1 in typescript quickstart - Fix mcp_use naming in development contributing guide * docs: fix incorrect TypeScript server API calls in inspector docs - Replace server.addTool() with server.tool() (correct mcp-use API) - Add missing zod import to debugging-chatgpt-apps example * docs: fix fake model names (gpt-5.1 → gpt-4o) in agent docs * docs: update model names, fix APIs, and add agent visibility hints - Replace all deprecated model names with latest: gpt-4.1, gpt-4.1-mini, claude-sonnet-4-6, claude-opus-4-7, gemini-2.5-flash across all docs - Fix TypeScript server.tool() API in installation.mdx (old positional string form) - Fix TypeScript agent.run() in quickstart.mdx (deprecated string form → object) - Remove broken manufact.com/docs/llms.txt hidden hints from 5 pages - Add <Visibility for="agents"> block to mcp101.mdx with install commands, key classes, and API signatures for agent-oriented navigation - Add LangChain provider install note to Python quickstart (mcp-use agent requires a separate langchain-* provider package) - Update model name cards in Python llm-integration.mdx * docs: clean up remaining stale model names and improve accuracy - Update supported model lists in Python and TypeScript llm-integration pages - Fix cost optimization table to use current model IDs - Update TypeScript agent overview supported providers list * docs: add LangChain provider install to TypeScript quickstart agent section The MCPAgent requires a separate @langchain/* provider package; this was not mentioned before the code example that imports from @langchain/openai. * docs: update to latest flagship model IDs (May 2026) - OpenAI: gpt-4.1 → gpt-5.5, gpt-4.1-mini → gpt-5.5-mini - Google: gemini-2.5-flash → gemini-3.1-flash, gemini-2.5-pro → gemini-3.1-pro - Groq: llama-3.1-* → llama-4-scout-17b-16e-instruct - Anthropic (claude-opus-4-7, claude-sonnet-4-6) already current, no change * docs: replace all em dashes with hyphens * docs: restore llms.txt hints using Visibility component * docs: simplify TypeScript logging page to unsupported notice only * docs: rewrite mcp101 to explain MCP protocol with mcp-use examples and doc links * docs: remove goal.md * docs: revert nav changes, keep only Misc group removal and blog redirects * docs: reorder mcp101 to Server/App -> Client/Inspector -> Agent, restore title * docs: add code examples for Resources and Prompts in mcp101 * docs: remove em dashes from mcp101 * docs: add MCPClient code examples to mcp101 * docs: add React client example to mcp101 * docs: add agent code examples to mcp101 * docs: expand MCP Apps section in mcp101 with example and links * docs: restore Contacts, Socials, and Founders sections to mcp101 * docs: add context-setting intro paragraph to mcp101 for new readers * docs: add MCP stores section to mcp101 intro with Claude, ChatGPT, Cursor * docs: fix Claude store link * docs: fix ChatGPT store link * docs: fix Cursor store link * docs: replace store Cards with linked image grid * docs: add captions to store images * docs: add Notifications to client primitives table in mcp101 * docs: add lead-in paragraph before resource cards at bottom of mcp101 * docs: move resource cards to end of page after Contacts/Socials/Founders * docs: demote Contacts/Socials/Founders to bold text to remove from TOC * docs: move Contacts/Socials/Founders to very end of mcp101 * docs: add Resources and Contacts section headers, link official MCP docs * chore(docs): update site metadata, footer links, and rename mcp_use to mcp-use * update docs metadata + images * docs: enhance MCP section by highlighting the reach of MCP stores with 1 billion weekly active users * api ref
303 lines
8.9 KiB
Plaintext
303 lines
8.9 KiB
Plaintext
---
|
|
title: "Tools"
|
|
description: "Define and expose tools from your MCP server"
|
|
icon: "hammer"
|
|
---
|
|
|
|
Tools are the primary way your MCP server exposes functionality to clients. They represent actions that an AI agent can invoke to perform tasks.
|
|
|
|
## Example
|
|
|
|
```python
|
|
@server.tool(
|
|
name="get_weather",
|
|
title="Weather Information Provider",
|
|
description="Get current weather information for a location",
|
|
annotations=ToolAnnotations(
|
|
readOnlyHint=True,
|
|
openWorldHint=True,
|
|
),
|
|
)
|
|
async def get_weather(
|
|
location: Annotated[str, Field(description="City name or zip code")],
|
|
units: Annotated[str, Field(description="Temperature units", default="celsius")],
|
|
context: Context,
|
|
) -> str:
|
|
"""Get current weather information for a location."""
|
|
await context.info(f"Fetching weather for {location}")
|
|
return f"Weather in {location}: 22 {units}"
|
|
```
|
|
|
|
## Anatomy of a Tool
|
|
|
|
Here's the JSON-RPC response that the example above produces when a client calls `tools/list`:
|
|
|
|
```json
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": {
|
|
"tools": [
|
|
{
|
|
"name": "get_weather",
|
|
"title": "Weather Information Provider",
|
|
"description": "Get current weather information for a location",
|
|
"annotations": {
|
|
"readOnlyHint": true,
|
|
"openWorldHint": true
|
|
},
|
|
"inputSchema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"location": {
|
|
"type": "string",
|
|
"description": "City name or zip code"
|
|
},
|
|
"units": {
|
|
"type": "string",
|
|
"description": "Temperature units",
|
|
"default": "celsius"
|
|
}
|
|
},
|
|
"required": ["location"]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Here's what maps to what:
|
|
|
|
| Python | MCP Schema | Notes |
|
|
|--------|-----------|-------|
|
|
| `name="get_weather"` | `"name"` | Falls back to function name if omitted |
|
|
| `title="Weather Information Provider"` | `"title"` | Human-readable display name |
|
|
| `description="Get current weather..."` | `"description"` | Falls back to docstring if omitted |
|
|
| `annotations=ToolAnnotations(...)` | `"annotations"` | Behavioral hints for clients |
|
|
| `location: str` | `"type": "string"` | Python type hint → JSON Schema type |
|
|
| `Field(description="City name...")` | property `"description"` | Argument-level description |
|
|
| `default="celsius"` | `"default": "celsius"` | Makes the parameter optional |
|
|
| No default on `location` | `"required": ["location"]` | Parameters without defaults are required |
|
|
| `context: Context` | *(not in schema)* | Automatically excluded from the schema |
|
|
|
|
<Tip>
|
|
Always use `Annotated[type, Field(description="...")]` for your tool parameters. Without it, LLMs calling your tool won't know what each argument means.
|
|
</Tip>
|
|
|
|
## Minimal Definition
|
|
|
|
At minimum, a tool only needs a function with type hints:
|
|
|
|
```python
|
|
@server.tool()
|
|
def greet(name: str) -> str:
|
|
"""Greet someone by name."""
|
|
return f"Hello, {name}!"
|
|
```
|
|
|
|
The function name becomes the tool name, the docstring becomes the description, and type hints define the input schema.
|
|
|
|
## Tool Options
|
|
|
|
The `@server.tool()` decorator accepts these options:
|
|
|
|
```python
|
|
@server.tool(
|
|
name="custom_name", # Override the function name
|
|
title="Custom Title", # Human-readable title
|
|
description="Custom desc", # Override the docstring
|
|
annotations=ToolAnnotations( # Behavioral hints for clients
|
|
destructiveHint=True,
|
|
readOnlyHint=False,
|
|
),
|
|
structured_output=True, # Return structured JSON output
|
|
)
|
|
def my_tool(param: str) -> str:
|
|
return param
|
|
```
|
|
|
|
### Tool Annotations
|
|
|
|
Tool annotations provide hints to clients about the tool's behavior:
|
|
|
|
| Annotation | Description |
|
|
|------------|-------------|
|
|
| `destructiveHint` | Tool may modify or delete data |
|
|
| `readOnlyHint` | Tool only reads data, no side effects |
|
|
| `idempotentHint` | Calling multiple times has same effect as once |
|
|
| `openWorldHint` | Tool interacts with external systems |
|
|
|
|
## Async Tools
|
|
|
|
Tools can be async for non-blocking I/O operations:
|
|
|
|
```python
|
|
import httpx
|
|
|
|
@server.tool()
|
|
async def fetch_url(
|
|
url: Annotated[str, Field(description="The URL to fetch content from")],
|
|
) -> str:
|
|
"""Fetch content from a URL."""
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.get(url)
|
|
return response.text
|
|
```
|
|
|
|
## Using Context
|
|
|
|
Access the MCP context for logging and progress reporting. Add a `Context` parameter - it's automatically excluded from the tool's input schema:
|
|
|
|
```python
|
|
from mcp_use.server import Context
|
|
|
|
@server.tool()
|
|
async def long_task(
|
|
items: Annotated[list[str], Field(description="Items to process")],
|
|
context: Context,
|
|
) -> str:
|
|
"""Process items with progress reporting."""
|
|
results = []
|
|
for i, item in enumerate(items):
|
|
await context.report_progress(i, len(items))
|
|
results.append(f"Processed: {item}")
|
|
return "\n".join(results)
|
|
```
|
|
|
|
## Parameter Types and JSON Schema
|
|
|
|
Every tool parameter becomes a property in the tool's `inputSchema`. mcp-use uses [Pydantic](https://docs.pydantic.dev/) to generate [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/schema) from your Python type hints.
|
|
|
|
### Type mapping
|
|
|
|
| Python type | JSON Schema | Notes |
|
|
|-------------|-------------|-------|
|
|
| `str` | `{"type": "string"}` | |
|
|
| `int` | `{"type": "integer"}` | |
|
|
| `float` | `{"type": "number"}` | |
|
|
| `bool` | `{"type": "boolean"}` | |
|
|
| `list[str]` | `{"type": "array", "items": {"type": "string"}}` | Works with any item type |
|
|
| `dict[str, Any]` | `{"type": "object"}` | |
|
|
| `Literal["a", "b"]` | `{"type": "string", "enum": ["a", "b"]}` | Renders as a dropdown in the Inspector |
|
|
|
|
### Required, optional, and nullable
|
|
|
|
How you declare a parameter determines whether it appears in the `required` array:
|
|
|
|
```python
|
|
@server.tool()
|
|
def example(
|
|
# Required - no default, goes into "required"
|
|
name: Annotated[str, Field(description="User name")],
|
|
|
|
# Optional with default - NOT in "required", default shown in schema
|
|
limit: Annotated[int, Field(description="Max results")] = 10,
|
|
|
|
# Nullable - NOT in "required", type stays "string" (not anyOf)
|
|
company: Annotated[str | None, Field(description="Company filter")] = None,
|
|
) -> str: ...
|
|
```
|
|
|
|
This produces:
|
|
|
|
```json
|
|
{
|
|
"properties": {
|
|
"name": { "type": "string", "description": "User name" },
|
|
"limit": { "type": "integer", "description": "Max results", "default": 10 },
|
|
"company": { "type": "string", "description": "Company filter", "default": null }
|
|
},
|
|
"required": ["name"]
|
|
}
|
|
```
|
|
|
|
<Tip>
|
|
`Optional[str]` and `str | None` are identical at runtime and produce the same schema.
|
|
</Tip>
|
|
|
|
### Enum parameters with Literal
|
|
|
|
Use `Literal` to restrict a parameter to a fixed set of values. MCP clients like the Inspector render these as dropdown selects:
|
|
|
|
```python
|
|
from typing import Literal
|
|
|
|
@server.tool()
|
|
def create_event(
|
|
title: Annotated[str, Field(description="Event title")],
|
|
visibility: Annotated[
|
|
Literal["public", "private", "team"],
|
|
Field(description="Who can see this event"),
|
|
],
|
|
recurrence: Annotated[
|
|
Literal["none", "daily", "weekly", "monthly"],
|
|
Field(description="Recurrence pattern"),
|
|
] = "none",
|
|
) -> dict: ...
|
|
```
|
|
|
|
Produces `{"type": "string", "enum": ["public", "private", "team"]}` in the schema.
|
|
|
|
<Note>
|
|
mcp-use automatically simplifies Pydantic's nullable `anyOf` schemas. Without this,
|
|
`str | None` would produce `{"anyOf": [{"type": "string"}, {"type": "null"}]}` which
|
|
breaks description rendering in the MCP Inspector and fails validation in some clients
|
|
like Google's Gemini API. mcp-use collapses this into `{"type": "string", "default": null}`.
|
|
</Note>
|
|
|
|
## Complex Input Types
|
|
|
|
Use Pydantic models for complex inputs:
|
|
|
|
```python
|
|
from pydantic import BaseModel
|
|
|
|
class SearchQuery(BaseModel):
|
|
query: str = Field(description="The search query string")
|
|
max_results: int = Field(default=10, description="Maximum number of results to return")
|
|
include_metadata: bool = Field(default=False, description="Whether to include metadata")
|
|
|
|
@server.tool()
|
|
def search(params: SearchQuery) -> list[str]:
|
|
"""Search with complex parameters."""
|
|
return ["result1", "result2"]
|
|
```
|
|
|
|
## Return Types
|
|
|
|
Tools can return various types:
|
|
|
|
```python
|
|
# String
|
|
@server.tool()
|
|
def text_tool() -> str:
|
|
return "Hello"
|
|
|
|
# Dict (serialized to JSON)
|
|
@server.tool()
|
|
def json_tool() -> dict:
|
|
return {"key": "value", "count": 42}
|
|
|
|
# List
|
|
@server.tool()
|
|
def list_tool() -> list[str]:
|
|
return ["a", "b", "c"]
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
Raise exceptions to indicate errors. The error message will be returned to the client:
|
|
|
|
```python
|
|
@server.tool()
|
|
def divide(
|
|
a: Annotated[float, Field(description="Dividend")],
|
|
b: Annotated[float, Field(description="Divisor")],
|
|
) -> float:
|
|
"""Divide two numbers."""
|
|
if b == 0:
|
|
raise ValueError("Cannot divide by zero")
|
|
return a / b
|
|
```
|