Skip to main content
Official Schema: See the JSON Schema definition for the authoritative tool configuration specification.
Tools are individual SQL operations that AI agents can discover and execute. Each tool encapsulates a SQL statement, parameter definitions, validation rules, and execution metadata.

Tool Structure

Every tool definition follows this structure:
tools:
  tool_name:
    source: ibmi-system
    description: "What this tool does and when to use it"
    statement: |
      SELECT * FROM qsys2.system_status_info
    parameters: []
    security: {}
    metadata: {}

Required Fields

All SQL tools must include these fields:
FieldTypeDescription
tool_namestring (YAML key)Unique identifier for the tool, used by AI agents to call it
sourcestringName of the database connection source (from sources section)
descriptionstringClear explanation of what the tool does, for AI agent consumption
statementstringSQL query to execute when the tool is called

Field Details

Unique identifier for the toolThe tool name is the YAML key and must be unique across all tools.Naming conventions:
  • Use lowercase with underscores: get_active_jobs
  • Be descriptive: find_employees_by_department not emp_search
  • Prefix by domain if needed: perf_system_status, sec_audit_trail
# ✅ Good names
tools:
  get_employee_details:
  find_employees_by_department:
  calculate_employee_bonus:

# ❌ Avoid
tools:
  emp:
  query1:
  temp_tool:

Parameters

Parameters define dynamic inputs for SQL tools. Each parameter specifies type, validation rules, and usage information.

Complete Parameter Guide

See the full Parameter Guide for detailed examples of all parameter types, validation patterns, and best practices for building SQL tools with parameters.

Parameter Structure

parameters:
  - name: employee_id
    type: string
    description: "Employee ID (6 digits)"
    required: true
    pattern: "^[0-9]{6}$"

Parameter Types

Text values with validation
parameters:
  - name: library_name
    type: string
    description: "IBM i library name (uppercase alphanumeric)"
    required: true
    pattern: "^[A-Z][A-Z0-9_]*$"
    minLength: 1
    maxLength: 10
    default: "QSYS2"
Validation options:
  • pattern - Regular expression for validation
  • minLength - Minimum string length
  • maxLength - Maximum string length
  • enum - Fixed list of allowed values
  • default - Default value if not provided
Example with enum:
parameters:
  - name: object_type
    type: string
    enum: ["*PGM", "*FILE", "*SRVPGM", "*DTAARA"]
    default: "*FILE"
    description: "IBM i object type filter"

Optional Parameters

Parameters without required: true or with default values are optional:
parameters:
  - name: user_filter
    type: string
    required: false
    description: "Optional user name filter"
SQL handling for optional parameters:
WHERE (:user_filter IS NULL OR user_name = :user_filter)

Security Configuration

Add security controls to tools for enhanced protection:
tools:
  execute_dynamic_sql:
    source: ibmi-system
    description: "Execute dynamic SQL with safety controls"
    statement: |
      SELECT * FROM user_profiles WHERE user_name = :user_name
    security:
      readOnly: true
      maxQueryLength: 15000
      forbiddenKeywords: ["DROP", "DELETE", "UPDATE", "TRUNCATE"]

Security Fields

FieldTypeDefaultDescription
readOnlybooleantrueRestrict to read-only operations (SELECT queries)
maxQueryLengthnumber10000Maximum SQL query length in characters
forbiddenKeywordsarray[]Additional forbidden SQL keywords beyond defaults
Mark tools as read-only (SELECT queries only):
security:
  readOnly: true  # Enforce SELECT-only operations
Best Practice: Mark all tools that don’t modify data as readOnly: true. This provides clear documentation and can be used for access control.
Default: true (for safety - tools are read-only by default)

Response Formatting

Control how tool results are formatted for AI agents:

responseFormat

Type: string Options: json (default), markdown
tools:
  markdown_report:
    source: ibmi-system
    description: "Generate formatted system report"
    responseFormat: markdown
    statement: |
      SELECT
        '# System Status Report' AS header,
        '## CPU: ' || cpu_utilization || '%' AS cpu,
        '## Memory: ' || ROUND((used_memory * 100.0 / total_memory), 2) || '%' AS memory
      FROM TABLE(QSYS2.SYSTEM_STATUS()) X
Response types:
  • json - Structured data (default, best for AI processing)
  • markdown - Formatted text with markdown syntax

Fetch-Row Controls

Control how many rows are fetched from the database per tool call. These are distinct from maxDisplayRows, which only truncates the rendered markdown table.
Database vs. display limits: rowsToFetch / fetchAllRows change how many rows the server pulls from Db2 for i. maxDisplayRows only affects how many rows appear in the formatted output. A tool can fetch 500 rows from the database but render only the first 100 in markdown.

