Tools API Reference
Complete reference for MCP Gateway Tools API.
Overview
Tools are the core building blocks of MCP servers. They allow AI assistants to:
- Execute custom logic
- Access external APIs
- Manipulate data
- Perform calculations
- And much more!
Quick Reference
| Method | Description |
|---|---|
tools/list |
List all available tools |
tools/call |
Invoke a specific tool |
tools/list
List all tools available on the server.
Request
{
"jsonrpc": "2.0",
"method": "tools/list",
"params": {
"cursor": "optional-pagination-cursor"
},
"id": 1
}
Parameters:
cursor(string, optional) - Pagination cursor
Response
{
"jsonrpc": "2.0",
"result": {
"tools": [
{
"name": "add_numbers",
"description": "Adds two numbers",
"inputSchema": {
"type": "object",
"properties": {
"number1": {
"type": "number",
"description": "First number"
},
"number2": {
"type": "number",
"description": "Second number"
}
},
"required": ["number1", "number2"]
}
}
],
"nextCursor": "optional-next-cursor"
},
"id": 1
}
Response fields:
tools(array) - List of tool definitionsnextCursor(string, optional) - Pagination cursor
Tool Schema
Each tool has:
{
name: string; // Tool identifier (e.g., "add_numbers")
description?: string; // Human-readable description
inputSchema: { // JSON Schema for parameters
type: "object";
properties: { ... };
required?: string[];
};
}
tools/call
Invoke a specific tool with parameters.
Request
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "add_numbers",
"arguments": {
"number1": 5,
"number2": 3
}
},
"id": 2
}
Parameters:
name(string, required) - Tool namearguments(object, optional) - Tool-specific parameters
Response (Success)
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"type": "text",
"text": "{\"result\":8}"
}
]
},
"id": 2
}
Response fields:
content(array) - Tool output
Response (Error)
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params",
"data": {
"detail": "Parameter 'number1' is required"
}
},
"id": 2
}
Defining Tools
Basic Tool
using Mcp.Gateway.Tools;
public class MyTools
{
[McpTool("hello_world")]
public JsonRpcMessage HelloWorld(JsonRpcMessage request)
{
return ToolResponse.Success(
request.Id,
new { message = "Hello, World!" });
}
}
Tool with Parameters (Typed Return)
[McpTool("greet")]
public TypedJsonRpc<GreetResponse> Greet(TypedJsonRpc<GreetParams> request)
{
var args = request.GetParams()
?? throw new ToolInvalidParamsException("Name required");
return TypedJsonRpc<GreetResponse>.Success(
request.Id,
new GreetResponse($"Hello, {args.Name}!"));
}
public record GreetParams(string Name);
public record GreetResponse(string Greeting);
Tool with Metadata
[McpTool("add_numbers",
Title = "Add Numbers",
Description = "Adds two numbers and returns the sum",
Icon = "https://example.com/icon.png")]
// OutputSchema is automatically generated from AddResponse!
public TypedJsonRpc<AddResponse> Add(TypedJsonRpc<AddParams> request)
{
var args = request.GetParams()!;
var result = args.A + args.B;
return TypedJsonRpc<AddResponse>.Success(
request.Id,
new AddResponse(result));
}
public record AddParams(double A, double B);
public record AddResponse(double Result);
Tool Attributes
[McpTool]
Marks a method as an MCP tool.
[McpTool(
string name, // Required: Tool name
string? Title = null, // Optional: Display title
string? Description = null, // Optional: Description
string? Icon = null, // Optional: Icon URL
string? InputSchema = null, // Optional: Input JSON Schema (auto-generated if not provided)
string? OutputSchema = null)] // Optional: Output JSON Schema (auto-generated if not provided)
Attribute properties:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Tool identifier (a-z, 0-9, _, -, .) |
Title |
string | No | Human-readable title |
Description |
string | No | Tool description for AI |
Icon |
string | No | Icon URL (v1.6.5+) |
InputSchema |
string | No | Input JSON Schema (auto-generated from parameters if not provided) |
OutputSchema |
string | No | Output JSON Schema (auto-generated from return type if not provided) |
InputSchema auto-generation:
- If not provided, MCP Gateway automatically generates
inputSchemafrom the toolβs parameter type - Uses
TypedJsonRpc<T>parameter type to infer JSON Schema
OutputSchema auto-generation (v1.8.0+):
- If not provided, MCP Gateway automatically generates
outputSchemafrom the toolβs return type - Uses
TypedJsonRpc<T>return type to infer JSON Schema - Example:
TypedJsonRpc<AddResponse>generates schema withnumberproperty forResult
Tool Responses
Success Response (Typed)
return TypedJsonRpc<MyResponse>.Success(
request.Id,
new MyResponse(42));
Output:
{
"content": [
{
"type": "text",
"text": "{\"result\":42}"
}
],
"structuredContent": {
"result": 42
}
}
Success Response (Legacy)
return ToolResponse.Success(
request.Id,
new { result = 42 });
Output:
{
"content": [
{
"type": "text",
"text": "{\"result\":42}"
}
]
}
Error Response
throw new ToolInvalidParamsException("Invalid input");
Output:
{
"error": {
"code": -32602,
"message": "Invalid params",
"data": {
"detail": "Invalid input"
}
}
}
Parameter Validation
Required Parameters
var args = request.GetParams()
?? throw new ToolInvalidParamsException("Parameters required");
Type Validation
if (args.Count < 0)
{
throw new ToolInvalidParamsException("Count must be positive");
}
Range Validation
if (args.Age < 0 || args.Age > 150)
{
throw new ToolInvalidParamsException("Age must be between 0 and 150");
}
Async Tools
Tools can be async:
[McpTool("fetch_data")]
public async Task<JsonRpcMessage> FetchData(JsonRpcMessage request)
{
var data = await _httpClient.GetStringAsync("https://api.example.com/data");
return ToolResponse.Success(request.Id, new { data });
}
Dependency Injection
Tools support both constructor injection and method parameter injection:
Option 1: Constructor Injection
Requires class registration in DI container:
public class MyTools
{
private readonly ILogger<MyTools> _logger;
private readonly IMyService _service;
public MyTools(
ILogger<MyTools> logger,
IMyService service)
{
_logger = logger;
_service = service;
}
[McpTool("my_tool")]
public async Task<JsonRpcMessage> MyTool(JsonRpcMessage request)
{
_logger.LogInformation("Tool invoked");
var result = await _service.DoSomethingAsync();
return ToolResponse.Success(request.Id, result);
}
}
// Register in Program.cs
builder.Services.AddScoped<MyTools>();
builder.Services.AddSingleton<IMyService, MyService>();
Option 2: Method Parameter Injection
No class registration needed - parameters resolved from DI:
public class MyTools
{
[McpTool("my_tool")]
public async Task<JsonRpcMessage> MyTool(
JsonRpcMessage request,
ILogger<MyTools> logger, // β Automatically injected!
IMyService service) // β Automatically injected!
{
logger.LogInformation("Tool invoked");
var result = await service.DoSomethingAsync();
return ToolResponse.Success(request.Id, result);
}
}
// Only register services (class auto-discovered)
builder.Services.AddSingleton<IMyService, MyService>();
Parameter resolution order:
JsonRpcMessageorTypedJsonRpc<T>- The request (must be first parameter)- Additional parameters - Resolved from DI container (in order)
Benefits of method parameter injection:
- β No class registration needed
- β Simpler for tools with few dependencies
- β Clear what each tool needs
- β Easier testing (mock parameters directly)
Error Codes
| Code | Name | Description |
|---|---|---|
| -32700 | Parse error | Invalid JSON |
| -32600 | Invalid request | Not a valid JSON-RPC request |
| -32601 | Method not found | Tool does not exist |
| -32602 | Invalid params | Invalid or missing parameters |
| -32603 | Internal error | Server-side error |
Best Practices
1. Always Validate Parameters
var args = request.GetParams()
?? throw new ToolInvalidParamsException("Parameters required");
2. Use Descriptive Names
// β
GOOD
[McpTool("calculate_fibonacci")]
// β BAD
[McpTool("calc_fib")]
3. Provide Clear Descriptions
[McpTool("send_email",
Description = "Sends an email to the specified recipient with subject and body")]
4. Handle Exceptions
[McpTool("divide")]
public JsonRpcMessage Divide(TypedJsonRpc<DivideParams> request)
{
var args = request.GetParams()!;
if (args.Divisor == 0)
{
throw new ToolInvalidParamsException("Cannot divide by zero");
}
return ToolResponse.Success(request.Id,
new { result = args.Dividend / args.Divisor });
}
5. Use Structured Responses
// β
GOOD - Structured
return ToolResponse.Success(request.Id, new
{
result = 42,
timestamp = DateTime.UtcNow,
status = "success"
});
// β BAD - Plain string
return ToolResponse.Success(request.Id, "42");
See Also
- Getting Started - Build your first tool
- Calculator Example - Complete tool examples
- Lifecycle Hooks - Monitor tool invocations
- Authorization - Secure your tools