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

# MCP

> How Jelou Functions automatically generates MCP tools so your AI agents can invoke functions as tools.

## Auto-generation of MCP tools

When you create a function with `define()`, it is automatically exposed as an [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) tool. Your AI agents can discover and invoke your function as a tool without additional configuration.

## Example

For this function:

```typescript index.ts theme={null}
import { define, z } from "@jelou/functions";

export default define({
  name: "query-balance",
  description: "Queries a customer's balance by phone number",
  input: z.object({
    phone: z.string().min(10).describe("Phone number with country code"),
  }),
  output: z.object({
    name: z.string(),
    balance: z.number(),
    currency: z.string(),
  }),
  handler: async (input, ctx) => {
    ctx.log("Querying balance", { phone: input.phone });
    return { name: "Maria Garcia", balance: 150.00, currency: "USD" };
  },
});
```

The `/mcp` endpoint exposes this schema:

```json theme={null}
{
  "name": "query-balance",
  "description": "Queries a customer's balance by phone number",
  "inputSchema": {
    "type": "object",
    "properties": {
      "phone": {
        "type": "string",
        "minLength": 10,
        "description": "Phone number with country code"
      }
    },
    "required": ["phone"]
  }
}
```

## The `description` field: the most important thing for MCP

<Warning>
  The `description` field of your `define()` is what the AI agent reads to decide **when** to invoke your tool. If the description is vague, the agent will not know when to use it — or worse, will use it at the wrong time.
</Warning>

| ❌ Vague           | ✅ Specific                                                                      | Why it matters                                      |
| ----------------- | ------------------------------------------------------------------------------- | --------------------------------------------------- |
| `"Handles users"` | `"Looks up a user by email or phone and returns their profile with balance"`    | The agent knows exactly what data it can get        |
| `"Sends message"` | `"Sends a WhatsApp message to a number with country code (e.g.: 593…)"`         | The agent knows the channel and expected format     |
| `"Queries API"`   | `"Queries the status of a shipment by tracking number in the Servientrega API"` | The agent knows the provider and what data it needs |

### `.describe()` annotations on fields

Zod `.describe()` annotations become parameter descriptions in the MCP tool. This is what AI agents see when they discover your function:

```typescript theme={null}
input: z.object({
  phone: z.string().min(10).describe("Number with country code, e.g.: 593987654321"),
  type: z.enum(["prepaid", "postpaid"]).describe("Customer's plan type"),
  includeHistory: z.boolean().default(false).describe("Whether to include the last 5 transactions"),
})
```

<Tip>
  Write clear and specific descriptions in `.describe()`. AI agents use these descriptions to decide what values to pass to your function.
</Tip>

## Testing the MCP endpoint

Start the local server with `jelou functions dev` and query the MCP schema:

<CodeGroup>
  ```bash curl theme={null}
  curl http://localhost:3000/mcp
  ```

  ```json Response theme={null}
  {
    "tools": [
      {
        "name": "query-balance",
        "description": "Queries a customer's balance by phone number",
        "inputSchema": {
          "type": "object",
          "properties": {
            "phone": {
              "type": "string",
              "minLength": 10,
              "description": "Phone number with country code"
            }
          },
          "required": ["phone"]
        }
      }
    ]
  }
  ```
</CodeGroup>

Invoke the function directly:

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST http://localhost:3000 \
    -H "Content-Type: application/json" \
    -d '{"phone": "593987654321"}'
  ```

  ```json Response 200 theme={null}
  {
    "name": "Maria Garcia",
    "balance": 150.00,
    "currency": "USD"
  }
  ```
</CodeGroup>

In production:

```bash theme={null}
curl https://query-balance.fn.jelou.ai/mcp
```

## Disabling MCP

If your function should not be discoverable as a tool (for example, a webhook that only receives callbacks), disable MCP:

```typescript theme={null}
config: { mcp: false }
```

When MCP is disabled, the `/mcp` endpoint returns 404.

## How agents use it

When you configure an AI agent in Jelou Brain Studio and assign functions as tools, the agent:

1. Discovers available tools via the `/mcp` endpoint
2. Reads the name, description, and input schema
3. Decides when to invoke the tool based on the user's conversation
4. Sends validated parameters to your function
5. Receives the response and incorporates it into the conversation

All of this happens automatically — you only need to write the function with `define()` and assign it to the agent.

## Multi-tool MCP

When you use `app()`, a single MCP server at `/mcp` automatically registers all tools. Each tool appears as an independent tool with its name, description, and schema.

To exclude a specific tool from the MCP registry, use `mcp: false` in its config:

```typescript theme={null}
import { app, define, z } from "@jelou/functions";

export default app({
  tools: {
    queryBalance: define({
      description: "Queries a customer's balance",
      input: z.object({ phone: z.string().min(10) }),
      handler: async (input) => ({ balance: 150.00 }),
    }),
    paymentWebhook: define({
      description: "Receives payment callbacks",
      input: z.object({ transactionId: z.string() }),
      config: { mcp: false },
      handler: async (input) => ({ received: true }),
    }),
  },
});
```

In this example, AI agents discover `queryBalance` via MCP but `paymentWebhook` is only accessible via direct HTTP at `/payment-webhook`.

<Tip>
  See the [full multi-tool guide](/guides/functions/multi-tool) for more details about auto-generated routes and config combination.
</Tip>
