> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmcp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> How to configure GetMCP servers and tools for reliable, accurate AI interactions.

The most common source of AI tool problems is not a bug — it's a vague description, a poorly structured schema, or a misconfigured parameter mapping. This guide covers the patterns that consistently produce accurate, reliable AI tool use.

***

## 1. Write Descriptions That Actually Work

Your tool description is the single most important thing you configure. The AI reads it to decide:

* Whether to call this tool at all
* Which tool to call when multiple options exist
* What arguments to supply

**Bad description:**

```
Gets customer data
```

**Good description:**

```
Retrieve a single customer record by their unique customer ID. Returns name, email,
billing address, subscription plan, and account status. Use this when you need
to look up a specific customer's details. Do not use this to search by name or
email — use search_customers for that.
```

The good description tells the AI: what the tool returns, when to use it, and when NOT to use it. That last part — explicitly ruling out incorrect use cases — dramatically reduces wrong tool calls.

**Rules for good descriptions:**

* Start with a verb: `Retrieve`, `Create`, `Search`, `Send`, `Update`, `Delete`
* State what the tool returns (not just what it does)
* Include when to use it vs when to use a similar tool
* Keep it under 200 words — models truncate very long descriptions
* Avoid vague words like "handles", "manages", "processes"

***

## 2. Name Tools in snake\_case with a Verb

Tool names follow a `verb_noun` or `verb_noun_noun` pattern. The AI's reasoning will often include the tool name, so make it readable:

| Good                       | Bad               |
| -------------------------- | ----------------- |
| `get_customer`             | `customer`        |
| `create_invoice`           | `newInvoice`      |
| `search_products`          | `products_search` |
| `send_email`               | `email`           |
| `list_open_orders`         | `orders`          |
| `update_subscription_plan` | `editSub`         |

Use the same verb convention consistently across your server: if you use `get_` for retrieval, don't also use `fetch_` or `retrieve_` — pick one.

***

## 3. Design Schemas for the AI, Not the API

Your input schema describes what the AI should provide — not necessarily what the underlying API needs. Map the gap in parameter mappings, not in the schema.

**Don't expose internal IDs as required inputs** when names work better:

```json theme={null}
// Bad — AI has to somehow know the numeric category ID
{ "category_id": { "type": "integer" } }

// Good — AI can use the name, you map it server-side
{ "category": { "type": "string", "description": "Product category name (e.g., 'electronics', 'clothing')" } }
```

**Use enums when there are fixed choices:**

```json theme={null}
{
  "status": {
    "type": "string",
    "enum": ["pending", "active", "cancelled", "refunded"],
    "description": "Filter orders by this status"
  }
}
```

**Mark only truly required fields as required.** Optional parameters with defaults should be `optional` — the AI will omit them when not needed.

**Add `description` to every parameter.** The AI uses these to understand what values to pass:

```json theme={null}
{
  "limit": {
    "type": "integer",
    "description": "Number of results to return. Default is 20, maximum is 100.",
    "default": 20
  }
}
```

***

## 4. One Tool = One Action

Keep tools focused. A tool that does six different things depending on which parameters you pass produces inconsistent AI behavior.

| Don't do this                                           | Do this instead                                         |
| ------------------------------------------------------- | ------------------------------------------------------- |
| `manage_customer` (with `action: create/update/delete`) | `create_customer`, `update_customer`, `delete_customer` |
| `order_tool` (fetches or updates depending on params)   | `get_order`, `update_order_status`                      |

Focused tools have clearer descriptions and are called more accurately.

***

## 5. Use Caching for Read-Only Data

Enable **Cache TTL** on tools that return data that doesn't change frequently. This is one of the easiest performance wins:

| Tool type               | Suggested TTL    |
| ----------------------- | ---------------- |
| Product catalog         | 300–900 seconds  |
| Reference / lookup data | 600–3600 seconds |
| User-specific data      | 0 (no cache)     |
| Real-time status        | 0 (no cache)     |
| Documentation content   | 3600+ seconds    |

Cached responses are served from WordPress object cache and don't count against your upstream API rate limits.

***

## 6. Set Appropriate Timeouts and Retries

**Timeout** — default is 30 seconds. Adjust based on your API:

* Fast internal APIs: 5–10 seconds
* Slow report generation, file exports: 60–120 seconds
* Third-party APIs (Stripe, GitHub, etc.): 15–30 seconds

**Retry Count** — only enable retries for idempotent operations (GET requests, read-only tools). Never set retries > 0 on tools that create or delete data — a retry after a network timeout could create duplicates.

```
get_order          → retry: 3, timeout: 15s  ✓ safe to retry
create_order       → retry: 0, timeout: 30s  ✗ don't retry writes
search_products    → retry: 2, timeout: 10s  ✓ safe to retry
send_email         → retry: 0, timeout: 20s  ✗ don't retry sends
```

***

## 7. Organize Servers by Domain and Access Level

One server per logical group — not one server for everything:

```
stripe-payments       (finance team only — high-value credentials)
github-tools          (engineering team)
customer-support      (support team — read-only tools only)
internal-admin        (admin team — create/update/delete tools)
```

Benefits:

* Limit blast radius if a URL is shared accidentally
* Different inbound auth credentials per team
* Cleaner `tools/list` — the AI only sees the tools relevant to the current task
* Independent rate limits per domain

***

## 8. Keep Parameter Mappings Clean

Use the right mapping type for each parameter — don't send everything in the body:

| Parameter type              | Mapping                         |
| --------------------------- | ------------------------------- |
| Record ID in the URL        | Path (`/customers/{id}`)        |
| Filters, pagination         | Query (`?status=active&page=2`) |
| Data to create/update       | Body (POST/PUT only)            |
| API keys (if user-supplied) | Header                          |

Avoid query parameters on POST requests when the API uses a request body — some APIs ignore query params on POST.

***

## 9. Test Before You Ship

Use the built-in **Test** panel on every tool before sharing the server URL with anyone. What to verify:

* [ ] Tool returns the expected data shape
* [ ] Required parameters produce an error when missing
* [ ] Error responses from the API are handled gracefully
* [ ] Response size is reasonable (very large responses slow AI clients)

For a full protocol-level audit, connect [MCP Inspector](/docs/guides/mcp-inspector) and test every tool interactively.

***

## 10. Security Checklist

* [ ] Enable inbound authentication for production servers (not `none`)
* [ ] Use HTTPS on your WordPress site — required for credentials in transit
* [ ] Store API keys only in Custom Headers — never embed them in endpoint URLs where they appear in logs
* [ ] Set a rate limit appropriate for your upstream API's own limits
* [ ] Configure webhooks to alert on `tool.error` events so you catch auth failures fast
* [ ] Rotate test credentials independently from production keys
* [ ] Review call logs periodically for unexpected clients or unusual patterns