Fields

The two fields compose: fetchAllRows is the pagination policy; rowsToFetch, when set, is the per-fetch size in pagination mode, or a single-shot row cap when fetchAllRows is off.
FieldTypeDefaultDescription
rowsToFetchinteger (≥ 1)100 (mapepire default)With fetchAllRows: true, the number of rows per fetchMore call. Without fetchAllRows, a single-shot cap applied to FETCH FIRST :limit ROWS ONLY-style queries.
fetchAllRowsbooleanfalseWhen true, paginate until the database reports is_done or the safety ceiling (IBMI_PAGINATION_MAX_ROWS, default 30000) is reached.

Composition

ConfigBehavior
rowsToFetch: N aloneSingle-shot execute(N) — up to N rows, one round-trip
fetchAllRows: true alonePaginate with IBMI_PAGINATION_DEFAULT_PAGE_SIZE (default 1000) per fetch
fetchAllRows: true, rowsToFetch: NPaginate with N rows per fetch — tune per tool for wide rows
When the paginated result hits IBMI_PAGINATION_MAX_ROWS, the server truncates the rows returned and emits a warning log. The CLI surfaces the truncation in the output footer so callers know the result was clipped.
Context-bloat warning: Large result sets consume LLM context quickly. Prefer rowsToFetch with a deliberate small value; only use fetchAllRows for small catalogs or when the caller has explicitly requested a full dump.
Lift the 100-row cap for a single call
tools:
  list_customers:
    source: ibmi-system
    description: "List up to 500 customers"
    rowsToFetch: 500          # lets FETCH FIRST :limit ROWS ONLY actually return 500
    statement: |
      SELECT ID, NAME FROM MYLIB.CUSTOMERS
      FETCH FIRST :limit ROWS ONLY
    parameters:
      - name: limit
        type: integer
        default: 500
        minimum: 1
        maximum: 500
Use when:
  • Your FETCH FIRST :limit ROWS ONLY clause needs more than 100 rows
  • You know the expected result size and want a predictable ceiling
  • You want row-count safety without running paginated fetches
Setting rowsToFetch alone does not automatically raise your SQL’s FETCH FIRST clause — you still need a parameter or literal that matches. rowsToFetch is the ceiling at the driver level.

Metadata

Add descriptive metadata for tool organization and discovery:
tools:
  inventory_analysis:
    source: ibmi-system
    description: "Comprehensive inventory analysis report"
    statement: |
      SELECT * FROM inventory_summary
    metadata:
      title: "Inventory Analysis Report"
      version: "2.1.0"
      author: "IBM i Development Team"
      keywords: ["inventory", "analysis", "reporting"]
      lastUpdated: "2024-01-15"
      domain: business
      category: reporting
      environment: production

Metadata Fields

Human-readable title for the tool
Semantic version for tracking tool changes
Individual or team responsible for the tool
Search keywords for tool discovery
Date of last modification (ISO format)
Business domain classification (monitoring, security, business, etc.)
Functional category within domain
Target environment (production, development, testing)

Complete Tool Examples

Simple Query (No Parameters)

tools:
  system_status:
    source: ibmi-system
    description: "Overall system performance statistics with CPU, memory, and I/O metrics"
    statement: |
      SELECT * FROM TABLE(QSYS2.SYSTEM_STATUS(
        RESET_STATISTICS=>'YES',
        DETAILED_INFO=>'ALL'
      )) X
    parameters: []

String Parameter with Validation

tools:
  get_employee_details:
    source: ibmi-sample
    description: "Retrieve detailed employee information including department and manager"
    statement: |
      SELECT
        E.EMPNO,
        E.FIRSTNME,
        E.LASTNAME,
        E.JOB,
        E.SALARY,
        D.DEPTNAME,
        M.LASTNAME AS MGR_LASTNAME
      FROM SAMPLE.EMPLOYEE E
      LEFT JOIN SAMPLE.DEPARTMENT D ON E.WORKDEPT = D.DEPTNO
      LEFT JOIN SAMPLE.EMPLOYEE M ON D.MGRNO = M.EMPNO
      WHERE E.EMPNO = :employee_id
    parameters:
      - name: employee_id
        type: string
        description: "Employee ID (e.g., '000010') - Must be 6 digits"
        required: true
        pattern: "^[0-9]{6}$"

Multiple Parameters with Different Types

