# EasyTerritory MCP (remote · mcp.easyterritory.ai)

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

- Trust score: 76/100 (medium)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-07

## Components

- remote · `mcp.easyterritory.ai`: 76/100 (this document), [markdown](https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp.md), [page](https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp)

## Channel facts

- Endpoint: `https://mcp.easyterritory.ai/`
- Transports: `streamable-http`
- Auth: `required`
- Version: `0.1.0`

## Trust breakdown

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. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-07.

- **Endpoint Security**: 89/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server offers only Dynamic Client Registration (RFC 7591), which MCP 2026-07-28 deprecated in favour of Client ID Metadata Documents.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 69/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - 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.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 26/100
  - Stability check failed: schema churn in the 8 days we've observed: 0 tool removals, 1 breaking changes, 0 auth/transport breaks, 0 additions.
- **Tool Coverage**: 72/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 2% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 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.
  - An AI judge read all 49 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).
  - Supports UI / widget rendering.

## 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.

### Claude

```bash
claude mcp add --transport http ai-easyterritory-ezt-mcp 'https://mcp.easyterritory.ai/'
```

### Cursor

```json
{
  "mcpServers": {
    "ai-easyterritory-ezt-mcp": {
      "url": "https://mcp.easyterritory.ai/"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "ai-easyterritory-ezt-mcp": {
      "type": "http",
      "url": "https://mcp.easyterritory.ai/"
    }
  }
}
```

### Codex

```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
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ai-easyterritory-ezt-mcp --url 'https://mcp.easyterritory.ai/' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  ai-easyterritory-ezt-mcp:
    url: "https://mcp.easyterritory.ai/"
```

### Netclaw

```json
{
  "McpServers": {
    "ai-easyterritory-ezt-mcp": {
      "Transport": "http",
      "Url": "https://mcp.easyterritory.ai/"
    }
  }
}
```

### Vellum

```bash
assistant mcp add ai-easyterritory-ezt-mcp -t streamable-http -u 'https://mcp.easyterritory.ai/'
```

### Other

