For the complete documentation index, see llms.txt. This page is also available as Markdown.

Connecting tools

Stand up an MCP tool server, secure it, declare it in the manifest, and design tools the agent calls correctly.

Context — Assumes the Tools concept page. This guide covers the practical side: building a server, wiring it in, authentication, and — most importantly — designing tools a language model uses well.

YAML examples follow manifest schema 6.1.5. Manifest and content shapes are schema-versioned and differ across runtime versions — see Versioning & compatibility.

1. Build an MCP server

The agent consumes tools over the Model Context Protocol with the streamable-http transport. Any MCP-compliant server works; in Python, fastmcp is the shortest path:

pip install fastmcp
"""CRM tool server example."""

from fastmcp import FastMCP

mcp = FastMCP("crm")


@mcp.tool
def get_account_status(party_id: str) -> dict:
    """Fetch the current account status for a customer.

    Args:
        party_id: The customer's PARTYID exactly as provided by
            authentication — do not transform it.

    Returns:
        {"status": "ACTIVE" | "SUSPENDED" | "CLOSED",
         "since": "YYYY-MM-DD",
         "reason": str | None}
    """
    record = lookup_account(party_id)
    return {
        "status": record.status,
        "since": record.status_since.isoformat(),
        "reason": record.status_reason,
    }


if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8001)

Requirements on your side:

  • Transport: streamable-http only.

  • Reachability: the platform-hosted agent must be able to reach the hostname:port your manifest declares — a public URL, or an address your platform networking allows. The agent connects out to your server; it never needs to reach in.

  • Statelessness between calls is your design choice; the agent passes whatever parameters the tool declares, nothing more.

2. Declare it in the manifest

Field
Type
Required
Default
Meaning

id

string

yes

Namespace prefix for this server's tools.

hostname

string

yes

Host including scheme (http:// or https://). Host only — no path, port, or query.

port

integer 1–65535

yes

TCP port.

transport

streamable-http

no

streamable-http

The only supported MCP transport.

path

string

no

/mcp

URL path the MCP endpoint is mounted at. Set when the server exposes MCP somewhere other than /mcp (e.g. /v2/mcp).

api_key

${VAR} env-ref

no

Sent to the MCP server as Authorization: Bearer. Omit for unauthenticated servers.

  • id becomes the namespace: this server's get_account_status is referenced everywhere as crm:get_account_status.

  • api_key (optional) is a ${VAR} env-ref; the agent sends it on every MCP request as Authorization: Bearer. Your server should verify it.

  • The agent connects at boot and fails startup if the server is unreachable; at runtime, transient failures reconnect automatically.

3. Designing tools the agent calls well

The model sees three things: the tool's name, its description, and its parameter schema (names, types, defaults, per-parameter docs). It decides when and how to call based on those alone. Treat them as a prompt:

Name by intent, verb-first. search_cars, create_booking, initiate_human_handoff — not cars_api_v2 or do_action.

Document the contract, not the implementation. Say what goes in, what comes out, and the gotchas:

Return errors as data, not exceptions. A structured {"error": "driver_age below minimum of 21"} lands in the conversation history where the model can read it, explain it, and recover. An exception gives it nothing to work with.

Keep results lean and labelled. The entire result enters the model's context. Return the fields the agent needs, with self-explanatory names and enum-like values ("ACTIVE", not 2). Page or summarise large sets — "the cheapest 5 of 23 matches" is a better tool result than 23 rows.

Make state-changing tools idempotent where possible. The model may retry after ambiguous failures; accepting an idempotency parameter or deduplicating server-side prevents double bookings.

One capability per tool. A manage_booking(action=...) multiplexer forces the model to learn your switch statement. Separate cancel_booking, update_booking_dates, get_booking tools each carry their own focused documentation.

4. The other half: tool use in content

The server defines what can be called; routines and policies define when and how:

  • A routine tool node pairs tools: crm:get_account_status with a tool_instruction explaining parameter derivation in this flow's context.

  • A policy lists tools: it may invoke from its action.

  • If a tool changes what the engine should believe (authentication, status changes), register it in context.reevaluation_tools or the policy's reevaluate_after — see Reevaluation tools.

Tool descriptions answer "how do I call this correctly?"; instructions answer "why now, with which values from this conversation?". Don't duplicate one into the other.

5. Verify the wiring

  1. Boot the agent; startup fails fast with the server name if an MCP server is unreachable.

  2. Send a message that should trigger the tool; watch the event stream for the tool event carrying tool_id, arguments, and result (isinstance(ev, ToolEvent) in the SDK).

  3. Check the trace: each tool call appears with its arguments and result — see Observability.

  4. Test the failure path: stop your MCP server mid-conversation and confirm the agent degrades the way you want (the failed call is visible to the model, which explains per its instructions).

Checklist

Last updated

Was this helpful?