HandsAI’s parameter system allows AI agents to provide structured inputs to API tools. The type system ensures proper validation and serialization for external API calls.
Available Parameter Types
HandsAI supports five parameter types defined in ParameterType.java:
public enum ParameterType {
STRING ,
NUMBER ,
BOOLEAN ,
OBJECT ,
ARRAY
}
Source: ParameterType.java:3-9
Parameter Schema
Every parameter includes these fields:
Field Type Description nameString Parameter identifier (matches API field) typeEnum STRING, NUMBER, BOOLEAN, ARRAY, or OBJECT descriptionString Human-readable explanation for AI agents requiredBoolean Whether parameter is mandatory defaultValueString Fallback value if not provided
Source: ToolParameter.java:18-26
STRING Parameters
The most common type for text input.
Basic Example
{
"name" : "title" ,
"type" : "STRING" ,
"description" : "Issue title" ,
"required" : true ,
"defaultValue" : ""
}
Real-World Use Case: Email Sending
From the Resend API integration:
{
"parameters" : [
{
"name" : "from" ,
"type" : "STRING" ,
"description" : "Sender email address (e.g., Acme <[email protected] >). Must be a verified domain." ,
"required" : true ,
"defaultValue" : ""
},
{
"name" : "to" ,
"type" : "STRING" ,
"description" : "Recipient email address." ,
"required" : true ,
"defaultValue" : ""
},
{
"name" : "subject" ,
"type" : "STRING" ,
"description" : "Email subject line." ,
"required" : true ,
"defaultValue" : ""
},
{
"name" : "html" ,
"type" : "STRING" ,
"description" : "Email body in HTML format." ,
"required" : true ,
"defaultValue" : ""
}
]
}
Source: NUEVOS_HITOS.json:24-51
Usage in MCP Call
{
"method" : "tools/call" ,
"params" : {
"name" : "resend-send-email" ,
"arguments" : {
"from" : "[email protected] " ,
"to" : "[email protected] " ,
"subject" : "Welcome to MyApp" ,
"html" : "<h1>Hello!</h1><p>Thanks for signing up.</p>"
}
}
}
NUMBER Parameters
For integer and decimal values.
Basic Example
{
"name" : "limit" ,
"type" : "NUMBER" ,
"description" : "Number of results to return (e.g., 10)" ,
"required" : false ,
"defaultValue" : "10"
}
Real-World Use Case: Bluesky Timeline
{
"name" : "limit" ,
"type" : "NUMBER" ,
"description" : "Number of posts to retrieve (e.g., 10)" ,
"required" : false ,
"defaultValue" : "10"
}
Source: NUEVOS_HITOS.json:224-229
Usage in MCP Call
{
"name" : "bluesky-timeline" ,
"arguments" : {
"limit" : 25
}
}
Note: AI agents can send numbers as integers (25) or strings ("25"). HandsAI handles both.
BOOLEAN Parameters
For true/false flags.
Basic Example
{
"name" : "include_images" ,
"type" : "BOOLEAN" ,
"description" : "Whether to include images in results (true/false)." ,
"required" : false ,
"defaultValue" : ""
}
Real-World Use Case: Tavily Search
{
"name" : "include_images" ,
"type" : "BOOLEAN" ,
"description" : "Whether to include images in search results (true/false)." ,
"required" : false ,
"defaultValue" : ""
}
Source: NUEVOS_HITOS.json:99-104
Usage in MCP Call
{
"name" : "tavily-search" ,
"arguments" : {
"query" : "HandsAI documentation" ,
"include_images" : true
}
}
Accepted Values: true, false, "true", "false", 1, 0
ARRAY Parameters
For lists of values, especially useful for multi-select options.
Basic Example
{
"name" : "platforms" ,
"type" : "ARRAY" ,
"description" : "Target social media platforms: linkedin, twitter, facebook, instagram" ,
"required" : true ,
"defaultValue" : "[ \" linkedin \" ]"
}
Real-World Use Case: Social Media Posting
From the Ayrshare integration (multi-platform posting):
{
"name" : "Publicar en Redes Sociales (Ayrshare)" ,
"code" : "ayrshare-post" ,
"description" : "Publica contenido en múltiples plataformas de redes sociales simultáneamente." ,
"parameters" : [
{
"name" : "post" ,
"type" : "STRING" ,
"description" : "El contenido a publicar." ,
"required" : true
},
{
"name" : "platforms" ,
"type" : "ARRAY" ,
"description" : "Lista de plataformas donde publicar (ej: linkedin, twitter, facebook, instagram)." ,
"required" : true ,
"defaultValue" : "[ \" linkedin \" ]"
},
{
"name" : "mediaUrls" ,
"type" : "ARRAY" ,
"description" : "URLs de imágenes o videos a adjuntar (array de strings)." ,
"required" : false ,
"defaultValue" : ""
}
]
}
Usage in MCP Call
AI agents can send arrays as native JSON: {
"name" : "ayrshare-post" ,
"arguments" : {
"post" : "Check out our new feature!" ,
"platforms" : [ "linkedin" , "twitter" ],
"mediaUrls" : [
"https://example.com/image1.jpg" ,
"https://example.com/image2.jpg"
]
}
}
Some LLMs send arrays as JSON strings: {
"name" : "ayrshare-post" ,
"arguments" : {
"post" : "Check out our new feature!" ,
"platforms" : "[ \" linkedin \" , \" twitter \" ]" ,
"mediaUrls" : "[ \" https://example.com/image1.jpg \" ]"
}
}
HandsAI automatically deserializes these strings to arrays. Source: ToolExecutionService.java:372-412
Array Deserialization Logic
HandsAI handles ARRAY parameters intelligently:
if (value instanceof String) {
String strVal = ((String) value). trim ();
if ( strVal . startsWith ( "[" )) {
List < Object > parsed = objectMapper . readValue (strVal, new TypeReference < List < Object >>() {});
bodyParams . put ( param . getName (), parsed);
}
}
Behavior:
If value is already a List → Use as-is
If value is a String starting with [ → Deserialize to List
Otherwise → Leave unchanged
Source: ToolExecutionService.java:385-411
Why This Matters Different LLMs serialize arrays differently:
Claude might send: ["a", "b"] (native array)
GPT might send: "[\"a\", \"b\"]" (JSON string)
HandsAI handles both automatically, so tools work with any MCP client.
OBJECT Parameters
For complex nested JSON structures (experimental).
Basic Example
{
"name" : "metadata" ,
"type" : "OBJECT" ,
"description" : "Additional metadata as JSON object" ,
"required" : false ,
"defaultValue" : "{}"
}
Usage in MCP Call
{
"name" : "custom-api-tool" ,
"arguments" : {
"metadata" : {
"user_id" : "12345" ,
"source" : "mobile_app" ,
"version" : "2.1.0"
}
}
}
Limited Support OBJECT parameters are currently experimental. For complex nested data, consider using STRING parameters with JSON serialization instead.
Required vs Optional Parameters
Required Parameters
{
"name" : "query" ,
"type" : "STRING" ,
"description" : "Search query to process." ,
"required" : true ,
"defaultValue" : ""
}
AI agents must provide this value. MCP calls without it will fail.
Optional Parameters with Defaults
{
"name" : "state" ,
"type" : "STRING" ,
"description" : "Filter by PR state (open, closed, all)." ,
"required" : false ,
"defaultValue" : "open"
}
If omitted, HandsAI uses "open" as the value.
Source: NUEVOS_HITOS.json:185-191
Optional Parameters Without Defaults
{
"name" : "body" ,
"type" : "STRING" ,
"description" : "Issue description (supports Markdown)." ,
"required" : false ,
"defaultValue" : ""
}
If omitted, the parameter is not sent to the API.
Source: NUEVOS_HITOS.json:154-159
Parameter Validation
Required Field Validation
HandsAI validates required parameters before making API calls. Missing required fields result in: {
"error" : {
"code" : -32602 ,
"message" : "Invalid params: missing required parameter 'query'"
}
}
HandsAI attempts to coerce types:
"25" (string) → 25 (number) for NUMBER parameters
"true" (string) → true (boolean) for BOOLEAN parameters
"[1,2,3]" (string) → [1,2,3] (array) for ARRAY parameters
Default Value Application
Default values are applied before API execution if:
Parameter is optional (required: false)
No value provided by AI agent
defaultValue is non-empty
Best Practices
Parameter names should match the target API’s field names exactly: // GitHub API expects "owner" and "repo"
{ "name" : "owner" , "type" : "STRING" },
{ "name" : "repo" , "type" : "STRING" }
Don’t rename to repository_owner unless the API uses that name.
Provide Clear Descriptions
Descriptions are shown to AI agents. Include:
Expected format (e.g., “ISO 8601 date”)
Valid values (e.g., “open, closed, or all”)
Examples (e.g., “e.g., facebook/react”)
{
"description" : "Repository owner (user or organization, e.g., 'facebook')."
}
Use ARRAY for Multi-Select Options
When an API accepts multiple values, use ARRAY instead of comma-separated strings: ✅ Good: {
"name" : "platforms" ,
"type" : "ARRAY" ,
"defaultValue" : "[ \" linkedin \" ]"
}
❌ Avoid: {
"name" : "platforms" ,
"type" : "STRING" ,
"defaultValue" : "linkedin,twitter"
}
For optional parameters, provide defaults that work for 80% of use cases: {
"name" : "limit" ,
"type" : "NUMBER" ,
"required" : false ,
"defaultValue" : "10" // Most users want ~10 results
}
Real-World Examples
Example 1: GitHub Issue Creation
Combines STRING parameters (required and optional) with path parameters:
{
"name" : "Create GitHub Issue" ,
"code" : "github-create-issue" ,
"endpointPath" : "/repos/{owner}/{repo}/issues" ,
"httpMethod" : "POST" ,
"parameters" : [
{
"name" : "owner" ,
"type" : "STRING" ,
"description" : "Repository owner (user or organization, e.g., 'facebook')." ,
"required" : true
},
{
"name" : "repo" ,
"type" : "STRING" ,
"description" : "Repository name (e.g., 'react')." ,
"required" : true
},
{
"name" : "title" ,
"type" : "STRING" ,
"description" : "Issue title." ,
"required" : true
},
{
"name" : "body" ,
"type" : "STRING" ,
"description" : "Issue description (supports Markdown)." ,
"required" : false
}
]
}
Source: NUEVOS_HITOS.json:124-160
Example 2: Tavily AI Search
Mixes STRING, BOOLEAN parameters with defaults:
{
"name" : "Tavily Search" ,
"code" : "tavily-search" ,
"endpointPath" : "/search" ,
"httpMethod" : "POST" ,
"parameters" : [
{
"name" : "api_key" ,
"type" : "STRING" ,
"description" : "Tavily API key (required in request body)." ,
"required" : true
},
{
"name" : "query" ,
"type" : "STRING" ,
"description" : "The search query to process." ,
"required" : true
},
{
"name" : "search_depth" ,
"type" : "STRING" ,
"description" : "Search depth ('basic' or 'advanced')." ,
"required" : false ,
"defaultValue" : "basic"
},
{
"name" : "include_images" ,
"type" : "BOOLEAN" ,
"description" : "Whether to include images in results (true/false)." ,
"required" : false
}
]
}
Source: NUEVOS_HITOS.json:68-105
Example 3: Google Jules Session Creation
Complex example with STRING parameters and optional fields:
{
"name" : "Create Jules Session" ,
"code" : "jules-create-session" ,
"endpointPath" : "/v1alpha/sessions" ,
"httpMethod" : "POST" ,
"parameters" : [
{
"name" : "prompt" ,
"type" : "STRING" ,
"description" : "The prompt for the Jules agent." ,
"required" : true
},
{
"name" : "source" ,
"type" : "STRING" ,
"description" : "The source name (format: 'sources/github/owner/repo', use jules-list-sources to get the list)." ,
"required" : true
},
{
"name" : "automationMode" ,
"type" : "STRING" ,
"description" : "Optional integration mode, e.g., 'AUTO_CREATE_PR'" ,
"required" : false
},
{
"name" : "startingBranch" ,
"type" : "STRING" ,
"description" : "The branch to start the Jules session from." ,
"required" : false ,
"defaultValue" : "main"
}
]
}
Source: NUEVOS_HITOS.json:258-295
Testing Parameters
Manual Testing
curl -X POST http://localhost:8080/api/mcp/tools/call \
-H "Content-Type: application/json" \
-d '{
"method": "tools/call",
"params": {
"name": "ayrshare-post",
"arguments": {
"post": "Test post from HandsAI",
"platforms": ["linkedin"],
"mediaUrls": []
}
}
}'
# Get tool details
curl http://localhost:8080/admin/tools/api | jq '.[] | select(.code=="ayrshare-post")'
# Check parameter definitions
curl http://localhost:8080/admin/tools/api/{id} | jq '.parameters'
Common Issues
ARRAY parameter not deserializing? Ensure the JSON string is properly escaped:
✅ "[\"a\", \"b\"]" (double-escaped for JSON)
❌ "['a', 'b']" (single quotes don’t parse)
Source: ToolExecutionService.java:397-408
Default values not applying? Check:
Parameter is marked required: false
defaultValue is a non-empty string
For ARRAY defaults, use escaped JSON: "[\"value\"]"
Next Steps
Register Tools Create tools with properly typed parameters
Import/Export Share tool configurations with parameter definitions
Managing Providers Configure authentication for API providers
API Reference Complete endpoint documentation