```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 recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-07 (score 76, +1)

- [security regression] 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

### 2026-10-04 (score 75, +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.

### 2026-10-02 (score 74, +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.

### 2026-09-30 (score 73, +1)

- [functional improvement] Stability: unverified → 0.03

### 2026-09-29 (score 72)

First indexed and scored.

## MCP tools (47)

### `get_map_visualization` (~310 tokens)

Open Map

[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.

Input parameters:

- `active_tal_id`
- `expiry_seconds`
- `guidance_handle`
- `interaction_flags`
- `job_id`
- `mode` (string)
- `new_project` (boolean)
- `presentation`
- `ts`
- `ts_handle`
- `user_id`

### `get_guidance` (~191 tokens)

Get Startup Guidance

[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.

### `discover_intent` (~435 tokens)

Discover Workflow Intent

[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.

Input parameters:

- `context`
- `user_request` (string, required)

### `workflow_advisor` (~602 tokens)

Get Next Workflow Step

[Tier 1 — Workflow Advisor] Deterministic read-only next-action advisor for multi-step workflows. When: you know the intent (use discover_intent first if not) and want the validated next tool call instead of guessing the order. Prerequisites: none (static state machine; executes nothing). Pass intent_category (builds: build_from_accounts | account_grouping | known_assignments; edits: realign_existing | restructure; map overlay: load_part_layer for add/show ZIP or part layer; routing: route_stops for driving a known list of stops; reachable areas: reachable_area for a drive-time or drive-distance area around origins, with isochrone_build accepted as an alias; scheduling: periodic_scheduling for a recurring cadence, with schedule_visits accepted as an alias), agent-supplied state (viewer_connected, point_layer, part_layer, tal_present, analysis_fresh; realign adds selection_requested/selection_committed/realign_applied; restructure adds source_tal_id), and optional inputs (builds: part_layer, territory_count, grouping_field, assignments_handle, tal_label; realign: tal_id, moves or realign_operation+part_ids, to_territory_id, analysis_requested; restructure: operation=split|merge|rebalance, source_tal_id, target_territory_id, territory_id_a/territory_id_b; load_part_layer: user_request for ZIP inference; route_stops: route_type=circuit|tour|open_tour, start, stop_sets, end for tour, stops_need_ingest when the stops are not in the TS yet; reachable_area: origins, bands, part_layer, travel_mode=car|truck, origins_need_ingest when the origins are not in the TS yet — the advisor never invents a budget; periodic_scheduling: visit_frequency_field, frequency_unit, dwell_time or dwell_minutes/dwell_hours, daily_capacity or daily_capacity_hours, horizon_days, max_buckets_per_day — the advisor reports cadence/dwell/capacity as missing rather than inventing them). Returns next_tool + drafted next_args, missing_inputs, blocked_by, remaining_steps, guidance_uri, and `guidance` (th…

Input parameters:

- `inputs`
- `intent_category` (string, required)
- `state`

### `ep_search` (~147 tokens)

Search Expert Pack

[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'.

Input parameters:

- `max_results` (integer)
- `query` (string, required)
- `tags`
- `type`

### `ep_list_topics` (~59 tokens)

List Expert Pack Topics

[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.

Input parameters:

- `type`

### `ep_graph_traverse` (~85 tokens)

Traverse Expert Pack Links

[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.

Input parameters:

- `depth` (integer)
- `edge_kinds`
- `file_path` (string, required)

### `ensure_map_viewer` (~225 tokens)

Wait for Map Viewer

[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.

Input parameters:

- `guidance_handle`
- `map_session_id` (string, required)
- `poll_interval_ms` (integer)
- `wait_seconds` (number)

### `submit_feedback` (~191 tokens)

Submit Feedback

[Tier 2 — Quality Feedback] When: workflow blocked, partial, workaround required, confusing tool response, or missing capability/docs. Prerequisites: none. Next: continue or end session after acknowledgement. Scenarios: GC-006. No secrets, credentials, raw customer data, or PII. Do not paste Territory Solution JSON, GeoJSON FeatureCollections, or account/CSV tables — those blocks are stripped.

Input parameters:

- `category`
- `client_name`
- `client_version`
- `confidence`
- `context_summary`
- `correlation_id`
- `expected_capability`
- `include_context` (boolean)
- `related_product_area`
- `related_tool`
- `session_id`
- `severity`
- `suggested_improvement`
- `user_goal` (string, required)
- `what_happened` (string, required)

### `query_parts` (~164 tokens)

Query Territory Parts

[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.

Input parameters:

- `filter`
- `guidance_handle`
- `max_results` (integer)
- `page_token`
- `part_ids`
- `part_layer` (string, required)

### `direct_build` (~345 tokens)

Build Territories from Assignments

[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.

Input parameters:

- `assignments`
- `assignments_handle`
- `duplicate_part_policy` (string)
- `expected_revision`
- `guidance_handle`
- `map_session_id`
- `missing_part_policy` (string)
- `part_layer` (string, required)
- `repair_policy` (string): 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_label` (string, required)
- `ts`
- `ts_handle`

### `auto_build` (~1221 tokens)

Auto-Build Territories