tools:
  search_employees:
    source: ibmi-sample
    description: "Search for employees by name with pagination"
    statement: |
      SELECT
        E.EMPNO,
        E.FIRSTNME,
        E.LASTNAME,
        E.JOB,
        E.WORKDEPT,
        D.DEPTNAME
      FROM SAMPLE.EMPLOYEE E
      LEFT JOIN SAMPLE.DEPARTMENT D ON E.WORKDEPT = D.DEPTNO
      WHERE UPPER(E.FIRSTNME) LIKE UPPER('%' || :name_search || '%')
      OR UPPER(E.LASTNAME) LIKE UPPER('%' || :name_search || '%')
      ORDER BY E.LASTNAME, E.FIRSTNME
      LIMIT :page_size OFFSET (:page_number - 1) * :page_size
    parameters:
      - name: name_search
        type: string
        description: "Name to search for (partial match)"
        required: true
        minLength: 2
      - name: page_size
        type: integer
        description: "Number of results per page"
        default: 10
        minimum: 1
        maximum: 100
      - name: page_number
        type: integer
        description: "Page number (starting from 1)"
        default: 1
        minimum: 1

Tool with Security Configuration

tools:
  user_profile_audit:
    source: ibmi-system
    description: "Audit user profile security settings (requires *AUDIT authority)"
    statement: |
      SELECT
        user_profile_name,
        status,
        previous_signon,
        days_until_password_expires,
        user_class_name,
        group_profile_name
      FROM qsys2.user_info
      WHERE user_profile_name = :user_profile
    parameters:
      - name: user_profile
        type: string
        required: true
        pattern: "^[A-Z][A-Z0-9_]*$"
        maxLength: 10
        description: "User profile name to audit"
    security:
      readOnly: true
      audit: true
      requiredAuthority: "*AUDIT"
      scopes: ["security:audit"]
      warning: "Accesses sensitive user profile information. Requires *AUDIT authority."

Array Parameter Tool

tools:
  find_project_team_members:
    source: ibmi-sample
    description: "Find all employees working on specific projects"
    statement: |
      SELECT
        E.EMPNO,
        E.FIRSTNME,
        E.LASTNAME,
        E.JOB,
        EPA.PROJNO,
        EPA.EMSTDATE AS PROJECT_START_DATE
      FROM SAMPLE.EMPPROJACT EPA
      JOIN SAMPLE.EMPLOYEE E ON EPA.EMPNO = E.EMPNO
      WHERE EPA.PROJNO IN (:project_ids)
      ORDER BY EPA.PROJNO, E.LASTNAME
    parameters:
      - name: project_ids
        type: array
        itemType: string
        description: "List of project IDs (e.g., ['MA2100', 'AD3100'])"
        required: true
        minLength: 1
        maxLength: 10

Best Practices

Optimization:
  • Always include FETCH FIRST n ROWS ONLY to limit results
  • Use LEFT JOIN instead of INNER JOIN when relationships are optional
  • Add ORDER BY for consistent result ordering
  • Use column aliases for better AI understanding
Example:
SELECT
  job_name AS "Job Name",
  user_name AS "User",
  cpu_used AS "CPU Time (ms)"
FROM qsys2.active_job_info
WHERE job_status = 'ACTIVE'
ORDER BY cpu_used DESC
FETCH FIRST 100 ROWS ONLY
Always validate:
  • String patterns for IBM i names: ^[A-Z][A-Z0-9_]*$
  • String lengths: maxLength: 10 for library names
  • Integer ranges: minimum: 1, maximum: 1000
  • Required vs optional: Mark appropriately
Example:
parameters:
  - name: library
    type: string
    required: true
    pattern: "^[A-Z][A-Z0-9_]*$"
    maxLength: 10
    description: "IBM i library name (uppercase, max 10 chars)"
Write for AI agents:
  • Be specific about what data is returned
  • Mention any special authority requirements
  • Include parameter examples in descriptions
  • Note any result limits or performance considerations
Good example:
description: "List active jobs sorted by CPU usage. Returns top 100 jobs. Requires connection to production system. Results updated every 5 seconds."
Mark sensitive tools:
  • Set audit: true for all tools accessing user data
  • Use readOnly: true for SELECT-only operations
  • Document required authorities in security.requiredAuthority
  • Add warnings for potentially destructive operations
Example:
security:
  readOnly: true
  audit: true
  requiredAuthority: "*SECADM"
  warning: "Accesses security configuration. Use with caution."

Next Steps

Sources Reference

Configure database connection sources

Toolsets Reference

Organize tools into logical groups

Building SQL Tools

Step-by-step guide with examples

Parameter Validation

Deep dive into validation rules
Tool Design Philosophy: Effective tools are discoverable (clear names and descriptions), safe (proper validation and security), and performant (optimized SQL with result limits). Write tools for AI agent consumption, not just human readability.