Skip to main content
Glama

Cluster Points

cluster_points

Groups the points of one ingested layer into balanced clusters directly, with no ZIP or part layer and no territory alignment. Writes group_field (default group_id) on every point and colors the layer by it, replacing any prior color classification (size and shape channels stay). Needs build_mode (fixed_territory_count or fixed_workload_target), objective, and dwell_time, as in auto_build; a missing one returns CLARIFICATION_REQUIRED with the question. point_filter (e.g. {STATE: FL}) clusters a subset of the layer; unmatched points stay, ungrouped. Max 25,000 points after the filter. seed_point_layer, a second point layer such as technician homes, anchors one group per seed (the seed count matches the group count, else seed_count_mismatch); seed_attraction 0-100 (default 70) is the pull of each seed on its group. Returns a task; the result lists groups with point_count, workload_hours, and point_ids.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "point_layer": "<point_layer>"
    },
    "name": "cluster_points"
  }
}

Input Schema

NameRequiredDescriptionDefault
objectiveNo
point_idsNoOptional point_id / row_id / account_id values to cluster. Unmatched points stay on the layer ungrouped.
ts_handleNoTerritory Solution reference (tsh_...) from a build, ingest_accounts, import_geojson, import_designer_project, or get_map_visualization; Territory Solutions are not accepted inline.
build_modeNo
dwell_timeNo
group_fieldNogroup_id
point_layerYes
point_filterNoOptional property filter on the named point layer. Keys are point properties (equality or IN list). Multiple keys are AND. Example: {"STATE": "FL"}. Unmatched points stay on the layer ungrouped. part_filter and part_scope are not used here.
metric_fieldsNoMetric columns to declare on the point layer (same shape as ingest_accounts metric_fields).
map_session_idNoOpen map session (msess_...) from get_map_visualization. Its Territory Solution is the input; omit ts_handle when set.
seed_attractionNoHow hard each group centroid is held at its seed. 100 pins it at the seed; 0 seeds only the starting point and lets the solver drift to the workload centroid. Requires seed_point_layer.
seed_point_layerNoSecond ingested point layer whose locations anchor the group centroids one-to-one (technician homes, depots). Must differ from point_layer; its point count must equal the group count.
expected_revisionNo
group_label_prefixNoGroup
visit_frequency_fieldNo

Output Schema

