[AgentTool] Attribute Reference
AgentToolAttribute marks a controller method (or an entire controller class) as an MCP-callable tool. It provides the Ithil source generator with the metadata needed to build the tool schema and governance rules at compile time.
Namespace
using Ithil.Attributes;Placement
[AgentTool] is applied to individual controller action methods. Each decorated method becomes one MCP tool.
Parameter reference
| Parameter | Type | Default | Description |
|---|---|---|---|
description (positional) | string | (required) | Human-readable description shown to the agent in the MCP tool manifest. The model reads this to decide whether to call the tool — be specific. |
AllowWrite | bool | false | When false, the gateway rejects tool calls that would mutate state (POST, PUT, PATCH, DELETE). Set to true for intentional write tools. |
MaxResponseTokens | int | 2000 | Token ceiling on the response body. The gateway truncates or rejects responses exceeding this limit before they reach the agent. |
RequiredScopes | string[] | null | OAuth scopes the calling agent’s JWT must contain. The gateway returns 403 if any required scope is absent. |
Category | string | null | Grouping label shown in the Ithil Dashboard’s tool library. Useful for organizing large tool sets. |
Examples
Read-only tool (default settings)
[AgentTool("Returns the current inventory count for a given SKU")]
[HttpGet("inventory/{sku}")]
public IActionResult GetInventory(string sku)
{
var count = _inventoryService.GetCount(sku);
return Ok(new { sku, count });
}Write tool with scope and token limit
[AgentTool("Creates a new support ticket and returns the ticket ID",
AllowWrite = true,
MaxResponseTokens = 500,
RequiredScopes = new[] { "support:write" },
Category = "Support")]
[HttpPost("tickets")]
public IActionResult CreateTicket([FromBody] TicketRequest req)
{
var ticket = _supportService.Create(req);
return Ok(new { ticketId = ticket.Id });
}How the source generator uses it
At compile time, the Ithil Roslyn source generator:
- Collects every method and class decorated with
[AgentTool] - Resolves the HTTP verb from
[HttpGet],[HttpPost], etc. - Resolves the full route template from
[Route]on the class and method - Builds the full tool schema for each method including the JSON Schema for its parameters
- Emits a
SchemaRegistrystatic class containing aToolscollection
The gateway reads SchemaRegistry.Tools via the GET /ithil/schema endpoint at startup. No reflection occurs at runtime.
Writing good descriptions
The description is the single most important field. It is what the AI model reads to decide whether and when to call your tool.
| Weaker | Stronger |
|---|---|
"Gets an order" | "Returns full order details including line items, status, and shipping address for a given order ID" |
"Updates inventory" | "Decrements the available inventory count for a SKU by a specified quantity. Fails if count would go negative." |
"Sends a message" | "Sends an email notification to a customer. Requires the customer's email address and a message body." |
Be specific about:
- What the tool returns
- What inputs it requires
- Any side effects (mutations, external calls, notifications)
- Any failure conditions the agent should know about
A vague description causes the model to call the wrong tool or hallucinate arguments. Treat the description as part of your public API contract.