Skip to main content
POST
/
mcp
/
tools
/
call
POST /mcp/tools/call
curl --request POST \
  --url https://api.example.com/mcp/tools/call
{
  "jsonrpc": "<string>",
  "result": {
    "content": [
      {
        "type": "<string>",
        "text": "<string>"
      }
    ]
  },
  "id": {},
  "error": {
    "code": 123,
    "message": "<string>"
  }
}

Endpoint Details

Method: POST
Path: /mcp/tools/call
Authentication: None required (public endpoint)
Content-Type: application/json

Purpose

Executes a tool registered in HandsAI by invoking its underlying REST API with the provided arguments. The tool name must match one of the tools returned by /mcp/tools/list. HandsAI:
  1. Validates the request structure
  2. Resolves the tool definition from the database/cache
  3. Makes the HTTP request to the configured REST API endpoint
  4. Returns the response wrapped in JSON-RPC format

Request Schema

The request body must follow JSON-RPC 2.0 format:
jsonrpc
string
required
Must be "2.0" (JSON-RPC protocol version)
method
string
required
Must be "tools/call" for tool execution requests
params
object
required
Contains the tool execution parameters
id
string | number
Optional request identifier. If provided, it will be echoed in the response to correlate requests and responses.

Response Schema

Success Response

jsonrpc
string
required
Always "2.0"
result
object
required
Contains the tool execution result
id
string | number
Echoed from the request if provided

Error Response

jsonrpc
string
required
Always "2.0"
error
object
required
Error details (replaces result on failure)
id
string | number
Echoed from the request if provided

Examples

Example 1: Weather Tool

Request:
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "weather_get",
    "arguments": {
      "location": "San Francisco",
      "units": "celsius"
    }
  },
  "id": "weather-123"
}
Success Response:
{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"temperature\": 18, \"condition\": \"Partly cloudy\", \"humidity\": 65}"
      }
    ]
  },
  "id": "weather-123"
}

Example 2: Document Search with Array Parameter

Request:
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "search_documents",
    "arguments": {
      "query": "quarterly revenue",
      "tags": ["finance", "2024"],
      "limit": 10
    }
  },
  "id": "search-456"
}
Success Response:
{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[{\"id\": \"doc-1\", \"title\": \"Q4 2024 Revenue Report\"}, {\"id\": \"doc-2\", \"title\": \"Q3 2024 Financial Summary\"}]"
      }
    ]
  },
  "id": "search-456"
}

Example 3: Invalid Parameters Error

Request (missing required parameter):
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "weather_get",
    "arguments": {
      "units": "celsius"
    }
  },
  "id": "error-789"
}
Error Response:
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params: location is required"
  },
  "id": "error-789"
}

Example 4: Missing Request Body

Request:
null
Error Response:
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params: missing required parameters"
  }
}

Example 5: Tool Execution Failure

Request:
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "database_query",
    "arguments": {
      "sql": "SELECT * FROM users"
    }
  },
  "id": "fail-101"
}
Error Response (if underlying API fails):
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal error: Connection timeout"
  },
  "id": "fail-101"
}

cURL Examples

Basic Tool Call

curl -X POST http://localhost:8080/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "weather_get",
      "arguments": {
        "location": "New York",
        "units": "fahrenheit"
      }
    },
    "id": "1"
  }'

Tool Call with Array Arguments

curl -X POST http://localhost:8080/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "send_notification",
      "arguments": {
        "recipients": ["[email protected]", "[email protected]"],
        "message": "Deployment completed successfully",
        "priority": "high"
      }
    },
    "id": "2"
  }'

Implementation Details

Request Validation

The controller performs the following validations:
  1. Request body must not be null
  2. params field must not be null
  3. Tool name must match a registered tool
  4. Arguments must satisfy the tool’s inputSchema requirements
Validation failures return error code -32602 (Invalid params).

Execution Flow

  1. Request mapping: McpToolCallRequest is converted to ToolExecuteRequest
  2. Tool resolution: ToolExecutionService looks up the tool configuration
  3. API invocation: HandsAI makes an HTTP request to the configured endpoint
  4. Response conversion: ToolExecuteResponse is wrapped in McpToolCallResponse
  5. Content formatting: Results are serialized to text content

Error Handling

The controller maps exceptions to JSON-RPC error codes:
Exception TypeError CodeExample Message
IllegalArgumentException-32602”Invalid params: tool not found”
Any other exception-32603”Internal error: NullPointerException”

Source Code Reference

Implemented in:
org.dynamcorp.handsaiv2.controller.MCPController.executeApiTool()
// Location: src/main/java/org/dynamcorp/handsaiv2/controller/MCPController.java:57

Best Practices

  1. Always validate tool names: First call /mcp/tools/list to get available tools
  2. Provide request IDs: Include an id field to correlate async requests
  3. Handle errors gracefully: Check for the error field before accessing result
  4. Type safety: Ensure argument types match the tool’s inputSchema
  5. Required parameters: Always provide all parameters listed in inputSchema.required

Build docs developers (and LLMs) love