Portal Community

How the LLM Uses Your Schema

When Octopus registers a tool with the LLM, it passes:

The LLM reads the description field on every property to decide what value to provide. Missing or vague descriptions cause the LLM to guess — resulting in incorrect or hallucinated argument values at runtime.

Schema Anatomy

{
  "type": "object",
  "properties": {
    // Each key is an argument the LLM can supply
    "email": {
      "type":        "string",
      "format":      "email",
      "description": "The contact's primary email address (e.g. jane@example.com)"
    },
    "include_notes": {
      "type":        "boolean",
      "description": "Set to true to include internal CRM notes in the response",
      "default":     false
    },
    "max_results": {
      "type":        "integer",
      "description": "Maximum number of records to return (1-100)",
      "minimum":     1,
      "maximum":     100,
      "default":     10
    }
  },
  "required": ["email"],
  "additionalProperties": false
}

Property Types and Formats

JSON Schema TypeUse ForUseful Constraints
stringText, IDs, names, free-form inputminLength, maxLength, pattern, format
string + enumFixed-value choicesList every valid value in the enum array
integerWhole numbers, counts, IDsminimum, maximum
numberDecimal amounts, percentagesminimum, maximum, multipleOf
booleanFlags, include/exclude togglesAlways add a default
arrayLists of values (emails, tags)items schema, minItems, maxItems
objectNested structuresDefine properties + required recursively

Useful String Formats

Format ValueMeaningExample
emailRFC 5321 email address"jane@example.com"
dateISO 8601 date (YYYY-MM-DD)"2024-06-15"
date-timeISO 8601 datetime"2024-06-15T14:30:00Z"
uriAbsolute URI"https://example.com/page"
uuidUUID v4"550e8400-e29b-41d4-a716-..."

Writing Effective Tool Descriptions

The tool-level description tells the LLM when to call the tool. The property-level description tells the LLM what value to supply. Both must be written for the LLM, not for human documentation.

// GOOD — tool description tells the LLM when and what it returns
{
  "name": "crm_get_contact",
  "description": "Look up a CRM contact by their email address. " +
                 "Call this when the user asks about a specific person, customer, or lead. " +
                 "Returns the contact's name, account, phone number, and open opportunities."
}

// BAD — too vague; LLM may not know when to use it
{
  "name": "crm_get_contact",
  "description": "Gets a contact."
}
// GOOD — property description tells the LLM exactly what to supply
"start_date": {
  "type":        "string",
  "format":      "date",
  "description": "Start of the date range in YYYY-MM-DD format. " +
                 "Use the date the user mentioned, or today's date if not specified."
}

// BAD — LLM may not format the date correctly
"start_date": {
  "type":        "string",
  "description": "Start date"
}

Arrays and Nested Objects

// Array of email addresses
"recipients": {
  "type":        "array",
  "description": "List of recipient email addresses (at least one required)",
  "items": {
    "type":   "string",
    "format": "email"
  },
  "minItems": 1,
  "maxItems": 10
}

// Nested object — date range
"date_range": {
  "type":        "object",
  "description": "Inclusive date range for the query",
  "properties": {
    "from": { "type": "string", "format": "date",
              "description": "Start date (YYYY-MM-DD)" },
    "to":   { "type": "string", "format": "date",
              "description": "End date (YYYY-MM-DD, inclusive)" }
  },
  "required": ["from", "to"]
}

Optional vs Required Parameters

Put genuinely optional parameters outside the required array and give them a meaningful default. The LLM will omit them when not needed, which makes tool calls shorter and cheaper.

{
  "type": "object",
  "properties": {
    "query":        { "type": "string",
                      "description": "Search query (required)" },
    "status":       { "type": "string",
                      "enum": ["open","closed","all"],
                      "description": "Filter by status. Default is 'open'.",
                      "default": "open" },
    "max_results":  { "type": "integer",
                      "description": "Maximum tickets to return (1–50). Default is 10.",
                      "default": 10,
                      "minimum": 1,
                      "maximum": 50 }
  },
  "required": ["query"]   // only query is mandatory
}

Common Schema Mistakes

MistakeEffectFix
No description on required fieldsLLM guesses the value; wrong calls at runtimeAdd clear, LLM-readable descriptions to every property
Required fields missing from required arrayLLM may omit them; handler throws null refList every mandatory param in required
Using any type or no typeLLM sends arbitrary JSON; handler failsAlways specify "type"
Enum values not matching handler expectationsHandler receives unexpected string; runtime errorSync enum values with your handler's switch/match cases
Date fields typed as string without formatLLM sends "next Tuesday" instead of a dateAdd "format": "date" or "date-time"
No additionalProperties: falseExtra LLM-generated fields silently ignored or storedAdd "additionalProperties": false to top-level schema
Test your schemas. After deploying your MCP server, run a smoke test by calling GET /tools and validating each inputSchema with a JSON Schema validator (e.g. Newtonsoft.Json.Schema or the jsonschema Python library). Malformed schemas are surfaced to the LLM as-is and can cause silent failures.