cnc-mcp
Provides tools for interacting with the Cisco Crosswork Network Controller (CNC) API, covering device inventory, credential profiles, providers (SR-PCE, NSO, etc.), the topology graph, tags, alarms, users, installed applications, and inventory jobs. Read tools list/get devices, credential profiles, providers, topology summaries/nodes/links, and platform resources, with paging and case-insensitive wildcard filters. Optional write tools (when enabled) create/update/delete devices, credential profiles, and providers, returning Crosswork's job envelope.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cnc-mcplist all devices that are currently unreachable"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cnc-mcp
MCP server for Cisco Crosswork Network Controller (CNC) — device inventory, credential profiles, providers (SR-PCE, NSO, …), the topology graph, tags, alarms, users, installed applications, and inventory jobs. Official MCP Python SDK 2.x, stdio transport. Built and verified live against a CNC 7.x lab fed by a CML/XRd SR-MPLS fabric with an SR-PCE.
Quickstart
Requires uv and a Crosswork user (see Account privileges).
make install # uv sync
cp .env.example .env # then set CNC_MCP_BASE_URL / USERNAME / PASSWORD
make test && make lint # all HTTP mocked; no live platform needed
make run # start on stdio
make inspect # MCP Inspector against the serverClaude Desktop / .mcp.json:
{
"mcpServers": {
"cnc": {
"command": "uv",
"args": ["--directory", "/path/to/cnc-mcp", "run", "cnc-mcp"],
"env": { "CNC_MCP_BASE_URL": "https://cnc.example.com:30603" }
}
}
}Put the credentials in .env (never in the JSON). Write tools stay hidden until
CNC_MCP_ENABLE_WRITES=true.
Related MCP server: network-mcp
Configuration
Variable | Default | Purpose |
| (required) | CNC UI/API URL with scheme, e.g. |
| — | Crosswork user; two-leg CAS SSO → 8 h JWT, refreshed automatically |
| — | Alternative: a pre-issued JWT (cannot be refreshed) |
|
|
|
|
| Write tools are not registered until |
| see | Timeouts, retries, concurrency, response cap |
Tools
Read tools (always registered):
Area | Tools |
Devices |
|
Credential profiles |
|
Providers |
|
Topology |
|
Platform |
|
Write tools (CNC_MCP_ENABLE_WRITES=true):
Area | Tools |
Devices |
|
Credential profiles |
|
Providers |
|
Conventions the tools follow (and that the server tells agents about):
List tools page with
page_size/page(0-based) and return{total, count, page, page_size, has_more, next_page, items};totalcounts matches for the filter,collection_totalthe whole collection.Filters are exact-match, case-insensitive, with
*as a wildcard.Enum inputs accept friendly values (
admin_state="up",family="sr_pce",protocol="ssh") or the platform's wire values.Writes return Crosswork's job envelope; a job the platform rejected is reported as
Error: …with the platform's reason.Ordering: credential profile → provider → device. A device's
te_router_idmust match its router-id in the SR-PCE topology for the two to correlate.
Account privileges
A user with the admin role was used for verification. Read tools need the
inventory, topology, alarm, and AAA read tasks; write tools need inventory
write. Crosswork returns the same "Invalid credentials" for a wrong password
and for a non-existent user — confirm the account under Administration ›
Users and Roles first.
Live smoke test
scripts/smoke_plan.json targets the lab described in the platform notes. The
read phase is side-effect free; the write phase creates smoke-* objects and
removes them again.
uv run python scripts/live_smoke.py # read phase
uv run python scripts/live_smoke.py --write # read + write phasesPlatform notes
Everything verified live about the CNC API (auth flow, the per-endpoint response envelopes, the query grammar and its traps, SR-PCE integration) is kept in the platform notes file outside this repo. Highlights that shaped the code:
Crosswork never answers 401: a bad token is
403 "Unauthorized request", a malformed one500 "Middleware error"— the auth strategy classifies those so the client re-authenticates.POST …/querybodies page withfilterData.PageSize/PageNum; a top-leveloffsetis silently ignored.Unknown filter field names are ignored and return the whole collection.
Update is
PATCH, delete takes a JSON body; path-parameter forms do not exist. Failed writes are HTTP 200 withstate: JOB_FAILED.CNC authenticates to an SR-PCE's northbound API with HTTP Digest.
Development
make test # pytest (respx-mocked HTTP)
make lint # ruff
make fmt # ruff format + autofix
make docker-buildAvailable Tools
19 toolscnc_get_credential_profileGet Credential ProfileARead-onlyIdempotent
Get the full record of one credential profile by name.
Read-only. Profiles have no UUID: the name is the identifier everywhere (devices and providers reference it in their "profile" field). Find names with cnc_list_credential_profiles.
Args: profile: exact profile name (case-insensitive; surrounding whitespace is stripped). A '*' wildcard is accepted by the platform but this tool needs a single exact match.
Returns: str: JSON object {"profile": str, "user_pass": [{"user_name", "password": "******", "type": "ROBOT_USERPASS_SSH|HTTP|HTTPS|...", ...}], "v2_info": {...}?, "v3_info": {...}?}. Secrets are masked by the API. On failure: "Error: Credential profile '' not found ..." when nothing matches, "Error: ... matches several profiles ..." when a wildcard was used, "Error: profile must not be empty ..." for a blank name, or "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| profile | Yes | Exact profile name, case-insensitive (e.g. 'nso', 'cml-xrd'). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the read-only/idempotent/non-destructive profile, but the description goes well beyond them: profiles have no UUID so the name is the identifier everywhere, secrets are masked by the API, wildcards are accepted by the platform but not by this tool, and it enumerates the exact error strings returned on failure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then Read-only note, then Args and Returns sections. The enumeration of four distinct error strings is slightly verbose but each is actionable for an agent and the rest is free of filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers identifier model, masking behavior, wildcard caveat, and failure modes. With an output schema present, the description does not need to explain return values, and its added behavioral context leaves an agent fully equipped to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents the single profile parameter, so the baseline is 3. The description adds real value beyond it: matching is case-insensitive, surrounding whitespace is stripped, and a '*' wildcard is accepted by the platform but rejected here – detail the schema does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (get) and resource (credential profile) with scope 'one ... by name'. It also distinguishes itself from the sibling cnc_list_credential_profiles, so an agent can tell the two apart without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes discovery to 'Find names with cnc_list_credential_profiles' and states the condition that selects this tool: a single exact match is required. Nothing about when to use it over the list sibling is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_deviceGet Device DetailsARead-onlyIdempotent
Get the full inventory record of one device by uuid or host name.
Read-only. Pass exactly one selector. Returns every field Crosswork holds for the node: uuid, host_name, node_ip, admin_state, reachability_state, operational_state, reachability_check, profile, connectivity_info, product_info, routing_info, tag_names, dg_name/dg_uuid, nso_state, errors, creation_time, last_upd_time, ...
Note the read/write asymmetry: node_ip.inet_af reads as a string ('ROBOT_INET_ADDR_TYPE_v4') but is the integer 0 in write bodies, so do not feed this object straight back into a write.
Returns: str: JSON object of the node, or "Error: ..." (not found -> no device matched the selector; ambiguous -> a wildcard host_name matched several devices, use the uuid).
| Name | Required | Description | Default |
|---|---|---|---|
| uuid | No | Device uuid (e.g. '2a9b7c1e-0f3d-4b8a-9c6e-1d2f3a4b5c6d'). | |
| host_name | No | Device host name, exact match, case-insensitive (e.g. 'PE1'). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, yet the description adds real behavioral context: the read/write type asymmetry on node_ip.inet_af that makes round-tripping into a write unsafe, plus precise error-string semantics. That is value well beyond the annotation set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then constraints, then error semantics — a sensible order. Slightly long: enumerating every returned field is redundant given an output schema exists, so a few lines do not fully earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers selection rules, read-only nature, notable data pitfalls, and both error shapes. With an output schema present it does not need to describe the return payload, so nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so uuid/host_name are already documented. The description still adds meaning: exactly one selector must be supplied, and the two selectors behave differently on ambiguity since only uuid guarantees a unique match. Minor tension: it mentions a 'wildcard host_name' while the schema declares exact match.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Get'), resource ('full inventory record of one device'), and both accepted selectors (uuid or host name). The singular 'one device' cleanly separates it from the sibling cnc_list_devices.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs 'Pass exactly one selector' and explains the two failure modes and their remedy (not found vs. ambiguous wildcard -> use the uuid). It does not name cnc_list_devices as the alternative for enumeration, but the singular scope makes the choice inferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_device_collection_summaryGet Device Collection Status SummaryARead-onlyIdempotent
Count devices by collection status across the whole inventory.
Read-only. This is the "Collection status" widget of the Network Devices page: how many devices are in progress, completed, warning, failed or in maintenance for inventory collection. Use it as a quick health check before drilling into individual devices with cnc_list_devices.
Returns: str: JSON with flat integer counts: {"inprogress": int, "warning": int, "failed": int, "completed": int, "maintenance": int} On failure: "Error: ...".
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, so the description's 'Read-only' line is redundant. However, it adds genuine behavioral context beyond structured fields: the exact status categories counted and the failure surface ('On failure: "Error: ..."'). This is solid added value, short of exceptional.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then usage, then return shape. Every block is relevant, though the 'Read-only' line repeats annotations and the explicit Returns block is somewhat redundant given an output schema exists. Minor padding, no real waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter aggregate tool whose safety profile is covered by annotations and whose return shape is backed by an output schema, the description is complete: purpose, use case, alternative, and count semantics are all present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4. There is nothing for the description to disambiguate on inputs, and it correctly spends no words on parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (count) and resource (devices by collection status) with an explicit scope (across the whole inventory). It further disambiguates from the sibling cnc_list_devices by contrasting the aggregate widget against drilling into individual devices.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use it ('quick health check before drilling into individual devices') and names the alternative tool (cnc_list_devices) for a different granularity. The routing condition is clear enough that an agent need not infer it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_inventory_jobGet Inventory JobARead-onlyIdempotent
Get one inventory job by id: its state, type, timestamps, the objects it touched and the error text when it failed.
Read-only. Use it to check the outcome of a device/credential/provider write. For a job that may still be running prefer cnc_wait_for_inventory_job, which polls until it finishes. The lookup scans the newest few hundred jobs (newest first), so a very old job may not be found even though cnc_list_inventory_jobs can still page to it.
Returns: str: JSON of the job: {"job_id", "state", "type", "creation_time", "completion_time", "created_by", "impacted": [" []"], "impacted_objects": [{"uuid", "name", "ip"}], "error"}. A state of JOB_COMPLETED_WITH_WARNING is a success whose advisory is in "error". "Error: No inventory job with id ..." when the id matches nothing; other failures: "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Inventory job id as returned by a write tool or cnc_list_inventory_jobs (e.g. '0f6c1a2e-...'). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower, yet the description still adds real context: the scan window limitation (newest few hundred jobs, newest first, so very old jobs may not be found), the success-with-warning semantics of JOB_COMPLETED_WITH_WARNING, and the exact error-string behavior. These are behavioral traits not encoded in annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose, then usage, then a structured returns block. Every sentence earns its place: the scan-window caveat and warning-state note are non-obvious and actionable, and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param read tool with an output schema and full annotations, this covers purpose, alternatives, lookup limitations, and return shape including edge cases (warning state, not-found error). Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single job_id parameter is already documented with its source and an example, so the schema carries this burden. The description adds little parameter-level detail beyond confirming the id is the lookup key. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get one inventory job by id') and enumerates exactly what is returned: state, type, timestamps, impacted objects, and error text. It explicitly distinguishes itself from siblings cnc_wait_for_inventory_job and cnc_list_inventory_jobs by name, so an agent can route without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('check the outcome of a device/credential/provider write') and a when-to-prefer-alternative rule ('For a job that may still be running prefer cnc_wait_for_inventory_job, which polls until it finishes'). It also names the fallback for old jobs (cnc_list_inventory_jobs can page to it). This is the full when/when-not/alternative set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_providerGet Provider DetailsARead-onlyIdempotent
Get the full record of one provider, by UUID or by exact name.
Read-only. Exactly one of uuid / name must be given. Use it to
inspect a provider's endpoints (connectivity_info), credential
profile (profile), family, reachability and properties (for
SR-PCE: auto-onboard, outgoing-interface, device-profile,
preferred-stack) — for example before cnc_update_provider or
cnc_delete_provider. A uuid lookup scans the (small) provider
collection and matches client-side, since uuid is not a verified
filter field on providers/query.
Returns:
str: JSON object with every provider field as Crosswork returns it
(note connectivity_info[].ipaddrs[].inet_af reads as
'ROBOT_INET_ADDR_TYPE_v4'; write bodies use 0 — don't round-trip a
read object into a write). "Error: ..." when neither or both
selectors are given, when no provider matches (verify with
cnc_list_providers), or on an API failure.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Exact provider name, case-insensitive (e.g. 'cml-pce'). No wildcards; use cnc_list_providers to search. Give either uuid or name, not both. | |
| uuid | No | Provider UUID, exactly as returned by cnc_list_providers (e.g. '4f1c2d3e-...'). Give either uuid or name, not both. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent safety, so the bar is lower, yet the description adds non-obvious behavior: the uuid lookup is a client-side scan because uuid is 'not a verified filter field', and read objects must not be round-tripped into write bodies (inet_af differs). It also enumerates error conditions. This is real operational context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose, then uses a Returns block and parenthetical asides to carry the quirks. Structure is good, but the Returns section is somewhat verbose given an output schema exists, and some phrasing ('as Crosswork returns it') repeats what structured output already implies.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations (safety), a full input schema, and an output schema already present, the description fills the remaining gaps: selector exclusivity, uuid scan behavior, error cases, and the read/write field-format mismatch. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds value by reinforcing the mutual-exclusivity of uuid/name and by explaining that uuid matching happens client-side because it is not a verified filter field, which affects how the agent should source the value. It stops short of adding format details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (get) and resource (one provider) with scope qualifiers (by UUID or exact name), and distinguishes itself from the sibling cnc_list_providers by returning 'the full record of one provider'. An agent can tell it apart from list/get_collection tools without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit rule ('Exactly one of uuid/name must be given'), names the scenarios where it applies (before cnc_update_provider or cnc_delete_provider), and routes to the alternative (verify with cnc_list_providers) when no match occurs. Both selection constraints and the fallback path are spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_topologyGet Topology GraphARead-onlyIdempotent
Get the topology graph: one page of nodes plus one page of links (edges).
Read-only. Crosswork returns the whole graph (up to maxLogicalNodes,
5000 on the lab instance) in one response with no server-side paging,
so this tool re-downloads the graph on every call and pages BOTH lists
client-side: page/page_size window the links, node_page/
node_page_size window the nodes. Each link carries both endpoints
resolved (node UUID, node name, interface), so a links page is
self-contained — you do not need the nodes page to read adjacency.
Use it for node-to-node adjacency (e.g. "what is PE1 connected to?");
for tabular attributes (IPs, reachability, link status/utilisation)
prefer cnc_list_topology_nodes / cnc_list_topology_links. Keep page
sizes modest: the response is capped at the configured size limit.
Args: map_type: 'logical' only ('geo' is rejected with an explanation). page_size: links per page (1-500). page: 0-based page of links. node_page_size: nodes per page (1-1000). node_page: 0-based page of nodes. response_format: markdown (default) or json.
Returns:
str: Markdown listing nodes then "A:ifA <-> B:ifB" per link, or JSON:
{"map_type": "LOGICAL", "attributes": {"totalNodes": int, ...},
"nodes": {"total": int, "count": int, "page": int, "page_size": int,
"items": [{"uuid": str, "name": str}],
"has_more": bool, "next_page": int|null, ...},
"links": {"total": int, "count": int, "page": int, "page_size": int,
"items": [{"uuid": str, "name": "-",
"source": {"node_uuid": str, "node_name": str,
"interface": str},
"target": {"node_uuid": str, "node_name": str,
"interface": str}}],
"has_more": bool, "next_page": int|null, ...}}
Node icon/checksum attributes and edge decoration attributes (the
only attributes the platform returns on /data) are dropped.
On failure: "Error: ". An HTTP 500 "Internal Server
Error" from /v1/topology-service/... means the service rejected the
request body (mapType/viewId/params) — deterministic, do NOT retry.
(It is not the inventory's "NATS request failed" signal.)
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page of links. | |
| map_type | No | Map to read. Only 'logical' (default; wire value 'LOGICAL') is supported — 'geo' is rejected because the platform answers HTTP 500 for it. | logical |
| node_page | No | 0-based page of nodes. | |
| page_size | No | Links per page (client-side paging). | |
| node_page_size | No | Nodes per page (client-side paging). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far beyond the annotations: it discloses that Crosswork returns the whole graph with no server-side paging, so every call re-downloads and pages client-side, that link endpoints are pre-resolved so a links page is self-contained, that icon/checksum and edge-decoration attributes are dropped, and that an HTTP 500 is deterministic and must not be retried.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core fact and cleanly sectioned into Args/Returns/error handling. The verbose JSON return-shape listing is somewhat redundant against the existing output schema, which costs it a point, but little of the prose is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter read tool with annotations and an output schema, the description still supplies the non-obvious operational context: client-side paging rationale, endpoint resolution, dropped attributes, page-size limits, and the deterministic-500 error contract.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds the cross-parameter model — that page/page_size window links while node_page/node_page_size window nodes, and that map_type accepts only 'logical'. This explains the interaction between parameters rather than just restating them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line gives a precise verb and resource plus the exact shape of the payload ('one page of nodes plus one page of links'). It explicitly distinguishes itself from the sibling tools cnc_list_topology_nodes / cnc_list_topology_links by naming them and the attribute category each covers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the use case with a concrete example ('what is PE1 connected to?') and gives an explicit when-not with the alternative tools for tabular attributes. It also adds a sizing caveat ('keep page sizes modest') that shapes invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_get_topology_summaryGet Topology SummaryARead-onlyIdempotent
Summarize the CNC topology: node/link totals and state breakdowns.
Read-only. Combines three topology-service calls (init,
nodes/summary, edges/summary) into one answer. Use it first to
learn whether the topology is populated at all (an empty topology with
a populated inventory usually means no reachable SR-PCE provider), then
drill in with cnc_get_topology, cnc_list_topology_nodes or
cnc_list_topology_links.
Returns:
str: JSON:
{"total_nodes": int, "unmapped_nodes": int, "max_logical_nodes": int,
"reachability": {"CONN_STATE_REACHABLE": 5, ...},
"link_state": {"Up": 1, "Degraded": 0, "Down": 0},
"node_breakdowns": {: {: }, ...},
"link_breakdowns": {: {: }, ...}}
unmapped_nodes counts nodes with no geographic location (they
render on the logical map only). node_breakdowns carries every
section the platform returned (e.g. device family) keyed by type.
Counts are null and breakdowns empty when the platform returns an
empty body (fresh, unpopulated topology).
On failure: "Error: ". An HTTP 500 "Internal Server
Error" from /v1/topology-service/... means the service rejected the
request body (mapType/viewId/params) — deterministic, do NOT retry.
(It is not the inventory's "NATS request failed" signal.)
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent, but the description adds substantial context beyond them: it discloses that three topology-service calls are combined, explains empty-body semantics (null counts, empty breakdowns), the failure format, and a critical non-retry rule for HTTP 500 body rejections, distinguishing it from the inventory's NATS failure signal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the one-line purpose, then usage guidance, then a structured Returns block. The return-shape transcription borders on redundant given an output schema exists, but the semantic annotations attached to it (unmapped_nodes meaning, empty-body behavior) justify most of the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, ordering guidance, alternative tools, return semantics, empty-topology interpretation, and error handling with a non-retry directive. Nothing an agent needs to call this zero-parameter tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to disambiguate; baseline for 0 params is 4. The description correctly implies no filtering input is required.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Summarize the CNC topology') plus the exact scope (node/link totals and state breakdowns), and explicitly names the sibling tools used for drilling in (cnc_get_topology, cnc_list_topology_nodes, cnc_list_topology_links). An agent can distinguish this from the drill-in siblings without reading any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit ordering guidance: 'Use it first to learn whether the topology is populated at all,' with a concrete diagnostic rule (empty topology + populated inventory ⇒ no reachable SR-PCE provider), then routes to the appropriate drill-in alternatives. Both when-to-use and when-to-use-something-else are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_alarmsList AlarmsARead-onlyIdempotent
List Crosswork platform alarms (device reachability, collection, application health, ...), newest first as the platform orders them.
Read-only. Use it to find out why something is unhealthy before digging into devices or providers. Alarms are paged with a SQL-like criteria string ('select * from alarm limit N page M'); no other filtering is exposed. The platform reports no total, so 'has_more' means the page came back full — request the next page to check.
Args: open_only: True for open alarms only (default), False for all. limit / page: page size and 0-based page number.
Returns: str: Markdown with one line per alarm (category, description, created time, id, acknowledged flag, event count; the Events detail is omitted), or JSON: {"total": null, "count": int, "page": int, "page_size": int, "items": [{"AlarmId": str, "AlarmCategory": str, "Description": str, "Created": str, "Updated": str, "Acknowledge": bool, "object_id": str, "origin_app_id": str, "events_count": int, "Events": [...]}, ...], "has_more": bool, "next_page": int|null} On failure: "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number (e.g. 0). | |
| limit | No | Alarms per page (e.g. 20). | |
| open_only | No | True (default) for open alarms only; False to include cleared. | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/non-destructive, but the description adds genuine behavioral detail beyond them: paging is done via a SQL-like criteria string, no total is reported, and 'has_more' just means the page came back full. These quirks materially affect correct invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded and easy to scan, but the description is bloated by an Args block that duplicates the schema and a very long Returns block that restates a full JSON shape despite an output schema existing. Those sections do not fully earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool with annotations and an output schema present, the description is complete enough: it covers purpose, paging, filtering limits, and error format. The only excess is redundant return-value detail, not a gap in coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters. The Args block restates open_only, limit, and page without adding syntax or edge-case meaning beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List Crosswork platform alarms') and even enumerates what the alarms cover (device reachability, collection, application health) plus ordering ('newest first'). It also implicitly distinguishes itself from siblings (devices, providers) by positioning itself as the diagnostic entry point.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-to-use guidance: 'find out why something is unhealthy before digging into devices or providers,' which routes the agent to deeper sibling tools. It also notes that 'no other filtering is exposed' beyond the criteria string, an implicit constraint. No explicit when-not-to-use, so not a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_applicationsList Installed ApplicationsARead-onlyIdempotent
List the applications installed on the Crosswork platform with their versions (e.g. Crosswork Optimization Engine, Service Health, ...).
Read-only. Use it to check what is installed and at which version before assuming a feature (topology, SR-TE, VPN services) is available on this instance.
Returns: str: Markdown "name (application_id) version — description" lines, or JSON: {"count": int, "items": [{"application_id": str, "application_data": {"version": str, "summary": {"name": str, "description": str}, "category": str, "build_information": {"date_time": str, "publisher": str}}}, ...]} On failure: "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so 'Read-only' mostly restates structured data. The one genuinely additive behavioral detail is the failure mode ('Error: <actionable message>'), but nothing is said about latency, pagination, or freshness of the installed-application data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and usage sentences are front-loaded and efficient, but the large 'Returns' block unpacks a nested JSON payload field-by-field, which is substantial duplication given an output schema exists. Roughly half the text is redundant structure rather than guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is inherently simple (one optional param, read-only), and the description covers purpose, usage context, and failure behavior. Since an output schema exists, the detailed return enumeration is unnecessary rather than missing, so completeness is high.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with a single optional response_format parameter whose enum and per-value meaning are documented in the schema. The description never mentions response_format, so it adds no meaning beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the applications installed on the Crosswork platform') and concretely grounds it with examples of the applications returned. It is clearly distinguishable from the device, credential, provider, and topology siblings, which all operate on different resources.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit situational guidance: use it to check what is installed and at which version before assuming a feature (topology, SR-TE, VPN services) is available. It doesn't name a competing sibling or a when-not-to-use case, but for a simple unfiltered list tool the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_credential_profilesList Credential ProfilesARead-onlyIdempotent
List credential profiles known to Crosswork, with optional name filter and paging.
Read-only. Use it to find the profile name to reference when adding devices or providers, or to check which protocols (SSH/HTTP/HTTPS/SNMPv2/...) a profile covers. For one profile's full record use cnc_get_credential_profile.
Secrets are masked by the API ("******"); usernames are returned in clear.
Args: profile: name filter (exact, case-insensitive, '*' wildcard; surrounding whitespace is stripped and a blank filter means no filter). page_size / page: filterData paging (0-based page). response_format: 'markdown' (default) or 'json'.
Returns: str: Markdown "- profile — types: SSH (user), HTTP (user), SNMPv2" lines, or JSON: {"total": int|null, "count": int, "page": int, "page_size": int, "items": [{"profile": str, "user_pass": [{"user_name": str, "password": "", "type": "ROBOT_USERPASS_SSH|HTTP|HTTPS|..."}], "v2_info": {"read_community": "", ...}?}, ...], "has_more": bool, "next_page": int|null, "collection_total": int|null} "total" is the number of profiles matching the filter (null when the platform omits it, i.e. zero matches); "collection_total" is the size of the whole collection regardless of filter. On failure: "Error: " (500 "NATS request failed" -> the query body was rejected; 403 -> token rejected or missing privilege).
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number (e.g. 0). | |
| profile | No | Filter by profile name: exact match, case-insensitive, '*' is a wildcard (e.g. 'nso', 'cml-*', '*xrd'). No filter lists every profile. | |
| page_size | No | Profiles per page (e.g. 20). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly/idempotent/openWorld), the description discloses that secrets are masked as '******' while usernames are clear, and maps failure modes (500 NATS request failed, 403 token rejected or missing privilege). That is auth/behavioral context the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and routing, then cleanly sectioned into Args and Returns. The Returns block is verbose and largely duplicates the existing output schema, which is the main place text is not fully earning its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param read-only list tool, the definition covers purpose, alternatives, filters, paging, output shape, and error semantics. An agent has everything needed to call it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds semantics the schema lacks: surrounding whitespace is stripped, a blank filter means no filter, and paging is explicitly 0-based with the response_format default restated. It goes modestly beyond the schema rather than merely echoing it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
First sentence states a specific verb (List) and resource (credential profiles) plus scope modifiers (name filter, paging). It explicitly contrasts itself with the sibling cnc_get_credential_profile, so the agent can route without inspecting either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use reasons ('find the profile name to reference when adding devices or providers', 'check which protocols a profile covers') and names the alternative for the single-record case. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_devicesList DevicesARead-onlyIdempotent
List network devices (inventory nodes) with optional filters and paging.
Read-only. Use it to discover device uuids/host names before calling cnc_get_device, cnc_update_device or cnc_delete_device. Filters AND together. Unmanaged devices are hidden in the CNC UI's default table but are returned here.
Args: host_name, reachability, admin_state, credential_profile: exact-match filters (case-insensitive, '*' wildcard). Enum filters accept friendly or wire values. page_size, page: paging (page is 0-based). response_format: 'markdown' (default) or 'json'.
Returns: str: Markdown, one line per device: "host_name (uuid) ip=... reach=... oper=... admin=... profile=... dg=..." plus "More available: page=N." when another page exists. Or JSON: {"total": int|null, "count": int, "page": int, "page_size": int, "has_more": bool, "next_page": int|null, "collection_total": int|null, "items": []} 'total' is the number of matches for the filter (absent when zero matched); 'collection_total' is the size of the whole inventory. On failure: "Error: " (unknown enum value -> the accepted values are listed; 500 'NATS request failed' -> the platform could not parse the request).
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number. | |
| host_name | No | Filter by host name: exact match, case-insensitive, '*' wildcard (e.g. 'PE1' or 'PE*'). No substring match without '*'. | |
| page_size | No | Devices per page (e.g. 20). | |
| admin_state | No | Filter by admin state: 'up', 'down' or 'unmanaged' (or the wire value, e.g. 'ROBOT_ADMIN_STATE_UP'). | |
| reachability | No | Filter by reachability: 'reachable', 'unreachable', 'degraded' or 'unknown' (or the wire value, e.g. 'CONN_STATE_REACHABLE'). | |
| response_format | No | 'markdown' for a one-line-per-device summary, 'json' for all fields. | markdown |
| credential_profile | No | Filter by credential profile name (e.g. 'cml-xrd'); '*' wildcard. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses that filters AND together, that unmanaged devices are included unlike the UI, and documents failure modes with actionable error semantics ('unknown enum value -> accepted values listed', 500 NATS failure meaning). This is unusually rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, usage, then Args/Returns. Well-organized, though the Returns block is long and partially redundant with the existing output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param, filter-heavy read tool with an output schema, this covers discovery intent, filter combination, visibility caveats, paging, and error behavior comprehensively. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the parameter descriptions already carry most semantics. The description adds the cross-parameter rule that filters are AND-ed together and repeats the case-insensitive/'*' wildcard and 0-based paging contract, which is useful but largely mirrored in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific verb+resource ('List network devices (inventory nodes)') plus scope ('optional filters and paging'). It even clarifies that these devices are inventory nodes, distinguishing it from the topology-oriented siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use this to discover uuids/host names before calling cnc_get_device, cnc_update_device or cnc_delete_device. It also warns that unmanaged devices are hidden in the CNC UI default table but returned here, preventing a wrong inference about coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_inventory_jobsList Inventory JobsARead-onlyIdempotent
List inventory jobs — the audit trail of every device, credential, provider and tag write on Crosswork (each write returns one job).
Read-only. Use it to review recent changes or to find the job_id of a write whose result was lost, then inspect one with cnc_get_inventory_job or wait for it with cnc_wait_for_inventory_job. Paged with the inventory filterData.PageSize/PageNum grammar (assumed for this endpoint; 'total' is null when the platform reports no result_count, and 'has_more' then means the page came back full).
Args: page_size / page: page size and 0-based page number.
Returns: str: Markdown listing, or JSON: {"total": int|null, "count": int, "page": int, "page_size": int, "items": [{"job_id": str, "state": str, "type": str, "creation_time": str, "completion_time": str, "created_by": str, "impacted": [str, ...], "error": str}, ...], "has_more": bool, "next_page": int|null, "collection_total": int|null} States: JOB_COMPLETED and JOB_COMPLETED_WITH_WARNING (a success with an advisory in "error", e.g. a no-op or partially applied write), JOB_FAILED / JOB_CANCELLED / JOB_ABORTED (unsuccessful), JOB_RUNNING and other in-progress states. On failure: "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number (e.g. 0). | |
| page_size | No | Jobs per page (e.g. 20). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint and no destruction, but the description adds real behavioral context: pagination grammar, the fact that 'total' is null when the platform reports no result_count, and that 'has_more' then means the page came back full. It also interprets job states (e.g. COMPLETED_WITH_WARNING is a success with an advisory in 'error') and failure format. The bulk of the return-value detail, however, overlaps the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, scope, and routing in the first two paragraphs, and the hedging on the pagination grammar ('assumed for this endpoint') is honest. It is somewhat over-long, however: the full Returns JSON shape duplicates information already present in the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a paged, read-only list endpoint, the definition covers purpose, routing alternatives, pagination caveats, item fields, state interpretation, and failure output. An output schema exists, so the return-shape narration is bonus rather than a gap, and nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents page, page_size and response_format. The description's Args line ('page_size / page: page size and 0-based page number') merely restates the schema, adding no new syntax or constraints — baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource plus its exact scope: 'the audit trail of every device, credential, provider and tag write on Crosswork (each write returns one job).' This clearly separates it from the singular cnc_get_inventory_job and the blocking cnc_wait_for_inventory_job.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names two use cases ('review recent changes' and 'find the job_id of a write whose result was lost') and routes the agent to the correct follow-up tools (cnc_get_inventory_job, cnc_wait_for_inventory_job) with the condition for each.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_providersList ProvidersARead-onlyIdempotent
List the providers configured in Crosswork (SR-PCE, NSO, WAE, ...).
Read-only. Providers are the external systems CNC integrates with; the SR-PCE provider is what feeds the L3/SR-TE topology (via BGP-LS), and the NSO provider is used for service provisioning. Use this to discover provider UUIDs and check their reachability before touching devices, topology, or services; use cnc_get_provider for the full record.
Filters AND together. Only name and family are supported
filters on this endpoint. Page with page/page_size (0-based).
Args:
name: exact/wildcard name filter (case-insensitive).
family: friendly family name (sr_pce, nso, wae, syslog_storage,
alert, proxy, onc, accedian_proxy) or wire value.
page_size, page: paging; has_more/next_page say whether to
fetch another page.
response_format: markdown (one line per provider: name, uuid,
family, reachability, endpoints, credential profile) or json.
Returns:
str: Markdown listing, or JSON:
{"total": int|null, "count": int, "page": int, "page_size": int,
"items": [{"uuid", "name", "family", "profile",
"reachability_state", "connectivity_info": [...],
"properties": {...}, ...}],
"has_more": bool, "next_page": int|null,
"collection_total": int|null, "offset": int, "next_offset": int|null}
total is the number of providers matching the filter (absent /
null when Crosswork omits it, which it does for zero matches);
collection_total is the size of the whole provider collection.
On failure: "Error: " (unknown family value ->
the list of accepted values; 500 "NATS request failed" -> malformed
request rather than an outage).
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Provider name filter: exact match, case-insensitive, '*' is a wildcard (e.g. 'cml-pce' or '*pce*'). No substring match without '*'. | |
| page | No | 0-based page number (e.g. 0). | |
| family | No | Provider family filter, one of: accedian_proxy, alert, nso, onc, proxy, sr_pce, syslog_storage, wae (e.g. 'sr_pce'); wire values such as 'ROBOT_PROVIDER_SR_PCE' are accepted too. | |
| page_size | No | Providers per page (e.g. 20). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly/idempotent/non-destructive/openWorld), and 'Read-only' restates them. The description does add genuinely non-annotated behavior: response_format output contents, 0-based paging with has_more/next_page, the null/absent semantics of total vs collection_total, and concrete error semantics (unknown family returns accepted values; 500 NATS request failed means malformed request, not an outage).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and organized with clear sections, but verbose: the Args block largely restates the 100%-covered schema and the Returns block reproduces the full JSON shape even though an output schema exists. The one valuable non-redundant detail is the total-vs-collection_total distinction on zero matches.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool it covers everything an agent needs: what it returns, how to page, how filters combine, the sibling to use for detail, and how to interpret failure messages. Missing values for providers/reachability are explained via the field semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds cross-parameter meaning not in the schema, notably that filters AND together, that only name and family are honored on this endpoint, the accepted family values, and what each response_format yields. The name wildcard rule is repeated from the schema rather than extended.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('List the providers configured in Crosswork'), enumerates the concrete provider types (SR-PCE, NSO, WAE), and explains what a provider is and which one feeds the topology. It is trivially distinguishable from cnc_get_provider, which it names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('discover provider UUIDs and check their reachability before touching devices, topology, or services') and names the alternative for the other case ('use cnc_get_provider for the full record'). It also states the filter composition rule (filters AND together) and which filters this endpoint supports.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_tagsList TagsARead-onlyIdempotent
List the tags defined on Crosswork (system tags such as 'mdt' plus any user-defined ones), with optional name/category filtering and paging.
Read-only. Use it to learn the exact tag names before filtering devices by tag or attaching tags to devices. The tool sends an empty body and applies the name/category filters and the paging itself after the fetch. Whether tags/query honours a filter body or pages server-side is not verified; if the response carries result_count/total_count larger than the rows returned, the collection was truncated by the server and the output says so. 'total' is the number of fetched tags that matched the filters; 'collection_total' is the number of tags on the platform (from the server's counts when present, else the number fetched).
Args: name: case-insensitive substring of the tag name. category: exact category (case-insensitive), e.g. 'default'. page_size / page: client-side paging over the filtered tags.
Returns: str: Markdown listing, or JSON: {"total": int, "count": int, "page": int, "page_size": int, "items": [{"name": str, "category": str, "created_by": str, "creation_time": str, "tag_type": str}, ...], "has_more": bool, "next_page": int|null, "collection_total": int} On failure: "Error: ".
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Case-insensitive substring to match against tag names (e.g. 'mdt'). Applied client-side. | |
| page | No | 0-based page number (e.g. 0). | |
| category | No | Exact tag category to keep, case-insensitive (e.g. 'default'). Applied client-side. | |
| page_size | No | Tags per page (e.g. 50). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds non-obvious implementation detail: the tool sends an empty body, filters and pages client-side, and warns the server-side behavior is unverified. It also defines 'total' vs 'collection_total' and the truncation signal, which no annotation or schema conveys.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The two opening sentences are front-loaded and efficient, but the implementation caveats ('Whether tags/query honours a filter body or pages server-side is not verified...') and the full inline return-shape block are verbose and partly duplicate the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, trigger, parameter behavior, the truncation edge case, and the total/collection_total distinction despite an output schema existing. The main gap is a slightly bloated return-value restatement, but overall the agent has what it needs to call and interpret the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each param is described there, so baseline is 3. The description adds value by clarifying that name/category are applied client-side after the fetch and by explaining paging behavior, going beyond the schema's field-level descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('List the tags defined on Crosswork') plus the scope (system tags like 'mdt' plus user-defined). The following sentence gives the downstream use case, and no sibling tool overlaps this purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it: 'Use it to learn the exact tag names before filtering devices by tag or attaching tags to devices.' This gives an unambiguous trigger, which is rare in the sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_topology_linksList Topology LinksARead-onlyIdempotent
List the links (edges) on the topology map with status and utilisation.
Read-only. Each link carries its type (display name, e.g. "L2 Ethernet" for LT_L2_ETHERNET, "L3 ISIS IPv4 L1", "L3 OSPF IPv4", "L3 BGP EPE IPv4"), status (Up/Degraded/Down), both endpoint node names/UUIDs and interface names, and per-direction utilisation labels such as "0.00015% (1.5Kbps/1Gbps)" with a HEALTHY/... severity. L2 links come from LLDP collection; L3 links need an SR-PCE provider (BGP-LS).
Paging is a row window: startRow = page * page_size,
endRow = startRow + page_size. Past the end the platform returns
totalCount with no rows (reported as an empty page, not an error).
No filtering is available.
Args: page_size: rows per page (1-500). page: 0-based page number. response_format: markdown (default) or json.
Returns:
str: Markdown "status linkType: srcNode:srcIf <-> dstNode:dstIf (util)"
per link, or JSON:
{"total": int, "count": int, "page": int, "page_size": int,
"items": [{"uuid": str, "name": str, "linkType": "L2 Ethernet", "status": "Up",
"sourceNode-name": str, "sourceNode-uuid": str,
"sourceConnector-name": str, "targetNode-name": str,
"targetNode-uuid": str, "targetConnector-name": str,
"targetConnector-uto-label": str,
"targetConnector-uto-severity": "HEALTHY", ...}],
"has_more": bool, "next_page": int|null, ...}
Each item is the element's uuid merged with its attributes.
On failure: "Error: ". An HTTP 500 "Internal Server
Error" from /v1/topology-service/... means the service rejected the
request body (viewId/params) — deterministic, do NOT retry.
(It is not the inventory's "NATS request failed" signal.)
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number. | |
| page_size | No | Rows per page (endRow - startRow). | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so 'Read-only' is redundant, but the description goes well beyond them: paging as a row window, past-the-end pages returning totalCount with no rows (not an error), no filtering available, and the deterministic HTTP 500 meaning the request body was rejected and must not be retried. That is substantive behavioral context, though the data-source caveat is the only precondition and auth/rate limits are untouched.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded and the Args section is tight, but the Returns block reproduces a full JSON item shape even though an output schema already exists, and the error-handling aside is a long parenthetical. Sizeable portions of the text do not earn their place against existing structured fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only paged list tool, the description covers paging edge cases, the no-filtering constraint, data-source prerequisites, and error semantics, and an output schema already carries the return shape. An agent has what it needs to call it correctly without guessing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so page, page_size and response_format are already documented. The description adds only the startRow/endRow paging formula, which is a modest gain over the schema's 'rows per page' wording; the 1-500 bound and markdown/json values merely restate the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List the links (edges) on the topology map') and immediately scopes what each element is. Combined with its sibling names (list_topology_nodes, get_topology, get_topology_summary) an agent can tell it returns the edges rather than nodes or a summary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the resource name, and the description notes that link population depends on data sources (L2 via LLDP, L3 requires an SR-PCE provider/BGP-LS). But it never states when to pick this over cnc_list_topology_nodes or cnc_get_topology, nor any explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_topology_nodesList Topology NodesARead-onlyIdempotent
List the nodes on the topology map as a sorted, paged table.
Read-only. Topology nodes are the devices CNC has placed on the map (fed by inventory + SR-PCE); their UUIDs match the inventory node UUIDs. Use this for per-node attributes (management IP, TE router-id, reachability, family); use cnc_get_topology for adjacency.
Paging is a row window: startRow = page * page_size,
endRow = startRow + page_size. Past the end the platform returns
totalCount with no rows (reported as an empty page, not an error).
No filtering is available on this endpoint — filter client-side or use
the inventory tools. The platform silently accepts an unknown sort
column (undefined order), so sort_by is validated here first.
Args: page_size: rows per page (1-500). page: 0-based page number. sort_by: column to sort on (see the parameter description). sort_ascending: sort direction. response_format: markdown (default) or json.
Returns:
str: Markdown listing, or JSON:
{"total": int, "count": int, "page": int, "page_size": int,
"items": [{"uuid": str, "name": str, "nodeIp": str, "teRouterId": str,
"reachabilityState": "CONN_STATE_REACHABLE"|..., "productType": str,
"deviceFamily": str, "lastUpdateTime": str, ...}],
"has_more": bool, "next_page": int|null, ...}
Each item is the element's uuid merged with its attributes.
On failure: "Error: " (unknown sort column ->
"Error: Unknown sort column ..."). An HTTP 500 "Internal Server
Error" from /v1/topology-service/... means the service rejected the
request body (viewId/params) — deterministic, do NOT retry.
(It is not the inventory's "NATS request failed" signal.)
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 0-based page number. | |
| sort_by | No | Column to sort on: 'name' (default), 'nodeIp', 'lastUpdateTime' (all three verified live), 'teRouterId', 'reachabilityState', 'productType' or 'deviceFamily'. | name |
| page_size | No | Rows per page (endRow - startRow). | |
| sort_ascending | No | Sort ascending (true, default) or descending. | |
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already declaring read-only/idempotent behavior, the description adds substantial behavioral context: paging is a row window, past-the-end returns totalCount with no rows rather than an error, unknown sort columns are silently accepted by the platform but validated here, and an HTTP 500 means a deterministic rejection that should not be retried.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with Args and Returns sections and front-loads the primary purpose and sibling routing. It is detailed but most sentences carry operational value; some return-format detail is redundant given the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, paged, filterless list tool with annotations and an output schema, the description covers the key edge cases: paging behavior, lack of server-side filtering, sort validation, and non-retryable HTTP 500 failures. Nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline would be 3. The description adds paging semantics beyond the schema, including the formulas startRow = page * page_size and endRow = startRow + page_size, and notes that sort_by is locally validated against unknown columns.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'List the nodes on the topology map as a sorted, paged table.' It also distinguishes the tool from its sibling cnc_get_topology, which is for adjacency rather than per-node attributes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use this for per-node attributes and directs adjacency queries to cnc_get_topology. It also states there is no filtering on this endpoint and recommends client-side filtering or inventory tools as alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_list_usersList UsersARead-onlyIdempotent
List the Crosswork user accounts with their role, status and device access groups.
Read-only. Use it to confirm an account exists (Crosswork answers the same 'Invalid credentials' for an unknown username and a wrong password) and to see which role (PolicyId, e.g. 'admin') and device access groups (e.g. 'ALL-ACCESS') an account carries. The platform returns a dict keyed by username with PascalCase fields; this tool flattens it to a list and never returns the Password field.
Returns: str: Markdown listing, or JSON: {"count": int, "items": [{"username": str, "role": str, "first_name": str, "last_name": str, "status": str, "device_access_groups": [str, ...]}, ...]} On failure: "Error: " (403 -> the configured account lacks the user-administration privilege).
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | 'markdown' for human-readable output, 'json' for complete data. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/non-destructive, and the description reinforces that while adding non-obvious traits: the Password field is never returned, the platform's PascalCase dict is flattened to a list, and a 403 indicates the configured account lacks user-administration privilege. These are genuinely useful behaviors not present in structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then usage, then returns and failure modes in labeled blocks. The Returns section is fairly long, but every element (count/items field names, error prefix) carries information an agent would otherwise have to guess.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description fully covers return shape, field names, failure string format, and the 403 case, so an agent can call and interpret results without further inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one optional parameter (response_format) and the schema already documents it at 100% coverage. The description nevertheless earns credit by tying each format to a concrete return shape in the Returns block, going beyond the schema's terse enum description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) plus resource (Crosswork user accounts) and enumerates the fields returned (role, status, device access groups). No sibling tool competes for this resource, so it is unambiguously distinguishable from the device/topology/provider listings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives two use cases: confirming an account exists (with a useful rationale about identical 'Invalid credentials' responses) and inspecting role/device access groups. It does not name alternatives or exclusions, but none exist among the siblings, so context is clear without them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_wait_for_device_reachableWait for Device to Become ReachableARead-onlyIdempotent
Poll a device until its reachability_state is CONN_STATE_REACHABLE.
Read-only convergence wait. Call it right after cnc_create_device (or after fixing credentials / admin state) instead of polling cnc_get_device in a loop. Pass exactly one of uuid / host_name. A new device typically moves UNKNOWN/CHECKING -> REACHABLE within a minute or two once it is attached to a Data Gateway.
Returns: str: On success: "Device () is reachable after Ns." plus a JSON summary (reachability_state, operational_state, dg_name, errors). On timeout (NOT an error): "Not reachable yet after Ns; current reachability_state=..., operational_state=..." plus the same summary — call again to keep waiting, or inspect 'errors' / dg_name. "Error: ..." only for API failures or when no device matches.
| Name | Required | Description | Default |
|---|---|---|---|
| uuid | No | Device uuid (from cnc_create_device's impacted_objects). | |
| host_name | No | Device host name, exact match (e.g. 'PE1'). | |
| timeout_seconds | No | How long to wait in total (e.g. 180). | |
| interval_seconds | No | Seconds between polls (e.g. 10). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds critical behavior beyond them: a timeout is explicitly NOT an error and the caller should re-invoke, the typical UNKNOWN/CHECKING -> REACHABLE timeline, and the shape of both success and timeout responses. This is exactly the kind of convergence-wait context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then usage, then return semantics in a logical order. Slightly long, and the Returns block partially restates the output schema, but every line (notably timeout-is-not-an-error) carries information. Minor redundancy is the only deduction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema and full annotation coverage present, the description still supplies the missing semantic layer: mutual-exclusive selector params, timeout semantics, and expected device-state transitions. Nothing an agent needs to invoke and interpret the result is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds a real constraint the schema cannot express: pass exactly one of uuid / host_name. It also ties uuid back to cnc_create_device's impacted_objects. The timeout/interval parameters are left to the schema, which is adequate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action and target: 'Poll a device until its reachability_state is CONN_STATE_REACHABLE.' It names the exact terminal state and, via the usage line, distinguishes itself from plain polling with cnc_get_device. An agent can select it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('right after cnc_create_device', 'after fixing credentials / admin state') and names the alternative it replaces ('instead of polling cnc_get_device in a loop'). It also states the mutual-exclusion rule ('Pass exactly one of uuid / host_name').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cnc_wait_for_inventory_jobWait For Inventory JobARead-onlyIdempotent
Poll an inventory job until it reaches a terminal state or the timeout elapses.
Read-only. Use it right after a write that came back JOB_RUNNING instead of calling cnc_get_inventory_job in a loop. Terminal states are the verified ones: JOB_COMPLETED and JOB_COMPLETED_WITH_WARNING (both successes; the latter carries an advisory, e.g. a no-op or partially applied write), and JOB_FAILED / JOB_CANCELLED / JOB_ABORTED (failures). Any other state (JOB_RUNNING or an in-progress state not seen before) keeps the tool polling until the timeout.
Returns: str: "Inventory job completed after s." followed by the job JSON (with "impacted_objects" parsed from "impacted") on success; for JOB_COMPLETED_WITH_WARNING the line also carries "Warning: " and the JSON gains a "warning" key. A timeout is NOT an error: "Inventory job not finished after s; current state: JOB_RUNNING. ..." followed by the job JSON — call again to keep waiting. "Error: Inventory job failed (job , state JOB_FAILED): " when the job ended unsuccessfully; "Error: No inventory job with id ..." when the id matches nothing; other API failures: "Error: ...".
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Inventory job id to wait for (e.g. '0f6c1a2e-...'). | |
| timeout_seconds | No | Give up after this many seconds (e.g. 120). | |
| interval_seconds | No | Seconds between polls (e.g. 5). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive behavior, but the description adds substantial behavioral detail: terminal states, warning semantics, timeout-as-non-error handling, and error return shapes. Nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence is front-loaded and the usage guidance is clear. The returns block is lengthy and partly overlaps the output schema, but it earns its place by explaining timeout and warning behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an asynchronous polling tool with annotations, a full input schema, and an output schema, the description is complete enough to call correctly. It covers usage context, terminal states, timeout behavior, and error semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so job_id, timeout_seconds, and interval_seconds are already documented in the schema. The description alludes to timeout behavior but does not add syntax, defaults, or constraints beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: poll an inventory job until terminal state or timeout. It distinguishes itself from the sibling cnc_get_inventory_job by explicitly saying to use this instead of calling that tool in a loop.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance: right after a write returns JOB_RUNNING, rather than polling cnc_get_inventory_job manually. It also clarifies that timeout is not an error and that the caller should call again to keep waiting.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
19 tool updates
v0.1.0- First observed
cnc_get_credential_profile - First observed
cnc_get_device - First observed
cnc_get_device_collection_summary - First observed
cnc_get_inventory_job - First observed
cnc_get_provider - First observed
cnc_get_topology - First observed
cnc_get_topology_summary - First observed
cnc_list_alarms - First observed
cnc_list_applications - First observed
cnc_list_credential_profiles - First observed
cnc_list_devices - First observed
cnc_list_inventory_jobs - First observed
cnc_list_providers - First observed
cnc_list_tags - First observed
cnc_list_topology_links - First observed
cnc_list_topology_nodes - First observed
cnc_list_users - First observed
cnc_wait_for_device_reachable - First observed
cnc_wait_for_inventory_job
TDQS
Scored across 19 tools
Each tool targets a distinct resource and action, and descriptions explicitly partition the topology tools (cnc_get_topology for adjacency vs cnc_list_topology_nodes/cnc_list_topology_links for tabular attributes). The only mild overlap is between the general topology getter and the two specialized topology listers, but the descriptions give clear guidance on when to use each.
Every tool follows the same cnc_<verb>_<noun> convention (list_*, get_*, wait_for_*), with no camelCase or mixed-style deviations. The pattern is fully predictable across all 19 tools.
19 tools is on the heavier side but each covers a genuinely distinct domain (devices, credentials, providers, topology, tags, users, applications, alarms, jobs) with read variants plus helpful summary/wait helpers. It feels slightly large but well-scoped rather than padded.
Read coverage is broad and coherent: devices, credentials, providers, topology, tags, users, applications, alarms and inventory jobs all have list/get surfaces, plus convergence-wait helpers. The notable gap is the complete absence of write operations (create/update/delete) even though descriptions reference them, but the surface appears intentionally read-only.
Maintenance
Related MCP Connectors
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Unified API to query AWS, GCP, Azure and generate Terraform/CLI execution kits for AI agents.
Protocol-native energy infrastructure orchestration for AI data centers. Provides 46 MCP tools across 8 grid protocols (IEC-61850, DNP3, Modbus, OCPP, OpenADR, IEEE 2030.5, IEC 60870-5-104, ICCP) with 5 core API primitives: connect, dispatch, settle, comply, and intel. Enables AI agents to programmatically interact with substations, grid interfaces, and energy assets for real-time workload-grid coordination.
Manage CallKaro voice agents, phone numbers, call queues, and place single or batch AI calls.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables AI-powered network automation through natural language interactions with Cisco NSO, providing access to device management, configuration retrieval, sync operations, and service orchestration via the RESTCONF API.94MIT
- AlicenseNot gradedqualityDmaintenanceProvides AI assistants with direct access to multi-vendor network devices for tasks like configuration management, health checks, and topology discovery through 35 specialized tools. It enables natural language control over platforms including Cisco, Juniper, and Nokia using SSH, NETCONF, and SNMP protocols.11MIT
- AlicenseNot gradedqualityAmaintenanceEnables LLMs to interact with network devices via Cisco RADKit, supporting inventory discovery, device attribute inspection, CLI command execution, and SNMP queries.11Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to interact with the Netdisco network management platform through its complete REST API, supporting device inspection, port queries, VLAN searches, and job management.MIT