Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

EasyTerritory MCP

REMOTE · MCP.EASYTERRITORY.AI · SCANNED OCT 7

Build, balance, realign and analyze sales/service territories; geocode, route, schedule, live map.

+3 this week 76 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score → Why this is hard to score →

Endpoint Security89
Transport & Reachability100
Schema Quality & AI Usability69
  • 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
  • AI-judged instruction clarity (good).Pass
  • Context-footprint check failed: tool/resource definitions use about 21018 tokens (~404/item across 52 items; 47 tools + 5 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management26
  • Stability check failed: schema churn in the 8 days we've observed: 0 tool removals, 1 breaking changes, 0 auth/transport breaks, 0 additions. See how to fix → Fail
Tool Coverage72
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 2% of tool parameters carry a description.Partial
  • Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety75
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • 0 of 4 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "delete_tal" implies "delete" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
  • An AI judge read all 49 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a current MCP spec version (2026-07-28).Pass
  • Supports UI / widget rendering.Pass
Install

How do I install the EasyTerritory MCP server?

EasyTerritory MCP is a hosted endpoint at https://mcp.easyterritory.ai/, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

remote · mcp.easyterritory.ai

# add to Claude Code
claude mcp add --transport http ai-easyterritory-ezt-mcp 'https://mcp.easyterritory.ai/'
// .cursor/mcp.json
{
  "mcpServers": {
    "ai-easyterritory-ezt-mcp": {
      "url": "https://mcp.easyterritory.ai/"
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "ai-easyterritory-ezt-mcp": {
      "type": "http",
      "url": "https://mcp.easyterritory.ai/"
    }
  }
}
# ~/.codex/config.toml
[mcp_servers.ai-easyterritory-ezt-mcp]
url = "https://mcp.easyterritory.ai/"
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ai-easyterritory-ezt-mcp": {
      "type": "remote",
      "url": "https://mcp.easyterritory.ai/",
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add ai-easyterritory-ezt-mcp --url 'https://mcp.easyterritory.ai/' --transport streamable-http
# ~/.hermes/config.yaml
mcp_servers:
  ai-easyterritory-ezt-mcp:
    url: "https://mcp.easyterritory.ai/"
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "ai-easyterritory-ezt-mcp": {
      "Transport": "http",
      "Url": "https://mcp.easyterritory.ai/"
    }
  }
}
# add to Vellum
assistant mcp add ai-easyterritory-ezt-mcp -t streamable-http -u 'https://mcp.easyterritory.ai/'
// mcp.json
{
  "mcpServers": {
    "ai-easyterritory-ezt-mcp": {
      "type": "http",
      "url": "https://mcp.easyterritory.ai/"
    }
  }
}

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 7 Oct 26 +1
    • Stability: 0.17 → fail ▼ security
    • The server rewrote its instructions, which are the text every model session reads security
    • Tool “analyze” rewrote its description, which is the text the model reads security
    • Tool “delete_territory” rewrote its description, which is the text the model reads security
    • Tool “ensure_map_viewer” rewrote its description, which is the text the model reads security
    • Tool “set_map_state” rewrote its description, which is the text the model reads security
    • Tool “territory_merge” rewrote its description, which is the text the model reads security
    • Tool “territory_rebalance” rewrote its description, which is the text the model reads security
  • 4 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.

  • 2 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

  • 30 Sept 26 +1
    • Stability: unverified → 0.03 ▲ functional
  • 29 Sept 26 72

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 9 Oct 2026 · Probed https://mcp.easyterritory.ai/

TLS valid

Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .

Subject Issuer Valid from Valid until Key Signature Serial
CN=mcp.easyterritory.ai CN=GeoTrust TLS RSA CA G1,OU=www.digicert.com,O=DigiCert Inc,C=US 11 Aug 2026 11 Feb 2027 RSA 2048 SHA256-RSA 9e95ccc46c8a973dd1d2d3db065a823
SANs: mcp.easyterritory.ai
CN=GeoTrust TLS RSA CA G1,OU=www.digicert.com,O=DigiCert Inc,C=US (CA) CN=DigiCert Global Root G2,OU=www.digicert.com,O=DigiCert Inc,C=US 2 Nov 2017 2 Nov 2027 RSA 2048 SHA256-RSA d07782a133fc6f9a57296e131ffd179
CN=DigiCert Global Root G2,OU=www.digicert.com,O=DigiCert Inc,C=US (CA) CN=DigiCert Global Root G2,OU=www.digicert.com,O=DigiCert Inc,C=US 1 Aug 2013 15 Jan 2038 RSA 2048 SHA256-RSA 33af1e6a711a9a0bb2864b11d09fae5

Background: What to check on a remote MCP endpoint →

DNSSEC insecure

Validation of mcp.easyterritory.ai. — Not signed

Zone DS Keys Algorithms Outcome
. trust_anchor 20326, 38696 8, 8 Verified
ai. present 3799 8 Verified
easyterritory.ai. absent Unsigned (proven) parent-signed NSEC/NSEC3 proves an unsigned delegation
Authentication Enforced and verified

The endpoint asked for a token and published valid RFC 9728 metadata describing how to get one.

Result Enforced and verified
Enforced On tool calls
HTTP status 200

WWW-Authenticate challenge Bearer realm="EZT MCP", resource_metadata="https://mcp.easyterritory.ai/.well-known/oauth-protected-resource", scope="ezt.mcp"

Bearer realm="EZT MCP", resource_metadata="https://mcp.easyterritory.ai/.well-known/oauth-protected-resource", scope="ezt.mcp"

Protected resource metadata

Document https://mcp.easyterritory.ai/.well-known/oauth-protected-resource
Retrieved Yes
Resource https://mcp.easyterritory.ai/
Authorisation server https://mcp.easyterritory.ai/

Background: How OAuth 2.1 works in the 2026 MCP spec →

Transports 2 probes
Transport URL Outcome Status Location
streamable-http https://mcp.easyterritory.ai/ Verified 200
http (plaintext) http://mcp.easyterritory.ai/ HTTPS enforced 301 https://mcp.easyterritory.ai/
MCP tools · 47 exposed · ~20,266 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
account_build ~507

[Tier 1 — Attribute Grouping Builder] When: territories should mirror an account attribute column from CRM exports (rep name, territory_name, territory code). Prerequisites: ingest_accounts with grouping column; part_layer chosen; viewer connected. Omit ts and ts_handle when the session id argument is already set. That session is the TS. Numeric codes are labels, not balance metrics; scoped builds use in-scope accounts only. Part scope defaults to bbox_intersect (bbox proximity of ingested accounts). When the user names a state/region ('TX ZIPs only'), pass part_scope=explicit and part_filter={state_abbr: TX} — not bbox_intersect. Scope fields are top-level part_filter/part_ids. Progress: linked tasks publish live subphases on Tasks status / MC overlay (grouping → radial seeds → inflate → empty-part assign → interlock polish) with cooperative cancel — same poll loop as auto_build (next_action / sleep_ms). VISIT FREQUENCY: when a cadence column is declared, pass visit_frequency_field to scale workload or ignore_visit_frequency=true for one visit per cycle — do not inherit the column silently. Modern form-capable clients (protocol >= 2026-07-28) may be prompted in-band for missing grouping_field / part_layer / tal_label; legacy hosts keep required-arg / INVALID_REQUEST errors. Next: analyze + load_analysis_panel. Scenarios: ACB-001..004, MC-011.

NameTypeReqDescription
conflict_policystring––
expected_revision–––
grouping_field–––
guidance_handle–––
ignore_visit_frequency–––
map_session_id–––
output_modestring–tal is the default. assignments returns assignments_artifact plus an authenticated download_url; no ts_handle, tal_id, or map_refresh.
part_filter–––
part_ids–––
part_layer–––
part_scope–––
point_layerstringyes–
repair_policystring–Topology repair for dissolved territories. default fills interior holes in the dissolved geometry (no part is added or reassigned; repair_summary.changed_part_ids lists the territories' own parts). r…
tal_label–––
ts–––
ts_handle–––
visit_frequency_field–––

Structured output declared, but exposes no named fields.

No examples provided.

analyze ~917

[Tier 1 — Analysis] When: balance diagnostics, cross-TAL comparison, or post-mutation facts. Accepts ts, ts_handle, or completed job_id (inline ts or result.ts_handle from prior compute jobs), or map_session_id alone to analyze the open map as it is now, including points ingested after the build. A job_id or ts_handle is that job's snapshot and wins when both are passed, except when the snapshot has no points and the open map does: then the live map is analyzed and the result warns ANALYZED_LIVE_SESSION. Prerequisites: TAL exists; re-run after any TAL or point change (I-2)—never treat stale analysis as current. Returns JSON facts and presentation guidance URI; no prose. metrics: omit to analyze all declared point-layer columns, or pass explicit names. System dimensions (always valid, not point columns): workload (territory hours; alias total_workload_hours), account_count. Point columns must be fields declared at ingest (metric_fields/workload_fields, e.g. Revenue, Units Sold); undeclared columns are discarded at ingest and fail with UNDECLARED_FIELD — re-ingest with the column declared to analyze it. Response includes available_metrics. METRIC COLUMNS ALWAYS RENDER: the territory_metric_grids (and the MC dock) carry Total Count plus a Total <metric> column for EVERY declared metric_fields column of the point layer, in declaration order, even when metrics names only account_count or workload — a count-only panel is never the correct outcome when metrics are declared. Declared names may be bare strings (Designer pull) or {field,label,type} objects (ingest). Metric cells are parsed leniently: '14,651', '$1,200.50', and padded strings sum as numbers. DWELL / WORKLOAD (T-171): workload hours need onsite/dwell time — request dwell_time, TAL build_provenance.dwell_time (auto_build), or the point layer's dwell_time_field. When none resolves, Analyze STILL RUNS and reports counts, metrics, classification breakdowns, and balance on those dimensions; workload is OMITTED (no…

NameTypeReqDescription
analysis_panel–––
compare_talsboolean––
dwell_time–––
guidance_handle–––
hypothetical_moves–––
job_id–––
map_session_id–––
max_depth–––
metrics–––
part_layer–––
scope–––
tal_ids–––
ts–––
ts_handle–––
visit_frequency_field–––

Structured output declared, but exposes no named fields.

No examples provided.

analyze_routes ~358

[Tier 2 — Route Facts] When: you need per-route numbers for routes calculate_route already drew — drive hours, dwell hours, route_workload_hours, stop coordinates, centroid, bbox (e.g. 'which of my Houston runs has room for one more stop', 'total hours for each route'). Prerequisites: at least one route in the session/TS (map_session_id preferred, else ts_handle); dwell confirmed by the user unless calculate_route already stored it. route_workload_hours = provider drive time + confirmed dwell, with NO visit-frequency multiplier. dwell_hours is one dwell per stop in stop_count. A circuit's stop_count includes the return to the start, so that account is charged dwell twice. Cluster and territory workload charge each account once. This is a DIFFERENT quantity from those hours — never sum, compare, or substitute one for the other. FACTS ONLY: no capacity, no headroom, no ranking, no overloaded flag. Apply constraints like 'nearest route under 7 hours' yourself from centroid + route_workload_hours, then add the stop by re-running calculate_route with that route_id and the revised stop list. Anti-patterns: do NOT call analyze for routes (analyze is TAL/part-grained and returns territory workload); do NOT feed these hours into auto_build, territory_rebalance, or a territory workload figure. Unresolved dwell returns CLARIFICATION_REQUIRED / needs_dwell — ask the user, never invent a default (including 30 minutes). Synchronous: no task_id. Scenarios: RT-011.

NameTypeReqDescription
dwell_time–––
guidance_handle–––
map_session_id–––
route_ids–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

auto_build ~1,221

[Tier 1 — Balanced Territory Builder] When: partition account points into N balanced territories over a part layer (for example, ten territories; Mode A count, Mode B workload target, Scoped Split). Execution gate: after sizing, balance, dwell, and scope are known, call THIS tool immediately — searching the catalog, get_guidance, or polling Tasks never starts a build. A successful response with a new task_id is the only proof of submit; do not claim started/restarting until then. Then follow do_this_next only with that new task_id. When workflow_advisor returns next_tool=auto_build, call auto_build next. Canonical example — 3 TX ZIP territories, workload-only, 30-min dwell: build_mode={mode: fixed_territory_count, territory_count: 3}, objective={workload_bias: 100}, dwell_time={type: scalar, value: 30, unit: minutes}, part_scope=explicit, part_filter={state_abbr: TX}, map_session_id=<open MC>. Omit ts and ts_handle when the session id argument is already set. That session is the TS. Do not repost inline ts. build_mode.mode must be exactly one of: fixed_territory_count, fixed_workload_target, scoped_split. For workload targets (e.g. 40-hour territories), use build_mode={mode: fixed_workload_target, target_workload: 40} (territories only approximate the target). ALWAYS ask for dwell/onsite time before calling — Auto Build always computes territory workload hours (drive + dwell), even when balancing on a metric or account count. Pass dwell_time only after they confirm a column ({type: field, field, unit}) or scalar ({type: scalar, value, unit}). Never invent default dwell such as 1 hour or 30 minutes per visit. Server rejects auto_build without resolved dwell_time (CLARIFICATION_REQUIRED). VISIT FREQUENCY: when the point layer has a visit-frequency column, ask whether to aggregate workload across a schedule period (pass visit_frequency_field) or ignore it (pass ignore_visit_frequency=true). Do not inherit the column silently. If no visit-frequency column exists, omit…

NameTypeReqDescription
build_mode–––
dwell_time–––
expected_revision–––
guidance_handle–––
ignore_visit_frequency–––
map_session_id–––
objective–––
output_modestring–tal is the default. assignments returns assignments_artifact plus an authenticated download_url; no ts_handle, tal_id, or map_refresh.
part_filter–––
part_ids–––
part_layerstringyes–
part_scope–––
point_layerstringyes–
repair_policystring–Topology repair for dissolved territories. default fills interior holes in the dissolved geometry (no part is added or reassigned; repair_summary.changed_part_ids lists the territories' own parts). r…
tal_labelstringyes–
ts–––
ts_handle–––
visit_frequency_field–––

Structured output declared, but exposes no named fields.

No examples provided.

calculate_route ~869

[Tier 1 — Routing] When: drive a list of stops in the best sequence — a windshield itinerary, a service run, a delivery sheet (RT-001..RT-008). This tool routes and sequences existing stops; it never creates or rebalances territories. When a visit-frequency column is on the point layer, the word route is ambiguous — confirm the user wants a driving itinerary of those stops, not schedule_visits, before calling this tool. Prerequisites: a TomTom or Azure Maps key on the server; stops referenced by point_layer must already be ingested, or pass inline lat/lon. TERRITORY STOPS: after a TAL is built or analyze linkage runs, account points carry territory_id. Route one territory with stop_sets source.filter.territory_id set to the leaf id from the last build (leaf_territories[].territory_id), not a display label. start is exactly one stop (home, depot, or one point_id). The territory filter belongs on stop_sets, never on start. ORDERED STOP SETS: stop_sets are visited in the order supplied and optimization NEVER moves a stop between sets, which keeps 'start at home, hit the depot, then the day's calls' in the right sequence. Use order='optimize' to let the solver sequence a set, 'as_given' to keep it fixed. group_by_field splits one set into ordered bands on a column value (e.g. route_priority: every 1 precedes every 2, optimized inside each band). ROUTE TYPES: 'circuit' returns to the start; 'tour' finishes at a declared end stop (end is required); 'open_tour' is a one-way run that ends at the last stop the solver picks, never returning to the start. A circuit's stop_count includes that return. analyze_routes charges dwell once per stop, so the start account is charged dwell twice. Cluster and territory workload charge each account once — those hour figures are not this route's hours. Sequencing is solved server-side against straight-line distance, then one provider call returns road distances, durations, and geometry, so reported numbers are always road-accurate. Drive…

NameTypeReqDescription
depart_at–––
dwell_time–––
end–––
guidance_handle–––
include_geometryboolean––
map_session_id–––
route_id–––
route_label–––
route_typestringyes–
startobjectyes–
stop_setsarrayyes–
travel_modestring––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

cluster_points ~829

[Tier 1 — Balanced Point Grouping] Partition one ingested point layer directly into balanced point groups with CCPD, without using ZIPs/counties or creating a TAL. The tool adds group_field (default group_id) to every point and color-classifies that field in the linked Map Component. That write replaces the layer's existing color classification (including a leftover color_classification ramp). Size and shape channels stay. Keep a prior metric as a second encoding with configure_map channel=size or channel=shape after this job — never a second color classification on the same layer. Example — five TX point groups balanced on workload with confirmed 30-minute dwell: point_layer=accounts, build_mode={mode: fixed_territory_count, territory_count: 5}, objective={workload_bias: 100}, dwell_time={type: scalar, value: 30, unit: minutes}. Prerequisite: ingest_accounts completed for point_layer. Omit ts and ts_handle when the session id argument is already set. That session is the TS. Ask the same sizing, balance, bias, visit-frequency, and dwell questions; workload means in-group drive time plus dwell, never a metric column. Never invent dwell. build_mode supports fixed_territory_count and fixed_workload_target only. SUBSET: a named state or region on an already-ingested layer — Florida schools, TX accounts only — uses point_filter on the first call, e.g. point_filter={STATE: FL}. Keys are point properties (one value or a list). Do not re-ingest a filtered extract. Do not pass part_filter or part_scope (those belong to ZIP/part tools). Do not cluster the national layer. Unmatched points stay on the layer with group_field cleared and appear as an Ungrouped legend class. The 10,000-point cap applies after the filter. Empty match is EMPTY_POINT_FILTER; unknown property is UNKNOWN_POINT_PROPERTY. SEEDING BIAS (start locations): when the groups should line up with a set of start locations — technician homes, depots, branch offices — pass seed_point_layer=<that layer>. It must be…

NameTypeReqDescription
build_mode–––
dwell_time–––
expected_revision–––
group_fieldstring––
group_label_prefixstring––
guidance_handle–––
map_session_id–––
metric_fields–––
objective–––
point_filter–––
point_layerstringyes–
seed_attraction–––
seed_point_layer–––
ts–––
ts_handle–––
visit_frequency_field–––

Structured output declared, but exposes no named fields.

No examples provided.

configure_map ~773

[Tier 2 — Durable Map Config] When: set or update project_name (the durable TS short name used as the Map Component heading), loaded_part_layers, active_part_layer, active_tal_id, point_layer_classifications, classification, presentation, center, or zoom on the TS. project_name is first-class: persists to ts.properties.map_config.project_name and emits config_changed so a linked session refreshes the heading in place. POINT SYMBOLOGY: point_layer_classifications is the way to recolor/resize/reshape points on an open map — never export GeoJSON, compute breaks client-side, and repost a TS. Each entry is {point_layer, field, method: quantile|equal_interval|categorical|manual, class_count (2-12), channel: color|size|shape, optional colors/sizes/shapes, optional style:{color,size,opacity,shape} for the layer base symbol}. Supported shapes: circle|square|triangle|diamond|star|cross|house|pin|flag|hexagon|pentagon|shield|arrow_up|building (aliases home→house, marker/map_pin→pin, hex→hexagon, arrow/up→arrow_up, warehouse/depot→building, plus/x→cross). The server computes breaks from the in-session points, writes point_layers[].<channel>_classification, pushes config_changed, and returns the applied classes with per-class counts. Categorical missing values become an Ungrouped class. One classification per channel per layer: a second color entry replaces the first. Two encodings on one layer mix channels (color+size or color+shape). clear:true with point_layer and channel drops that channel classification, including a same-channel classification object. Other channels and the base style stay. active_channels reports the channels still set. Method defaults to quantile for numeric fields and categorical otherwise; pass one entry per layer to give two point layers distinct colors or shapes. classification (without a point_layer) stays a project-level map_config patch and does NOT paint points; a point-layer-targeted classification is routed to symbology with a warning. PART LAY…

NameTypeReqDescription
active_part_layer–––
active_tal_id–––
center–––
classification–––
expected_content_hash–––
expected_revision–––
guidance_handle–––
loaded_part_layers–––
map_session_id–––
merge_strategy–––
point_layer_classifications–––
presentation–––
project_name–––
ts–––
ts_handle–––
zoom–––

Structured output declared, but exposes no named fields.

No examples provided.

create_territory_from_parts ~540

[Tier 2 — Territory From Parts] When: create or update one leaf territory from committed part IDs (manual MC-005 build or RL-011/012). Prerequisites: part_ids from selection or agent list; part_layer; viewer connected. Pass map_session_id for the open MC — the server loads that session's TS, appends the new TAL, and rebinds the same session before map_refresh (do not call get_map_visualization just to show the new territory). If result.map_refresh.notified is false or status is rebind_required, call get_map_visualization(job_id=<this job>). With no open MC, pass ts_handle from the prior result (never repost inline ts when a handle exists); the new TAL is appended to that TS and the result returns a new ts_handle. map_session_id wins when both are passed. Completed result includes created_territory.territory_id, leaf_territories, and selection_summary (requested/unique counts plus duplicate_part_ids) — territory_name is a display label only (e.g. T1 → territory_id like tal-t1-t1). Later realign into this territory MUST use created_territory.territory_id (preferred) or the exact leaf display name when unique; never invent shorthand (T3 ≠ Territory 3) — if unclear, ask which leaf from leaf_territories. DWELL: this tool creates a NEW TAL and does not inherit dwell_time from a prior auto_build. Dwell is NOT required to create the territory (same as direct_build). Optional dwell_time={type:scalar,value,unit} stamps build_provenance for later Analyze. Without dwell, Analyze still runs and reports every other statistic but OMITS workload (result.workload_omitted) — present the stats, then relay its ask_user sentence; never invent a default (including 30 minutes). Modern form-capable clients may be prompted in-band for dwell when a hydrated TS shows points without dwell provenance; declining still allows create (HITL-038). Next: repeat for additional territories, realign with created_territory.territory_id, or analyze with confirmed dwell_time. Scenarios: MC-005, RL-011, RL…

NameTypeReqDescription
conflict_policy–––
dwell_time–––
guidance_handle–––
map_session_id–––
part_idsarrayyes–
part_layerstringyes–
tal_id–––
territory_namestringyes–
territory_path–––
ts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

delete_route ~199

[Tier 2 — Delete Route] When: drop a whole route from the map and the TS (e.g. 'delete the Tuesday A route', 'remove route houston-tue-a'). Prerequisites: map_session_id for an open MC (preferred), else ts_handle; plus route_id (or an exact unique route label). NOT for removing a single stop — for that, call calculate_route again with the SAME route_id and the remaining stops, which replaces the route in place. Already-absent routes return ok with already_absent=true and no error. An ambiguous label returns AMBIGUOUS_ROUTE with matching_route_ids — pass an explicit route_id rather than guessing. Synchronous: no task_id. Verify the open map legend no longer lists the route. Scenarios: RT-010.

NameTypeReqDescription
guidance_handle–––
map_session_id–––
route_idstringyes–
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

delete_tal ~261

[Tier 1 — Delete TAL] When: wipe one whole Territory Alignment Layer (user language: territory layer, alignment, all territories, active alignment — not only 'TAL') from the TS and open map (e.g. 'remove the territory layer', 'wipe all territories', 'remove the alignment', 'clear tal-tx-10t before rebuild'). Prerequisites: map_session_id for an open MC (preferred), else ts_handle; plus tal_id (or an exact unique TAL label). NOT for deleting one leaf territory — that is delete_territory. Do NOT N× delete_territory to wipe an alignment. Synchronous: no task_id / no Realign progress overlay. Points, part-layer overlays, and routes stay; active_tal_id becomes a remaining TAL, __points__, or __empty__. Already-absent returns ok with already_absent=true. Ambiguous label returns AMBIGUOUS_TAL. Next: verify the legend dropped the alignment, then auto_build / account_build / direct_build when rebuilding. Scenarios: HITL-057, T-134.

NameTypeReqDescription
guidance_handle–––
map_session_id–––
tal_idstringyes–
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

delete_territory ~419

[Tier 1 — Delete Territory] When: delete one leaf territory from an existing TAL (e.g. 'delete T1', 'remove territory West'). Prerequisites: ONE current TS reference — prefer map_session_id for an open MC, else ts_handle or ts; tal_id; territory_id (stable leaf id from created_territory.territory_id / leaf_territories preferred, or an exact unique display name — do not invent shorthand like T3 for Territory 3; ask if unclear). Do NOT invent part_ids or call auto_build. This tool collects the leaf's part_ids and runs Realign remove_parts + remove_empty_territories (same engine as RL-013). To wipe an entire TAL / alignment before rebuild, call delete_tal instead — never N× this tool. When a rep leaves and the neighbors should take over the territory, call territory_merge instead — this tool leaves the deleted territory's parts unassigned. Already-absent territories return ok with already_absent=true (no job). Next: follow the returned Tasks status operation until completed, call its result operation once, then verify the open map legend no longer lists the territory AND the territory fill/outline is gone from the canvas (not just the legend) before claiming success. Geography-only delete does not require Analyze. Scenarios: feedback delete-territory, RL-013 wrapper, T-087 last-leaf paint clear.

NameTypeReqDescription
expected_revision–––
guidance_handle–––
map_session_id–––
part_layer–––
repair_policystring–Topology repair for dissolved territories. default fills interior holes in the dissolved geometry (no part is added or reassigned; repair_summary.changed_part_ids lists the territories' own parts). r…
tal_idstringyes–
territory_idstringyes–
ts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

direct_build ~345

[Tier 1 — Known Assignments Builder] When: user has explicit part-to-territory assignments (spreadsheet, legacy file, hierarchical territory_path). assignments_handle must be a server upload handle (aup_...) from request_assignment_upload — csv_text/csv_file/assignments, or a POST of the CSV file to its key-less result.upload_url. Legacy spreadsheets (Postal Code + Territory/Region/Division) are auto-mapped when staged. Conflicting duplicate part_ids default to duplicate_part_policy=keep_first (first wins). Prerequisites: part_layer chosen; viewer connected for MC-first; ts/ts_handle optional. Not for account point locations—use ingest_accounts. Not for balanced partitioning—use auto_build. Not for attribute grouping—use account_build. Next: verify TAL in MC (MC-011), analyze + load_analysis_panel. Scenarios: DB-001..005, MC-011.

NameTypeReqDescription
assignments–––
assignments_handle–––
duplicate_part_policystring––
expected_revision–––
guidance_handle–––
map_session_id–––
missing_part_policystring––
part_layerstringyes–
repair_policystring–Topology repair for dissolved territories. default fills interior holes in the dissolved geometry (no part is added or reassigned; repair_summary.changed_part_ids lists the territories' own parts). r…
tal_id–––
tal_labelstringyes–
ts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

discover_intent ~435

[Tier 1 — Router] Deterministic entry point for ambiguous or open-ended territory requests. When: the user's goal or build type is unclear and you want the correct workflow before acting. Prerequisites: none (static keyword routing; no compute). Returns an intent_category, the recommended tool order, the Tier 1 tool + Tier 2 alternatives, required_inputs, clarifying_questions to ask when inputs are missing, a guidance_uri (ezt://guidance/workflows/{name}) for the full atom, and `guidance` — the same EMEP atom inlined as {uri, title, excerpt, truncated}, so you do NOT need a second resources/read to get the workflow text. Use it to disambiguate auto_build vs account_build vs direct_build and to route realign / restructure / analyze / delegation / geocode-ingest / load-part-layer-on-map (add zips, show zip codes) / route-stops (drive a list of stops in the best order) / reachable-area (a drive-time or drive-distance area around origins — service area, catchment, coverage, isochrone, which routes to isochrone_build) / periodic-scheduling (a recurring cadence — 'every 30 days', 'twice a month' — and which day each visit lands on, which routes to schedule_visits, never auto_build or cluster_points) / push-to-designer (an EasyTerritory Designer rolodex project from a TS: export_geojson then POST FromTerritorySolution to create or PUT .../Projects/{projectId}/... to update; territories, points, and routes import; ezt_pat_; there is no MCP push tool) / pull-from-designer (a Designer rolodex project into the MCP: GET REST/Agent/Projects then GET .../Projects/{projectId}/TerritorySolution with ezt_pat_, then import_geojson geojson_gzip; there is no MCP pull tool). Scenarios: AB-016, ACB-003, wrong-build-tool.

NameTypeReqDescription
context–––
user_requeststringyes–

Structured output declared, but exposes no named fields.

No examples provided.

ensure_map_viewer ~225

[Tier 1 — MC-First Gate] When: after get_map_visualization returns map_url and before any compute, build, analyze, or selection work with a human in the loop. Prerequisites: map_session_id from get_map_visualization. Next: ingest, configure_map, build, realign, or analyze once viewer_status.connected. Surface-agnostic: the in-chat MCP App shell connects the same session over the same SSE channel, so this gate works unchanged whether the human is looking at the in-chat map or the map_url tab. Do not skip it on an Apps host. wait_seconds blocks at most 30 s per call (larger values are clamped; the result reports requested_wait_seconds and max_wait_seconds). On VIEWER_NOT_CONNECTED, call again with the same map_session_id while the user opens map_url. Scenarios: MV-001, I-1.

NameTypeReqDescription
guidance_handle–––
map_session_idstringyes–
poll_interval_msinteger––
wait_secondsnumber––

Structured output declared, but exposes no named fields.

No examples provided.

ep_graph_traverse ~85

[Knowledge Retrieval] Traverse the EMEP knowledge graph from a topic file (e.g. 'workflows/realign-by-selection.md') to find related guidance, up to `depth` hops. Returns no edges unless the pack ships a _graph.yaml.

NameTypeReqDescription
depthinteger––
edge_kinds–––
file_pathstringyes–

Structured output declared, but exposes no named fields.

No examples provided.

ep_list_topics ~59

[Knowledge Retrieval] List EMEP topics grouped by type (concept, workflow, interface, troubleshooting, decision). Use to discover what guidance exists before ep_search, or to browse the pack. Optional `type` filter.

NameTypeReqDescription
type–––

Structured output declared, but exposes no named fields.

No examples provided.

ep_search ~147

[Knowledge Retrieval] Semantic search over the EZT MCP Expert Pack (EMEP) for targeted workflow guidance, concepts, interfaces, and common mistakes. When: you are unsure which tool or order to use, hit an error, or need product-specific domain context before acting. Returns ranked markdown chunks with source files; atoms pulled in via `requires` are flagged requires_expanded. Degrades to the ezt://guidance/... resources if retrieval is unavailable. Examples: 'build balanced territories from accounts', 'viewer not connected before compute', 'auto_build vs account_build'.

NameTypeReqDescription
max_resultsinteger––
querystringyes–
tags–––
type–––

Structured output declared, but exposes no named fields.

No examples provided.

export_geojson ~368

[Tier 2 — Project save] The only Territory Solution export. Materialize the working GeoJSON FeatureCollection (territory polygons with part_ids, point features, and route paths + numbered stops). Omit tal_ids / point_layers / route_layers for the full project. Async: returns task_id; follow its Tasks next_action/sleep_ms until completed, then fetch the result once. The result carries geojson_artifact {artifact_id, bytes}, zip (default true = gzip download), and download_url (GET with Bearer API key) — never an inline multi-MB body. Set zip=false for uncompressed GeoJSON. Prerequisites: ts_handle, completed build job_id, or map_session_id. Set include_points=false or include_routes=false to drop a family. Reopen with import_geojson, then get_map_visualization(ts_handle=...). Paint travels with the export: every feature and point_layers[] / route_layers[] entry carries style {color, opacity, size, shape, weight} exactly as shown, so reopen and Designer import need no restyling. An EasyTerritory Designer rolodex project is this download POSTed to Designer REST/Agent/Projects/FromTerritorySolution (new) or PUT to .../Projects/{projectId}/FromTerritorySolution (update). Territories, points, and routes import. There is no MCP push tool (ezt://guidance/workflows/push-to-designer).

NameTypeReqDescription
guidance_handle–––
include_pointsboolean––
include_routesboolean––
job_id–––
map_session_id–––
point_layers–––
route_layers–––
tal_ids–––
ts_handle–––
zipboolean––

Structured output declared, but exposes no named fields.

No examples provided.

extract_tal_branch ~157

[Tier 1 — Delegation Extract] When: senior planner sends a regional subtree to a delegate for bounded editing. Prerequisites: master TS with hierarchical TAL; branch rollup or path identified. Next: store branch extract + branch_metadata; delegate opens MC on extract only. Scenarios: DL-001, DL-002.

NameTypeReqDescription
branch_rollup_territory_id–––
branch_territory_path–––
delegate_ref–––
exclude_lockedboolean––
expected_content_hash–––
expected_revision–––
guidance_handle–––
map_session_id–––
tal_idstringyes–
ts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

ezt ~258

[Tier 1 — Plain-language orchestrator] Use when the exact granular tool is unclear or when a greedy/file-holding client wants to complete an action in one step. Prefer granular tools directly when you know the step. Pass request (your goal) plus optional csv_file / accounts_handle / assignments_handle / map_session_id / ts_handle. For an uploaded CSV, pass csv_file as the ChatGPT/OpenAI file parameter; ezt parses/stages it server-side and can run ingest_accounts with map_session_id so points appear on the open map. For fixed-workload builds, args.target_hours / args.workload_target are normalized to auto_build build_mode.mode=fixed_workload_target. Modern form-capable clients (protocol >= 2026-07-28) may answer missing part_layer, tal_label, sizing, dwell, and optional balance in-band (aligned with auto_build); legacy hosts keep CLARIFICATION_REQUIRED / ask_user (HITL-025).

NameTypeReqDescription
accounts_handle–––
args–––
assignments_handle–––
csv_file–––
guidance_handle–––
map_session_id–––
requeststringyes–
state_facts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

geocode_address ~326

[Tier 1 — Geocode Only] When: geocode addresses without full account ingest, or headless bulk geocode (GC-001). Prerequisites: none for headless; ts_handle + MC-first when human verifies on map. Prefer ingest_accounts for territory builds (it geocodes inline with accept_suboptimal_geocodes default true). Use this tool when the user must verify geocode quality first; set accept_suboptimal_geocodes=true to accept ZIP-centroid/suboptimal matches. Address columns: address/address_line1/street, city, state, postal (CRM headers auto-mapped). QUOTA: billable provider calls are capped per API key per calendar month. Cache hits cost nothing and are never counted, so never set use_cache=false or force_regeocode=true to work around a cap — that turns free hits into paid calls. Past the cap the tool returns PROVIDER_QUOTA_EXCEEDED carrying limit, used, remaining, and period_resets_at; an operator must raise the cap, so report those numbers instead of retrying or splitting the batch. Next: pass result.geocoded_rows to ingest_accounts or export point layer. Scenarios: GC-001..006.

NameTypeReqDescription
accept_suboptimal_geocodesboolean––
country_hint–––
force_regeocodeboolean––
guidance_handle–––
map_session_id–––
min_confidencenumber––
region_hint–––
rowsarrayyes–
use_cacheboolean––

Structured output declared, but exposes no named fields.

No examples provided.

get_guidance ~191

[Tier 1 — Startup Guide + Handle] CALL THIS FIRST. Read-only. When: session start, after blocked_by=guidance_required, or when the shared rules are unclear. Returns result.text (the short cross-tool brief, same text as server instructions), result.guidance_handle (the rotating code every territory/map tool requires), result.server_version (this server's product version; the same string as serverInfo.version), and result.seat (plan standard|trial, key_expires_at, and quota_remaining for geocode/route/isochrone — tell a trial user when the trial or an allowance is close to running out). Per-tool rules are on that tool's description. Workflow essays are inlined as guidance on discover_intent, workflow_advisor, and blocked_by. Exempt: get_guidance, submit_feedback, discover_intent, workflow_advisor, ep_* tools.

Input schema present but exposes no named parameters.

Structured output declared, but exposes no named fields.

No examples provided.

get_map_selection ~240

[Tier 2 — MC Selection Poll] When: read the latest committed MC session selection — especially when Monica started selection from the legend finger icon and then tells the agent what to do with 'my selection' (no prior request_part_selection in this turn). Prerequisites: map_session_id of the open MC. Returns part_layer + part_ids (+ selection_task_id when a first-class task was created). Prefer get_part_selection when you already have selection_task_id and it is still available. Next for 'add these to <territory>': call realign with tal_id, the same map_session_id, and moves=[{part_id, to_territory_id}] derived from every returned part_id using the stable leaf territory_id (created_territory.territory_id / leaf catalog). Display-name aliases need an exact unique name match — do not invent shorthand (T3 ≠ Territory 3). If unclear, ask which leaf. Do not resend the TS or request a new selection. Scenarios: MC-004 variants, user-initiated select.

NameTypeReqDescription
guidance_handle–––
map_session_idstringyes–

Structured output declared, but exposes no named fields.

No examples provided.

get_map_visualization ~310

[Tier 1 — MC-First Entry] FIRST step of non-headless territory work (invariant I-1). When: open a blank map for planning, or open/reuse the user's Map Component for an existing Territory Solution (TS), ts_handle, or completed job. Pass new_project=true to replace the live workspace with an empty project; omitted empty+view reuses the existing project. Optional presentation.view_name: empty | points_only | review | selection (defaults from mode/TS content). Diagnostics: presentation.debug_panel=true. Prerequisites: none (idempotent per user_id). Next: hand user map_url, then ensure_map_viewer until viewer_status.connected. Dual surface (same map_session_id, one map): Apps-capable hosts render this map in chat from ui://easyterritory/map-viewer (_meta.ui.resourceUri); every other client — including Cursor — opens map_url in a browser tab. map_url is always returned. Do not open a second surface or call this tool again to 'fix' a map. Scenarios: MC-000, MC-001, MV-001, S004.

NameTypeReqDescription
active_tal_id–––
expiry_seconds–––
guidance_handle–––
interaction_flags–––
job_id–––
modestring––
new_projectboolean––
presentation–––
ts–––
ts_handle–––
user_id–––

Structured output declared, but exposes no named fields.

No examples provided.

get_part_selection ~208

[Tier 2 — Selection Poll] When: poll or retrieve committed part IDs after request_part_selection OR after Monica starts selection from the MC legend finger icon. Prerequisites: selection_task_id from request_part_selection or from map session state (active_selection_task_id on ezt://map-sessions/{id}/state). Poll loop: while status=awaiting_user_selection, sleep recommended_poll_delay_ms (fallback poll_interval_ms, min 250ms) and poll again until status=committed, expired, or cancelled. Response includes do_this_next and poll_loop while awaiting. If the user already committed and says 'add my selection to …', call once for the committed task (or use get_map_selection) and proceed — do not start a new selection. Next: realign, create_territory_from_parts, or analyze scoped to selection.part_ids. Scenarios: AN-007, RL-008.

NameTypeReqDescription
guidance_handle–––
selection_task_idstringyes–

Structured output declared, but exposes no named fields.

No examples provided.

import_geojson ~288

[Tier 2 — Project reopen] Import a GeoJSON FeatureCollection (standard points or an export_geojson artifact, including gzip/zip). Returns ts_handle + summary — pass ts_handle to get_map_visualization / analyze / export_geojson next; do not repost the GeoJSON body. Arbitrary territory polygons WITHOUT part_ids are rejected (TERRITORY_POLYGONS_WITHOUT_PART_IDS) unless you explicitly pass part_layer plus overlay_policy="centroid_within" to assign parts whose centroids fall inside each polygon. Optional: point_layer (name for imported points), tal_label. Supply geojson (object), geojson_text (JSON or sniffed gzip/zip), or geojson_gzip (base64 gzip/zip). An EasyTerritory Designer rolodex project arrives here too: GET Designer REST/Agent/Projects (list) then GET .../Projects/{projectId}/TerritorySolution with the user's ezt_pat_ Bearer, and pass the (gzipped) file as geojson_gzip. There is no MCP pull tool (ezt://guidance/workflows/pull-from-designer).

NameTypeReqDescription
geojson–––
geojson_gzip–––
geojson_text–––
guidance_handle–––
overlay_policy–––
part_layer–––
point_layer–––
tal_label–––

Structured output declared, but exposes no named fields.

No examples provided.

ingest_accounts ~1,284

[Tier 1 — Data Intake] When: load/add account/location rows or account CSV point data into a TS point layer. ALWAYS before account-derived builds (auto_build, account_build). Prerequisites: MC-first + viewer connected when human verifies points; ts/ts_handle optional. Geocodes rows lacking valid coordinates (accept_suboptimal_geocodes defaults true for bulk address-only CSVs). Recognized address columns: address/address_line1/street, city, state, postal columns, plus common CRM headers (e.g. Address 1: Street 1). Coordinate passthrough accepts case-insensitive GIS headers latitude/lat/LAT and longitude/lon/lng/long/LON (no rename required); pass explicit latitude_field/longitude_field for other headers (e.g. Address 1: Latitude). If unused numeric lat/lon-like columns exist and ingest would otherwise bulk-geocode, the job fails fast with CLARIFICATION_REQUIRED / blocked_by=needs_coordinate_fields — set latitude_field/longitude_field or force_regeocode=true; never wait on a national geocode crawl. After submit, if the first Tasks status shows coordinate_passthrough_count=0 with a large geocode_query_count on a file that had coord-like columns, call tasks/cancel or tasks_cancel and fix headers/fields. id_field must be a UNIQUE business key (default row_id). Never use label/name columns — duplicates fail with blocked_by=needs_unique_row_id. If no unique column exists, omit id_field (server synthesizes row-1, row-2, … when row_id is absent) or synthesize a unique row_id client-side before staging. Before this call, inspect headers/samples for metric, dwell-time, and visit-frequency columns. Pass confirmed business metrics as metric_fields and confirmed workload roles as workload_fields plus visit_frequency_field/dwell_time_field so downstream tools can reuse point-layer metadata. If no visit-frequency column exists, omit visit_frequency_field; do not ask for an average/default frequency. DECLARED FIELDS ARE THE RETENTION CONTRACT: the TS keeps only id, coordinates, lab…

NameTypeReqDescription
accept_suboptimal_geocodesboolean––
accounts_handle–––
country_hint–––
display_fields–––
dwell_time_field–––
force_regeocodeboolean––
grouping_fields–––
guidance_handle–––
id_fieldstring––
labelstring––
label_fieldstring––
latitude_fieldstring––
longitude_fieldstring––
map_session_id–––
metric_fields–––
min_confidencenumber––
point_layerstring––
region_hint–––
rows–––
search_fields–––
ts–––
ts_handle–––
use_cacheboolean––
visit_frequency_field–––
workload_fields–––

Structured output declared, but exposes no named fields.

No examples provided.

isochrone_build ~836

[Tier 1 — Isochrone Build] When: draw the area reachable by DRIVING from one or more origins within a time or distance budget — '20-minute drive-time area around each branch', service area, catchment, coverage ring, reachable range, isochrone, isodistance (IS-001..IS-006). It draws reachable area. It has no objective and does not balance workload. Prerequisites: a TomTom or Azure Maps key on the server (no key → ISOCHRONE_NOT_CONFIGURED, no degraded mode — never substitute a straight-line radius); and, for point-layer origins, ingested points plus ts_handle or map_session_id. Inline origins need no TS. No part layer is involved. ORIGINS x BANDS: origins are inline {latitude, longitude, label?} or a point-layer reference {point_layer, point_ids?, filter?, label_field?} — '40 minutes around each of my 6 branches' is ONE call. bands are [{time_budget_seconds} | {distance_budget_meters}], one budget per band, and every band in a call must use the SAME unit (mixing returns MIXED_BUDGET_TYPES). One band → one leaf per origin; several bands → a rollup per origin with one leaf per band. Cost is origins x bands provider calls, capped by TOO_MANY_ORIGINS (default 25) / TOO_MANY_BANDS (default 5). QUOTA: those billable calls also draw on a per-API-key monthly cap. The whole fan-out is claimed before any call goes out, so a build that does not fit returns PROVIDER_QUOTA_EXCEEDED with limit, used, remaining, and period_resets_at having spent nothing. An operator must raise the cap; report those numbers instead of retrying with fewer bands. LIMITS: travel_mode is 'car' or 'truck' ONLY — neither provider offers a walking or cycling reachable range, unlike calculate_route. time_budget_seconds <= 21600, distance_budget_meters <= 500000 (BUDGET_OUT_OF_RANGE). depart_at is supported; arrive_at is not. avoid accepts toll_roads, motorways, ferries, unpaved_roads, carpools, border_crossings, tunnels, car_trains, low_emission_zones. GEOMETRY: each territory IS the provider's exact polygo…

NameTypeReqDescription
avoid–––
bandsarrayyes–
depart_at–––
guidance_handle–––
map_session_id–––
originsarrayyes–
route_typestring––
tal_id–––
tal_label–––
trafficboolean––
travel_modestring––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

load_analysis_panel ~338

[Tier 2 — Analysis Panel Display] When: show Analyze JSON in the MC bottom dock (single or comparison) after a completed analyze that omitted analysis_panel. Prefer analyze(analysis_panel=single, map_session_id=...) so the dock fills without this second call. Prerequisites: map_session_id; a full Analyze result — pass task_id/job_id of the completed analyze job, or analyses=[<full Analyze result>]. The result must include tal_analyses and ts_identity (territory_metric_grids when metrics exist). A thin {tal_analyses} object is INVALID_REQUEST, not an empty dock. presentation_mode is single|compare|executive|diagnostic — territory_metric_grid is default_presentation.view inside the Analyze payload, not a presentation_mode. Does not mutate TS. Re-run analyze after any TAL or point change (I-2). dismiss=true hides the whole dock, header bar included, and keeps the stats on the session. analysis_panel.dismissed is then true. A later analyze with analysis_panel=single shows the dock again. Omit analyses on a dismiss call. Dual surface: the dock renders in the in-chat map on Apps-capable hosts and in the map_url tab everywhere else — same map_session_id, no extra call. Scenarios: MC-009, AN-006, MC-007.

NameTypeReqDescription
analyses–––
dismissboolean––
guidance_handle–––
job_id–––
labels–––
map_session_idstringyes–
presentation_mode–––
roles–––
task_id–––

Structured output declared, but exposes no named fields.

No examples provided.

query_parts ~164

[Tier 2 — Part Metadata] When: enrich or filter parts before build, or inspect attributes without geometry. Prerequisites: part_layer from ezt://part-layers. Pass exactly one of filter (e.g. {state_abbr: TX}) or part_ids; neither or both is INVALID_REQUEST. To check that a part layer exists, read ezt://part-layers instead of probing with an empty query. Next: direct_build, configure_map, or agent-side join before build. Scenarios: DS-002. Returns part_id and attributes only; no geometry.

NameTypeReqDescription
filter–––
guidance_handle–––
max_resultsinteger––
page_token–––
part_ids–––
part_layerstringyes–

Structured output declared, but exposes no named fields.

No examples provided.

realign ~540

[Tier 1 — Realign] When: move parts between leaf territories within ONE TAL. Prerequisites: existing TAL plus ONE current TS reference: map_session_id (preferred for an open MC), ts_handle, or ts; expected_revision is optional optimistic concurrency (STALE_TS_REVISION → reload and retry). For a committed ad-hoc map selection, call get_map_selection(map_session_id), then pass moves=[{part_id, to_territory_id}] for each returned selection.part_ids plus tal_id and the same map_session_id. Do not repost the full TS and do not start another selection. to_territory_id must be a leaf territory_id (prefer created_territory.territory_id / leaf_territories / legend catalog). A display-name alias is accepted only as an exact unique match to the leaf's actual name (e.g. 'Territory 3' or 'T1' when that is the name) — do NOT invent shorthand expansions (T3 ≠ Territory 3; no T→Territory mapping). It is NOT tal_id. On UNKNOWN_TERRITORY_ID / AMBIGUOUS_TERRITORY read error.details.available_leaf_territories and stop guessing; if the spoken destination is still unclear, ask the user which leaf (id or exact name). Visual moves with a destination known in advance: request_part_selection with purpose=realign. Structural rebalance: territory_split/merge/rebalance. Next: verify the live map refresh. Run analyze + load_analysis_panel only when the TS has a point layer (I-2). For a geography-only ZIP/part edit, skip analyze unless the user requested AN-004; do not create a NO_POINT_LAYER failure after a successful edit. Full atom: ezt://guidance/workflows/realign-by-selection. Scenarios: RL-001..013, S001, MC-004, EV-001.

NameTypeReqDescription
expected_revision–––
guidance_handle–––
map_session_id–––
moves–––
part_ids–––
part_layer–––
realign_operation–––
remove_empty_territoriesboolean––
repair_policystring–Topology repair for dissolved territories. default fills interior holes in the dissolved geometry (no part is added or reassigned; repair_summary.changed_part_ids lists the territories' own parts). r…
tal_idstringyes–
ts–––
ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

reintegrate_branch ~155

[Tier 1 — Delegation Reintegrate] When: merge an approved proposal TS into master. Prerequisites: branch_metadata, expected_master_revision; proposal TS at current lineage. STALE_TS_REVISION if master moved—request fresh extract. Sequential merges only. Next: refresh master Analysis panel (I-2). Scenarios: DL-003, DL-004, DL-006.

NameTypeReqDescription
branch_metadataobjectyes–
expected_master_content_hash–––
expected_master_revisionintegeryes–
guidance_handle–––
map_session_id–––
master_ts–––
master_ts_handle–––
proposal_ts–––
proposal_ts_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

request_account_upload ~714

[Tier 2 — Data Intake helper] When: you have account/location rows or an account CSV that you cannot inline in a single ingest_accounts call (e.g. a large CSV, hundreds/thousands of rows). Stage the rows here in one or more chunks, then call ingest_accounts(accounts_handle=...). If the file includes metric, workload, visit-frequency, or dwell-time fields, stage the file here first, inspect returned csv_headers / row keys, confirm role candidates, then pass metric_fields/workload_fields/visit_frequency_field/dwell_time_field to ingest_accounts. Continue only after ingest_accounts has loaded the points. WAYS TO STAGE (all return an upload_handle): (A) CSV on disk + a shell with network (Cursor, Claude Code, Codex, CLI agents): call with no rows to get result.upload_url, then run result.curl_example — POST the raw file with Content-Type: text/csv. No API key: upload_url is the credential (expires in 15 min; each POST appends to the same handle). Fastest for large files; do not re-type rows into csv_text or rows chunks. (B) MCP csv_file: pass the uploaded CSV as a ChatGPT/OpenAI file parameter when available. (C) MCP csv_text: pass csv_text=<raw CSV string> (whole file in one call, up to 16 MB) when you have no shell or no network. Preserve multiline newlines — do NOT JSON-encode with PowerShell ConvertTo-Json (that corrupts rows into a single line). Use Python json.dumps or MCP csv_file instead. (D) MCP rows: call with rows=<chunk>; append more with upload_handle=<prior handle>. A local path in csv_file fails (UNREADABLE_FILE_REFERENCE); use (A). Every result carries a fresh upload_url for its handle; an expired URL returns UPLOAD_TOKEN_EXPIRED — call again with upload_handle for a new one. Then: ingest_accounts(accounts_handle=<upload_handle>, map_session_id=<MC session id>, label_field=<label field>). GIS coordinate headers latitude/lat/LAT and longitude/lon/lng/long/LON passthrough case-insensitively. CRM headers such as Address 1: Latitude and Address 1: Longitude…

NameTypeReqDescription
csv_file–––
csv_text–––
guidance_handle–––
rows–––
ttl_seconds–––
upload_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

request_assignment_upload ~332

[Tier 2 — Direct Build intake] When: you have part-to-territory assignment rows or a legacy spreadsheet (e.g. Zip2Terr.csv with Postal Code + Territory/Region/Division) that you cannot inline in direct_build. Stage rows here, then call direct_build(assignments_handle=<upload_handle>). WAYS TO STAGE (all return upload_handle): (A) CSV on disk + a shell with network: call with no rows to get result.upload_url, then run result.curl_example — POST the raw file with Content-Type: text/csv. No API key: upload_url is the credential (expires in 15 min; each POST appends). (B) MCP csv_file: pass the uploaded CSV as a ChatGPT/OpenAI file parameter. (C) MCP csv_text: pass csv_text=<raw multiline CSV> — preserve newlines; do NOT JSON-encode with PowerShell ConvertTo-Json (corrupts rows). (D) MCP assignments: pass assignments=<chunk of row objects>; append with upload_handle. An expired upload_url returns UPLOAD_TOKEN_EXPIRED — call again with upload_handle. Legacy columns (Postal Code, Territory, Region, Division) auto-map to part_id + territory_path. Then: direct_build(assignments_handle=<handle>, part_layer=..., tal_label=..., map_session_id=...). Handle is single-use and expires (default 1h).

NameTypeReqDescription
assignments–––
csv_file–––
csv_text–––
guidance_handle–––
ttl_seconds–––
upload_handle–––

Structured output declared, but exposes no named fields.

No examples provided.

request_part_selection ~366

[Tier 2 — Human Spatial Input] When: Monica selects parts on the map for realign, manual territory build, or return_list. Prerequisites: MC-first + viewer connected; part_layer; active TAL when realigning. Poll loop: after submit, poll get_part_selection(selection_task_id) using recommended_poll_delay_ms from the response (or scripts/wait_part_selection.py) until status=committed — never ask the human to type committed/done/go. User-initiated path: Monica may also start select mode from the MC legend finger icon on a part-layer row (no prior request_part_selection). When the user refers to 'my selection' / 'the parts I selected', read the open map session's latest committed selection via get_map_selection(map_session_id) or get_part_selection using active_selection_task_id from ezt://map-sessions/{id}/state — do not ask them to select again. Next: realign, create_territory_from_parts, or analyze with selection.part_ids. Dual surface: in an Apps-capable host the human selects on the in-chat map (ui://easyterritory/map-viewer); otherwise they select in the map_url tab. The commit poll loop above is identical on both surfaces. Scenarios: S001, MC-004..006, RL-006..013.

NameTypeReqDescription
active_tal_id–––
destination_territory_id–––
expiry_seconds–––
guidance_handle–––
new_territory–––
part_layerstringyes–
prompt–––
purposestring––
realign_operation–––
remove_empty_territoriesboolean––
ts–––
user_id–––

Structured output declared, but exposes no named fields.

No examples provided.

schedule_visits ~605

[Tier 1 — Periodic Scheduling] When: accounts carry a recurring cadence (every 7 days, twice a month) and the user asks which day each visit happens. Expands demand across a repeating horizon and packs it into daily work clusters (buckets) under one technician-day workload cap. This tool decides the day. Neighbors: auto_build, cluster_points, calculate_route. When the user said route and a visit-frequency column exists, confirm they want a schedule, not calculate_route, before calling. It creates no TAL and assigns no technician. Prerequisite: ingest_accounts completed for point_layer with the cadence column declared. Omit ts and ts_handle when the session id argument is already set. That session is the TS. An undeclared column fails with UNDECLARED_FIELD. Required: point_layer, visit_frequency_field, dwell_time, daily_capacity. Ask the user for dwell and the daily cap; never invent them. frequency_unit=interval_days means the value is the maximum days between visits (so a 3-day cadence in a 14-day horizon is 5 visits, not 4); visits_per_horizon means the count across the horizon. Values in never_visit_values (default 0, null, empty) are excluded and reported in excluded_accounts, never silently dropped. Example — weekly and biweekly accounts across 8-hour technician days: point_layer=accounts, visit_frequency_field=service_interval_days, dwell_time={type: scalar, value: 45, unit: minutes}, daily_capacity={mode: not_to_exceed, hours: 8}, max_buckets_per_day=3. bucket_workload_hours is in-bucket drive plus dwell with NO visit-frequency multiplier: it is neither territory workload nor route_workload_hours — never sum or compare them. Re-running with the same visit_layer_name replaces that schedule in place; a different name adds a second one for comparison. After submission, follow do_this_next with the returned task_id: sleep exactly sleep_ms while next_action=sleep_and_poll, fetch the result once on consume_result, and stop on stop_error. Next: calculate_route over…

NameTypeReqDescription
cadence_flexibility_pct–––
daily_capacity–––
dwell_time–––
emit_visit_layerboolean––
expected_revision–––
frequency_unitstring––
guidance_handle–––
horizon–––
map_session_id–––
max_buckets_per_day–––
never_visit_values–––
objective–––
point_layerstringyes–
schedule_label–––
ts–––
ts_handle–––
visit_frequency_fieldstringyes–
visit_layer_name–––

Structured output declared, but exposes no named fields.

No examples provided.

seed_build ~833

[Tier 1 — Seed Build] When: grow ONE territory outward from a seed location until it holds a target number of locations or a target metric sum — 'a franchise territory around this address with 40 stores', 'grow from this point until it reaches $2M revenue', 'the ZIPs around our new branch that cover 300 stores'. The result is an ordinary part-based territory (ZIPs, counties) appended as a new leaf on an existing layer (tal_id) or as a new layer when tal_id is omitted. It grows one territory from one seed. It does not partition, balance, or route. Prerequisites: an ingested point layer (ingest_accounts) — its locations are the values counted or summed; a part_layer (ezt://part-layers); and the seed as {longitude, latitude}. Resolve an address or POI to coordinates first with the address geocoding tool; a map click already gives coordinates. TARGET: target={type: 'location_count', value: N} or {type: 'metric_sum', field: <column declared in metric_fields at ingest>, value: X}. An undeclared field returns UNDECLARED_FIELD — re-ingest with metric_fields. Fit is CLOSEST: growth adds the nearest adjacent part that still fits, then takes the smallest remaining neighbour only when overshooting lands nearer the target than stopping short. target_status reports reached | closest_under | closest_over | frontier_exhausted | max_parts_reached; a closest fit that misses the target also warns SEED_TARGET_UNDERSHOT / SEED_TARGET_OVERSHOT with the signed difference — tell the user, parts are indivisible. NO OVERLAP, EVER: with tal_id, parts already in any territory of that layer are never taken — the new territory drifts away from them instead (blocked_part_count, seed_offset_km). A seed inside an existing territory fails SEED_PART_ASSIGNED; pick another seed or reassign parts with realign. There is no allow_overlap flag. SCOPE: growth reads only the seed's neighbourhood — the point layer is indexed once and parts are materialised ring by ring outward from the seed part; it never j…

NameTypeReqDescription
guidance_handle–––
map_session_id–––
max_parts–––
part_filter–––
part_ids–––
part_layer–––
part_scope–––
point_layer–––
seedobjectyes–
tal_id–––
tal_label–––
targetobjectyes–
territory_name–––
ts_handle–––
user_id–––

Structured output declared, but exposes no named fields.

No examples provided.

set_map_state ~329

[Tier 2 — Low-Level MC State] When: switch MC mode, active TAL, or pending job ref, or jump the open MC camera with center ([longitude, latitude]) and/or zoom (0-24). Camera here is session-only and does not write the TS — use configure_map to persist a default view. Prerequisites: map_session_id. Prefer configure_map for durable TS map_config. Prefer request_part_selection for selection workflows. The result's render_ack is read the instant the change is published, so state=sent_unconfirmed with applied_render_version one behind is normal; to confirm the paint, read ezt://map-sessions/{map_session_id}/state a second or two later. Only a sent_unconfirmed that persists with a render_ack failure detail means the viewer could not apply it; render_ack_hint says which case applies (reread_state or resend). Once you set center/zoom, the open MC keeps that view (no automatic refit) and a reload of map_url reopens there. Every result carries camera {center, zoom, source}: requested (this call), session (an earlier set_map_state), map_config (the TS default view), or viewer_current (no camera known; the MC keeps its view — switching active_tal_id never refits). Scenarios: residual backlog (no dedicated scenario by design).

NameTypeReqDescription
active_tal_id–––
center–––
guidance_handle–––
map_session_idstringyes–
mode–––
pending_job_reference–––
zoom–––

Structured output declared, but exposes no named fields.

No examples provided.

show_map_overlay ~726

[Tier 1 — Map Overlay] When: customer wants something on the map — US ZIP codes, counties, accounts/points, or a territory alignment — in any phrasing ('add US zip codes to the map', 'show zip codes', 'add zips'). Prerequisites: ts_handle (or inline ts) from get_map_visualization; viewer connected for live MC refresh. Pass user_request alone (e.g. 'add US zip codes to the map') or overlay_kind (part_layer | point_layer | tal | route) with optional overlay_id. Resolves the four MC overlay families and calls the correct underlying step (configure_map for part layers and active TAL; point layers must already be in the TS from ingest_accounts). Source the TS via ts_handle, inline ts, OR map_session_id (preferred for points: reads the LIVE session TS so points pushed by ingest_accounts(map_session_id=...) are found without threading a new ts_handle). Returns overlay_kind, overlay_id, viewer_hint, and for part layers a visibility block (state, min_zoom, camera_action). An open map_session_id zooms the MC to min_zoom (camera_action=fit_to_visible). When the user already named a center and zoom, do_this_next.tool is configure_map: call it once with that center and zoom before ingest or a point classification, so the fit does not replace it. Skip that call when no center was named, and do not invent one. Do not call configure_map again unless a later result also reports camera_action=fit_to_visible. Do not use ezt_test/focusAt. POINT LAYERS with map_session_id: status=already_on_map is verified against the live session render payload; when the layer is in the TS but missing from the session, the tool pushes a refresh and returns status=refreshed with a map_refresh block — check its render_ack before claiming points are visible. PART LAYERS are never loaded by a build; they show only when asked. 'Hide/remove the zips' returns status=hidden and takes that layer off the map (territories unchanged). ROUTE overlay (overlay_kind=route) needs map_session_id and only re-shows or hi…

NameTypeReqDescription
expected_content_hash–––
expected_revision–––
guidance_handle–––
map_session_id–––
merge_strategy–––
overlay_id–––
overlay_kind–––
route_id–––
ts–––
ts_handle–––
user_request–––

Structured output declared, but exposes no named fields.

No examples provided.

Common questions

What is the EasyTerritory MCP server?

EasyTerritory MCP is listed in the public MCP registry as ai.easyterritory/ezt-mcp. Build, balance, realign and analyze sales/service territories; geocode, route, schedule, live map. This page covers its hosted endpoint (https://mcp.easyterritory.ai/).

Is the EasyTerritory MCP server safe to use?

EasyTerritory MCP scores 76 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the EasyTerritory MCP server expose?

EasyTerritory MCP exposes 47 tools: get_map_visualization, get_guidance, discover_intent, workflow_advisor, ep_search, and 42 more. Their descriptions and schemas cost roughly 20,266 tokens of context every time the server is loaded.

Does the EasyTerritory MCP server require authentication?

Yes. EasyTerritory MCP asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

Is the EasyTerritory MCP server still maintained?

EasyTerritory MCP is still listed as active in the MCP registry. We last reached this channel on 7 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.