[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…

Input parameters:

- `build_mode`
- `dwell_time`
- `expected_revision`
- `guidance_handle`
- `ignore_visit_frequency`
- `map_session_id`
- `objective`
- `output_mode` (string): 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` (string, required)
- `part_scope`
- `point_layer` (string, required)
- `repair_policy` (string): 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` (string, required)
- `ts`
- `ts_handle`
- `visit_frequency_field`

### `cluster_points` (~829 tokens)

Cluster Points

[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…

Input parameters:

- `build_mode`
- `dwell_time`
- `expected_revision`
- `group_field` (string)
- `group_label_prefix` (string)
- `guidance_handle`
- `map_session_id`
- `metric_fields`
- `objective`
- `point_filter`
- `point_layer` (string, required)
- `seed_attraction`
- `seed_point_layer`
- `ts`
- `ts_handle`
- `visit_frequency_field`

### `schedule_visits` (~605 tokens)

Schedule Visits

[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…

Input parameters:

- `cadence_flexibility_pct`
- `daily_capacity`
- `dwell_time`
- `emit_visit_layer` (boolean)
- `expected_revision`
- `frequency_unit` (string)
- `guidance_handle`
- `horizon`
- `map_session_id`
- `max_buckets_per_day`
- `never_visit_values`
- `objective`
- `point_layer` (string, required)
- `schedule_label`
- `ts`
- `ts_handle`
- `visit_frequency_field` (string, required)
- `visit_layer_name`

### `account_build` (~507 tokens)

Build Territories by Account Field

[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.

Input parameters:

- `conflict_policy` (string)
- `expected_revision`
- `grouping_field`
- `guidance_handle`
- `ignore_visit_frequency`
- `map_session_id`
- `output_mode` (string): 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_layer` (string, required)
- `repair_policy` (string): 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`

### `realign` (~540 tokens)

Realign Parts

[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.

Input parameters:

- `expected_revision`
- `guidance_handle`
- `map_session_id`
- `moves`
- `part_ids`
- `part_layer`
- `realign_operation`
- `remove_empty_territories` (boolean)
- `repair_policy` (string): 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` (string, required)
- `ts`
- `ts_handle`

### `delete_tal` (~261 tokens)

Delete Alignment

[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.

Input parameters:

- `guidance_handle`
- `map_session_id`
- `tal_id` (string, required)
- `ts_handle`

### `delete_territory` (~419 tokens)

Delete Territory

[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.

Input parameters:

- `expected_revision`
- `guidance_handle`
- `map_session_id`
- `part_layer`
- `repair_policy` (string): 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` (string, required)
- `territory_id` (string, required)
- `ts`
- `ts_handle`

### `territory_split` (~328 tokens)

Split Territory

[Tier 1 — Minimal-Disruption Split] When: split one oversized territory with minimal disruption to the rest of the alignment. Prerequisites: existing TAL with target territory; viewer connected for MC-first. Open MC preferred args: map_session_id + source_tal_id + target_territory_id (live session TS is authoritative — do not repost GeoJSON). Headless: ts_handle or Compact/GeoJSON ts. Distinct from auto_build Scoped Split (balanced-from-scratch). Modern form-capable clients may be prompted in-band for missing source/target ids (and unresolved workload dwell); legacy hosts keep CLARIFICATION_REQUIRED. Next: compare derived TAL in MC, analyze disruption_summary. Scenarios: SP-001..004.

Input parameters:

- `balance_tolerance`
- `disruption_weight`
- `dwell_time`
- `guidance_handle`
- `map_session_id`
- `new_tal_label`
- `new_territory_label`
- `objective`
- `part_layer`
- `point_layer`
- `repair_policy` (string): 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…
- `source_tal_id`
- `target_territory_id`
- `ts`
- `ts_handle`
- `visit_frequency_field`

### `territory_merge` (~424 tokens)

Merge Territories

[Tier 1 — Minimal-Disruption Merge] When: merge two adjacent territories and rebalance with minimal disruption — including a rep who quits or leaves (their territory is absorbed by its neighbors) and going from N to N-1 territories on an existing alignment. Pass the territory that goes away as territory_id_b and one adjacent neighbor as territory_id_a (it keeps its id); the same job then rebalances every remaining territory, so do not follow it with territory_rebalance. Not delete_territory (that leaves the parts unassigned) and not a new auto_build (that discards the alignment). One call removes one territory. On NON_ADJACENT_TERRITORIES pick another neighbor. Prerequisites: adjacent territory_id_a and territory_id_b in source TAL. Open MC preferred args: map_session_id + source_tal_id + territory_id_a/b (live session TS is authoritative — do not repost GeoJSON). Headless: ts_handle or Compact/GeoJSON ts. Modern form-capable clients may be prompted in-band for missing ids / workload dwell; legacy hosts keep CLARIFICATION_REQUIRED. Next: verify merged TAL in MC, analyze. Scenarios: MG-001..005, EV-001.

Input parameters:

- `balance_tolerance`
- `disruption_weight`
- `dwell_time`
- `guidance_handle`
- `map_session_id`
- `new_tal_label`
- `objective`
- `part_layer`
- `point_layer`
- `repair_policy` (string): 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…
- `source_tal_id`
- `territory_id_a`
- `territory_id_b`
- `ts`
- `ts_handle`
- `visit_frequency_field`

### `territory_rebalance` (~467 tokens)

Rebalance Territories

[Tier 1 — Minimal-Disruption Rebalance] When: underlying account data changed but alignment should stay close to current (MDR). Open MC preferred args: map_session_id + source_tal_id (+ objective/dwell) — the live session TS is authoritative; do not invent a ts_handle or repost multi-MB GeoJSON when a map session is open. Headless: ts_handle or Compact TS v2 / GeoJSON ts (both valid). Prerequisites: source TAL, refreshed point_layer; viewer connected for MC-first. point_layer may be omitted: the source TAL's build point layer, else the TS's only point layer, is used. CLARIFICATION_REQUIRED details.reason=ambiguous_point_layer (pass point_layer from details.point_layers) or zero_workload (workload_bias>0 but no account maps to a part — check point_layer and dwell; never rerun as is). The source assignment is the non-regression baseline: if no generated candidate improves the requested objective, the derived TAL stays unchanged and returns NO_IMPROVING_REBALANCE_FOUND. Read solver_diagnostics for source/generated/accepted objectives and convergence. Modern form-capable clients may be prompted in-band for missing source_tal_id / uninferable part_layer / unresolved workload dwell; legacy hosts keep CLARIFICATION_REQUIRED (HITL-025). Next: report retention_pct and diagnostics, then analyze before/after with analysis_panel=single. Scenarios: RB-001..005, EV-003.

Input parameters:

- `balance_tolerance`
- `disruption_weight`
- `dwell_time`
- `guidance_handle`
- `map_session_id`
- `new_tal_label`
- `objective`
- `part_layer`
- `point_layer`
- `repair_policy` (string): 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…
- `source_tal_id`
- `ts`
- `ts_handle`
- `visit_frequency_field`

### `extract_tal_branch` (~157 tokens)

Extract Alignment Branch

[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.

Input parameters:

- `branch_rollup_territory_id`
- `branch_territory_path`
- `delegate_ref`
- `exclude_locked` (boolean)
- `expected_content_hash`
- `expected_revision`
- `guidance_handle`
- `map_session_id`
- `tal_id` (string, required)
- `ts`
- `ts_handle`

### `reintegrate_branch` (~155 tokens)

Reintegrate Alignment Branch

[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.

Input parameters:

- `branch_metadata` (object, required)
- `expected_master_content_hash`
- `expected_master_revision` (integer, required)
- `guidance_handle`
- `map_session_id`
- `master_ts`
- `master_ts_handle`
- `proposal_ts`
- `proposal_ts_handle`

### `request_part_selection` (~366 tokens)

Request Part Selection

[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.

Input parameters:

- `active_tal_id`
- `destination_territory_id`
- `expiry_seconds`
- `guidance_handle`
- `new_territory`
- `part_layer` (string, required)
- `prompt`
- `purpose` (string)
- `realign_operation`
- `remove_empty_territories` (boolean)
- `ts`
- `user_id`

### `get_part_selection` (~208 tokens)

Get Part Selection

[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.

Input parameters:

- `guidance_handle`
- `selection_task_id` (string, required)

### `create_territory_from_parts` (~540 tokens)

Create Territory from Parts

[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…

Input parameters:

- `conflict_policy`
- `dwell_time`
- `guidance_handle`
- `map_session_id`
- `part_ids` (array, required)
- `part_layer` (string, required)
- `tal_id`
- `territory_name` (string, required)
- `territory_path`
- `ts`
- `ts_handle`

### `analyze` (~917 tokens)

Analyze Territories

[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…

Input parameters:

- `analysis_panel`
- `compare_tals` (boolean)
- `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`

### `ingest_accounts` (~1284 tokens)

Ingest Accounts

[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…

Input parameters:

- `accept_suboptimal_geocodes` (boolean)
- `accounts_handle`
- `country_hint`
- `display_fields`
- `dwell_time_field`
- `force_regeocode` (boolean)
- `grouping_fields`
- `guidance_handle`
- `id_field` (string)
- `label` (string)
- `label_field` (string)
- `latitude_field` (string)
- `longitude_field` (string)
- `map_session_id`
- `metric_fields`
- `min_confidence` (number)
- `point_layer` (string)
- `region_hint`
- `rows`
- `search_fields`
- `ts`
- `ts_handle`
- `use_cache` (boolean)
- `visit_frequency_field`
- `workload_fields`

### `request_account_upload` (~714 tokens)

Request Account Upload

[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…

Input parameters:

- `csv_file`
- `csv_text`
- `guidance_handle`
- `rows`
- `ttl_seconds`
- `upload_handle`

### `request_assignment_upload` (~332 tokens)

Request Assignment Upload

[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).

Input parameters:

- `assignments`
- `csv_file`
- `csv_text`
- `guidance_handle`
- `ttl_seconds`
- `upload_handle`

### `geocode_address` (~326 tokens)

Geocode Addresses

[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.

Input parameters:

- `accept_suboptimal_geocodes` (boolean)
- `country_hint`
- `force_regeocode` (boolean)
- `guidance_handle`
- `map_session_id`
- `min_confidence` (number)
- `region_hint`
- `rows` (array, required)
- `use_cache` (boolean)

### `calculate_route` (~869 tokens)

Calculate Route

[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…

Input parameters:

- `depart_at`
- `dwell_time`
- `end`
- `guidance_handle`
- `include_geometry` (boolean)
- `map_session_id`
- `route_id`
- `route_label`
- `route_type` (string, required)
- `start` (object, required)
- `stop_sets` (array, required)
- `travel_mode` (string)
- `ts_handle`

### `isochrone_build` (~836 tokens)

Build Drive-Time Area

[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…

Input parameters:

- `avoid`
- `bands` (array, required)
- `depart_at`
- `guidance_handle`
- `map_session_id`
- `origins` (array, required)
- `route_type` (string)
- `tal_id`
- `tal_label`
- `traffic` (boolean)
- `travel_mode` (string)
- `ts_handle`

### `seed_build` (~833 tokens)

Grow Territory from Seed

[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…

Input parameters:

- `guidance_handle`
- `map_session_id`
- `max_parts`
- `part_filter`
- `part_ids`
- `part_layer`
- `part_scope`
- `point_layer`
- `seed` (object, required)
- `tal_id`
- `tal_label`
- `target` (object, required)
- `territory_name`
- `ts_handle`
- `user_id`

### `delete_route` (~199 tokens)

Delete Route

[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.

Input parameters:

- `guidance_handle`
- `map_session_id`
- `route_id` (string, required)
- `ts_handle`

### `analyze_routes` (~358 tokens)

Analyze Routes

[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.

Input parameters:

- `dwell_time`
- `guidance_handle`
- `map_session_id`
- `route_ids`
- `ts_handle`

### `tasks_cancel` (~106 tokens)

Cancel Task

[Tier 2 — MCP Tasks mirror] Tool-only client equivalent of native tasks/cancel. Use only when this mirror appears in tools/list; Tasks-capable clients use tasks/cancel instead. Prerequisite: task_id from the immediately preceding async submission. Returns the same Task status fields and EZT poll metadata as the native method. Cancellation is cooperative; confirm TS unchanged or partial per the originating tool contract. Scenarios: OP-001.

Input parameters:

- `task_id` (string, required)

### `tasks_get` (~252 tokens)

Get Task Status

[Tier 2 — MCP Tasks mirror] Tool-only client equivalent of native tasks/get. Use only when this mirror appears in tools/list; Tasks-capable clients use tasks/get. Prerequisite: task_id from the immediately preceding async submission. Polling never starts work. next_action and sleep_ms sit on this document (the same fields as the submit result) and are repeated under _meta. Follow next_action exactly: sleep_and_poll means sleep the single authoritative sleep_ms value, call tasks_get once, then re-read both fields; consume_result means call tasks_result once now; stop_error means stop. status=cancelled is a user stop — do not resubmit the same tool unless asked. Never sleep on estimated_remaining_ms and never poll HTTP /result for status. While a task is still queued, _meta also carries queue_position (1-based within its worker lane), queue_depth, queue_lane (io|compute), and estimated_start_ms — report these to explain a wait; estimated_start_ms is advisory and never a sleep duration. The result is the same Task status document returned by native tasks/get. Scenarios: OP-002, tool-only MCP clients.

Input parameters:

- `task_id` (string, required)

### `tasks_result` (~139 tokens)

Get Task Result

[Tier 2 — MCP Tasks mirror] Tool-only client equivalent of native tasks/result. Call exactly once after tasks_get returns status=completed and _meta.next_action=consume_result. Prerequisite: task_id from that completed Task. Returns the originating tool's terminal handle-only result (ts_handle, counts, timings, map binding/shortcut); it never returns inline TS when a handle exists. Do not poll this operation while working. After build results, pass ts_handle or the same task_id as job_id to analyze with explicit tal_ids; never resubmit a build to recover from an Analyze lookup error.

Input parameters:

- `task_id` (string, required)

### `set_map_state` (~329 tokens)

Set Map State

[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).

Input parameters:

- `active_tal_id`
- `center`
- `guidance_handle`
- `map_session_id` (string, required)
- `mode`
- `pending_job_reference`
- `zoom`

### `get_map_selection` (~240 tokens)

Get Map Selection

[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.

Input parameters:

- `guidance_handle`
- `map_session_id` (string, required)

### `load_analysis_panel` (~338 tokens)

Load Analysis Panel

[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.

Input parameters:

- `analyses`
- `dismiss` (boolean)
- `guidance_handle`
- `job_id`
- `labels`
- `map_session_id` (string, required)
- `presentation_mode`
- `roles`
- `task_id`

### `configure_map` (~773 tokens)

Configure Map

[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…

Input parameters:

- `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`

### `show_map_overlay` (~726 tokens)

Show Map Overlay

[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…

Input parameters:

- `expected_content_hash`
- `expected_revision`
- `guidance_handle`
- `map_session_id`
- `merge_strategy`
- `overlay_id`
- `overlay_kind`
- `route_id`
- `ts`
- `ts_handle`
- `user_request`

### `export_geojson` (~368 tokens)

Export GeoJSON

[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).

Input parameters:

- `guidance_handle`
- `include_points` (boolean)
- `include_routes` (boolean)
- `job_id`
- `map_session_id`
- `point_layers`
- `route_layers`
- `tal_ids`
- `ts_handle`
- `zip` (boolean)

### `import_geojson` (~288 tokens)

Import GeoJSON

[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).

Input parameters:

- `geojson`
- `geojson_gzip`
- `geojson_text`
- `guidance_handle`
- `overlay_policy`
- `part_layer`
- `point_layer`
- `tal_label`

### `ezt` (~258 tokens)

EasyTerritory Assistant

[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).

Input parameters:

- `accounts_handle`
- `args`
- `assignments_handle`
- `csv_file`
- `guidance_handle`
- `map_session_id`
- `request` (string, required)
- `state_facts`
- `ts_handle`

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp#diagnostics

## Score history

- 2026-10-07: 76
- 2026-10-04: 75
- 2026-10-03: 74
- 2026-10-02: 74
- 2026-10-01: 73
- 2026-09-30: 73
- 2026-09-29: 72

## 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.

## Links

- Remote endpoint: https://mcp.easyterritory.ai/
- Authorisation metadata: https://mcp.easyterritory.ai/.well-known/oauth-protected-resource
- Website: https://easyterritory.ai/
- Changelog RSS feed: https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp.json
- HTML version of this page: https://verifymcp.io/servers/ai-easyterritory-ezt-mcp/mcp