NameRequiredDescriptionDefault
okYes
errorNoPresent when ok is false.
resultNoPresent when ok is true. A submission returns the task reference (task_id, next_action, sleep_ms); the completed task result carries the remaining fields.
warningsNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed12 schema fields changed
    • changedInput schema / properties / build_mode / anyOf
      Previous value: -[
      -  {
      -    "oneOf": [
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "mode": {
      -            "const": "fixed_territory_count"
      -          },
      -          "territory_count": {
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "required": [
      -          "mode",
      -          "territory_count"
      -        ],
      -        "type": "object"
      -      },
      -      {
      -        "additionalProperties": false,
      -        "properties": {
      -          "mode": {
      -            "const": "fixed_workload_target"
      -          },
      -          "target_workload": {
      -            "exclusiveMinimum": 0,
      -            "type": "number"
      -          },
      -          "workload_unit": {
      -            "default": "hours",
      -            "enum": [
      -              "minutes",
      -              "hours"
      -            ],
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "mode",
      -          "target_workload"
      -        ],
      -        "type": "object"
      -      }
      -    ]
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "description": "Sizing mode: {mode: 'fixed_territory_count', territory_count: <int>} or {mode: 'fixed_workload_target', target_workload: <number>, workload_unit: 'hours'|'minutes'}.",
      +    "properties": {
      +      "mode": {
      +        "description": "Sizing mode for clustering.",
      +        "enum": [
      +          "fixed_territory_count",
      +          "fixed_workload_target"
      +        ],
      +        "type": "string"
      +      },
      +      "target_workload": {
      +        "description": "Target workload per group when mode='fixed_workload_target'.",
      +        "exclusiveMinimum": 0,
      +        "type": "number"
      +      },
      +      "territory_count": {
      +        "description": "Target number of groups when mode='fixed_territory_count'.",
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "workload_unit": {
      +        "default": "hours",
      +        "description": "Unit for target_workload ('hours' or 'minutes').",
      +        "enum": [
      +          "minutes",
      +          "hours"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "mode"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • removedInput schema / properties / build_mode / description
      Removed value: -"Required unless modern form elicitation supplies sizing."
    • addedInput schema / properties / build_mode / title
      Added value: +"Build Mode"
    • addedInput schema / properties / point_ids
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Optional point_id / row_id / account_id values to cluster. Unmatched points stay on the layer ungrouped.",
      +  "title": "Point Ids"
      +}
    • changedOutput schema / properties / result / description
      Previous value: -"Present when ok is true."New value: +"Present when ok is true. A submission returns the task reference (task_id, next_action, sleep_ms); the completed task result carries the remaining fields."
    • changedOutput schema / properties / result / properties / do_this_next / type
      Previous value: -"string"New value: +[
      +  "object",
      +  "string"
      +]
    • addedOutput schema / properties / result / properties / job_id
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / result / properties / next_action
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / result / properties / sleep_ms
      Added value: +{
      +  "type": "integer"
      +}
    • addedOutput schema / properties / result / properties / status
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / result / properties / task_id
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / result / properties / terminal
      Added value: +{
      +  "type": "boolean"
      +}
  2. Changed18 schema fields changed
    • changedInput schema / properties / build_mode / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": true,
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "oneOf": [
      +      {
      +        "additionalProperties": false,
      +        "properties": {
      +          "mode": {
      +            "const": "fixed_territory_count"
      +          },
      +          "territory_count": {
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "required": [
      +          "mode",
      +          "territory_count"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "additionalProperties": false,
      +        "properties": {
      +          "mode": {
      +            "const": "fixed_workload_target"
      +          },
      +          "target_workload": {
      +            "exclusiveMinimum": 0,
      +            "type": "number"
      +          },
      +          "workload_unit": {
      +            "default": "hours",
      +            "enum": [
      +              "minutes",
      +              "hours"
      +            ],
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "mode",
      +          "target_workload"
      +        ],
      +        "type": "object"
      +      }
      +    ]
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / build_mode / description
      Added value: +"Required unless modern form elicitation supplies sizing."
    • removedInput schema / properties / build_mode / title
      Removed value: -"Build Mode"
    • addedInput schema / properties / map_session_id / description
      Added value: +"Open map session (msess_...) from get_map_visualization. Its Territory Solution is the input; omit ts_handle when set."
    • changedInput schema / properties / metric_fields / anyOf
      Previous value: -[
      -  {
      -    "items": {
      -      "additionalProperties": true,
      -      "type": "object"
      -    },
      -    "type": "array"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "items": {
      +      "additionalProperties": false,
      +      "properties": {
      +        "field": {
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "label": {
      +          "type": "string"
      +        },
      +        "role": {
      +          "description": "Optional semantic role for workload columns. Agents should set visit_frequency or dwell_time when declaring canonical workload inputs.",
      +          "type": "string"
      +        },
      +        "type": {
      +          "enum": [
      +            "number",
      +            "integer",
      +            "string",
      +            "boolean"
      +          ],
      +          "type": "string"
      +        },
      +        "unit": {
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "field"
      +      ],
      +      "type": "object"
      +    },
      +    "type": "array"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / metric_fields / description
      Added value: +"Metric columns to declare on the point layer (same shape as ingest_accounts metric_fields)."
    • removedInput schema / properties / metric_fields / title
      Removed value: -"Metric Fields"
    • changedInput schema / properties / point_filter / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": true,
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": {
      +      "anyOf": [
      +        {
      +          "type": [
      +            "string",
      +            "number",
      +            "boolean"
      +          ]
      +        },
      +        {
      +          "items": {
      +            "type": [
      +              "string",
      +              "number",
      +              "boolean"
      +            ]
      +          },
      +          "minItems": 1,
      +          "type": "array"
      +        }
      +      ]
      +    },
      +    "minProperties": 1,
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / point_filter / description
      Added value: +"Optional property filter on the named point layer. Keys are point properties (equality or IN list). Multiple keys are AND. Example: {\"STATE\": \"FL\"}. Unmatched points stay on the layer ungrouped. part_filter and part_scope are not used here."
    • removedInput schema / properties / point_filter / title
      Removed value: -"Point Filter"
    • addedInput schema / properties / seed_attraction / description
      Added value: +"How hard each group centroid is held at its seed. 100 pins it at the seed; 0 seeds only the starting point and lets the solver drift to the workload centroid. Requires seed_point_layer."
    • addedInput schema / properties / seed_point_layer / description
      Added value: +"Second ingested point layer whose locations anchor the group centroids one-to-one (technician homes, depots). Must differ from point_layer; its point count must equal the group count."
    • removedInput schema / properties / ts
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "additionalProperties": true,
      -      "type": "object"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "title": "Ts"
      -}
    • addedInput schema / properties / ts_handle / description
      Added value: +"Territory Solution reference (tsh_...) from a build, ingest_accounts, import_geojson, import_designer_project, or get_map_visualization; Territory Solutions are not accepted inline."
    • removedOutput schema / additionalProperties
      Removed value: -true
    • addedOutput schema / properties
      Added value: +{
      +  "error": {
      +    "description": "Present when ok is false.",
      +    "properties": {
      +      "ask_user": {
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "code": {
      +        "type": "string"
      +      },
      +      "details": {
      +        "type": "object"
      +      },
      +      "do_this_next": {
      +        "type": "object"
      +      },
      +      "message": {
      +        "type": "string"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "ok": {
      +    "type": "boolean"
      +  },
      +  "result": {
      +    "description": "Present when ok is true.",
      +    "properties": {
      +      "annotation_summary": {
      +        "type": "object"
      +      },
      +      "build_mode_summary": {
      +        "type": "object"
      +      },
      +      "creates_tal": {
      +        "type": "boolean"
      +      },
      +      "distribution_summary": {
      +        "type": "object"
      +      },
      +      "do_this_next": {
      +        "type": "string"
      +      },
      +      "expires_at": {
      +        "type": "string"
      +      },
      +      "group_count": {
      +        "type": "integer"
      +      },
      +      "group_field": {
      +        "type": "string"
      +      },
      +      "group_labels": {
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "groups": {
      +        "items": {
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "map_refresh": {
      +        "type": "object"
      +      },
      +      "objective_summary": {
      +        "type": "object"
      +      },
      +      "point_count": {
      +        "type": "integer"
      +      },
      +      "point_filter_summary": {
      +        "type": "object"
      +      },
      +      "point_layer": {
      +        "type": "string"
      +      },
      +      "seed_summary": {
      +        "type": "object"
      +      },
      +      "ts_handle": {
      +        "type": "string"
      +      },
      +      "ts_identity": {
      +        "type": "object"
      +      },
      +      "ts_omitted": {
      +        "type": "object"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "warnings": {
      +    "items": {
      +      "properties": {
      +        "code": {
      +          "type": "string"
      +        },
      +        "message": {
      +          "type": "string"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "type": "array"
      +  }
      +}
    • addedOutput schema / required
      Added value: +[
      +  "ok"
      +]
    • removedOutput schema / title
      Removed value: -"cluster_pointsDictOutput"
  3. Changed1 schema field changed
    • changedInput schema / properties / objective / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": true,
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "description": "Balance objective: {metric: '<column>|__account_count__', workload_bias: 0..100, metric_bias: 0..100}. Biases sum to 100. For pure metric balance, pass {metric: '<column>', workload_bias: 0, metric_bias: 100} (or {metric: '<column>'} on restructure tools). When omitted on restructure tools, inherits the source TAL build_provenance objective or seed_build target.",
      +    "properties": {
      +      "metric": {
      +        "description": "Point metric column name to balance (e.g. 'Revenue', 'weekly_volume'), or '__account_count__' for location-count balance.",
      +        "type": "string"
      +      },
      +      "metric_bias": {
      +        "description": "Weight (0..100) on the metric or location-count dimension.",
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "workload_bias": {
      +        "description": "Weight (0..100) on workload (drive time + dwell).",
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  4. Changed1 schema field changed
    • changedInput schema / properties / dwell_time / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": true,
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "description": "Onsite (dwell) time per visit: {type: 'scalar', value: <number>, unit: 'minutes'|'hours'} or {type: 'field', field: '<column>', unit: 'minutes'|'hours'}.",
      +    "properties": {
      +      "field": {
      +        "description": "Point column name holding per-account onsite time when type='field'.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "type": {
      +        "description": "Dwell source: 'scalar' for a fixed per-visit duration or 'field' for an ingested point column.",
      +        "enum": [
      +          "scalar",
      +          "field"
      +        ],
      +        "type": "string"
      +      },
      +      "unit": {
      +        "default": "minutes",
      +        "description": "Time unit for value or field ('minutes' or 'hours').",
      +        "enum": [
      +          "minutes",
      +          "hours"
      +        ],
      +        "type": "string"
      +      },
      +      "value": {
      +        "description": "Confirmed onsite duration per visit when type='scalar'.",
      +        "minimum": 0,
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "type"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  5. Changed1 schema field changed
    • removedInput schema / properties / guidance_handle
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "title": "Guidance Handle"
      -}
  6. First observed

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses consequential side effects beyond annotations: writes group_field on every point, recolors the layer replacing prior classification while preserving size/shape channels, enforces a 25,000-point cap, and returns CLARIFICATION_REQUIRED or seed_count_mismatch on specific failures. It also states it returns a task and what the result contains, which the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and scope, then moves through parameters in a logical order with no filler. Several sentences are long and pack multiple clauses (filter, cap, seeds) that could be split, but nearly every clause carries operative information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 15-parameter mutation tool, the description covers the required inputs, filter behavior, seed constraints, failure modes, and task-based return. Gaps around input-source params (ts_handle, map_session_id) are partly mitigated by their own schema descriptions, and an output schema exists so return values need little elaboration.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 47% schema coverage across 15 params, the description meaningfully compensates: it explains the required trio (build_mode, objective, dwell_time), the filter/subset semantics with a concrete example, and seed_point_layer/seed_attraction including the default of 70 that the schema omits. It leaves ts_handle, map_session_id, metric_fields, expected_revision, and group_label_prefix undescribed, so it is not fully compensating.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource+scope: 'Groups the points of one ingested layer into balanced clusters directly, with no ZIP or part layer and no territory alignment.' The negative clauses explicitly distinguish it from part/territory-based siblings like auto_build and direct_build.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than routed: 'no ZIP or part layer and no territory alignment' tells the agent this is the point-only path, and 'as in auto_build' points at a related sibling for required inputs. But there is no explicit statement of when to choose this over seed_build, direct_build, or auto_build, and no exclusions beyond the scope phrase.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources