# R1-MCP documentation
---
---
> MCP server (Claude connector) for RUCKUS One. Google sign-in; calls any of the 1500+ R1 API endpoints, plus floorplan maps, venue and config copy, backups, live device CLI, webhook analytics and MOP workflows.
---
---
# What is R1-MCP?
Source: https://docs.neuralconfig.com/r1-mcp/
R1-MCP is a hosted MCP server that connects Claude to **your** RUCKUS One
tenant. You sign in with Google, save your R1 API credentials, and add one URL
to Claude as a custom connector. From then on you can ask Claude about your
network in plain language, and it works against the live R1 API on your behalf.
It covers the whole API — all 1500+ RUCKUS One endpoints — plus the RUCKUS One
user guide, FastIron documentation for ICX switches, and a set of guided
workflow prompts.
## What it does for you
R1-MCP turns day-to-day RUCKUS One work into a conversation:
- **Inventory and health** — venues, APs, switches and clients, what is online,
what is down, and why.
- **RF and clients** — airtime, channel plans, co-channel candidates, a single
client's disconnects, and roaming between APs.
- **Switch configuration** — FastIron syntax checked against the command
reference for your firmware train, applied through RUCKUS One, and live CLI
on switches and APs when you need the console.
- **Copy and backup** — snapshot a venue's configuration, copy it into another
venue or tenant, and keep encrypted backups you can restore.
- **Floor maps** — your APs placed on the venue floorplan with coverage,
roaming and co-channel findings drawn on it.
- **Documentation** — as-built packets, topology diagrams, and answers drawn
from the RUCKUS One user guide.
Your R1 API credentials set the limit on all of it: R1-MCP can do exactly what
your RUCKUS One API client is allowed to do.
## What you can ask for
Some things people actually use it for:
- *"What's the RF health at the Charleston venue over the last 24 hours?"*
- *"Find the client with MAC `aa:bb:…` and tell me why it keeps disconnecting."*
- *"Draw me an L2 topology diagram of this venue."*
- *"Build an as-built documentation packet for this site."*
- *"Which APs have the worst airtime utilization this week?"*
- *"Generate the FastIron config to add VLAN 200 tagged on ports 1/1/1-1/1/8."*
The [MCP prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) in Claude's **+** menu package the bigger
ones as guided workflows.
## Beyond the REST API
Optional [features](https://docs.neuralconfig.com/r1-mcp/reference/features/) extend the surface well past R1's REST
endpoints:
| Feature | What it adds |
|---|---|
| **ICX** | Full-text search over FastIron command reference and config guides, plus an end-to-end switch config workflow |
| **Webhooks** | An inbound webhook receiver plus incident, client, anomaly, and roaming analytics |
| **Edge** | RUCKUS Edge documentation search |
| **Write Guard** | Confirm-before-write on direct API calls (`call_r1` and `call_r1_gql`) |
| **Live CLI** | A held console session to devices, and MOP author / record / replay |
| **Test Bed** | Capture, plan, and apply lab hardware swaps between saved config sets |
| **[Copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/)** | Snapshot a venue's config and copy it into another venue or another tenant |
| **[Floorplan](https://docs.neuralconfig.com/r1-mcp/features/floorplans/)** | Venue floor maps with APs placed, plus coverage, client, roaming and co-channel layers, rendered as an image |
Plus password-gated Early Access features:
[GraphQL](https://docs.neuralconfig.com/r1-mcp/features/graphql/) against the RUCKUS analytics services, on-LAN ground
truth via [Probe MCP](https://docs.neuralconfig.com/r1-mcp/features/probe/),
[Data Studio](https://docs.neuralconfig.com/r1-mcp/features/data-studio/) chart building, the
[Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/), and
[VLAN probe](https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/) — wireless VLAN reachability tested
through a temporary SSID, started from the r1-mcp companion extension.
## How it reaches the whole API
Most MCP servers expose one MCP tool per API operation. With 1500+ endpoints
that would be unusable — no model can pick sensibly from a list that long, and
the tool definitions alone would swamp the context window.
R1-MCP instead exposes exactly **one** MCP tool, `code_mode`. Inside it, Claude
writes small TypeScript programs against an `r1` object that can *discover*
endpoints and *call* them. So instead of choosing from 1500 tools, Claude
searches the API index, reads the endpoint's schema, and calls it — the same
way you would with the docs open.
That code runs in a sandboxed V8 isolate on Cloudflare, with your credentials
applied server-side. Read [How code mode
works](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/) for the mechanics.
## Getting started
1. [Sign in and add your R1 credentials](https://docs.neuralconfig.com/r1-mcp/setup/getting-started/)
2. [Connect it to Claude](https://docs.neuralconfig.com/r1-mcp/setup/connecting-claude/)
3. Try one of the [prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) or an [example](https://docs.neuralconfig.com/r1-mcp/examples/)
## Explore the docs
### Set up
- [Getting started](https://docs.neuralconfig.com/r1-mcp/setup/getting-started/): Sign in with Google, add your RUCKUS One API credentials, test the connection, and get your MCP URL.
- [Connecting to Claude](https://docs.neuralconfig.com/r1-mcp/setup/connecting-claude/): Add R1-MCP as a custom connector — the MCP URL, the OAuth consent, and what to do when it doesn't appear.
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/): Manage several RUCKUS One tenants from one account, and tell Claude which one to work against.
### How it works
- [How code mode works](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/): Why R1-MCP exposes one MCP tool instead of 1500, and how Claude discovers an endpoint before calling it.
- [Security model](https://docs.neuralconfig.com/r1-mcp/concepts/security/): Where your credentials live, how tokens are minted server-side, and what Claude can and cannot see.
### Reference
- [Core tools](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/): The tools every account gets — API discovery, calling any RUCKUS One endpoint, and documentation search.
- [Workflow prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/): The 18 guided workflows in Claude's + menu, from RF health to as-built documentation.
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/): Every optional feature, what it adds, and how to turn it on for your account.
- [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/): The 20 curated documents R1-MCP ships, and the get_reference tool that searches them.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): The run budget, per-user caps on stored artifacts, event retention windows, and what each limit does when you hit it.
### Feature guides
- [ICX switches](https://docs.neuralconfig.com/r1-mcp/features/icx/): Search the FastIron command reference by firmware train, and run the end-to-end switch configuration workflow.
- [Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/): Run real commands on switches and APs, then author, record, and replay MOPs and test plans.
- [Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/): Receive RUCKUS One events, and query incident, client, anomaly, and roaming analytics built from them.
- [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/): Confirm-before-write on direct API calls — what counts as a write, what it does not cover, and why production tenants want it.
- [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/): Capture, plan, and apply lab hardware swaps between saved configuration sets.
- [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/): Snapshot a venue's configuration and copy it into another venue or tenant — plan, run, verify, undo.
- [What a venue copy carries](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/): The per-domain support matrix: which configuration a copy moves, and which it leaves behind.
- [Copying one object](https://docs.neuralconfig.com/r1-mcp/features/element-copy/): Move a single WLAN, switch profile, or ethernet-port profile — with everything it depends on — to another tenant.
- [Venue backups](https://docs.neuralconfig.com/r1-mcp/features/backups/): Keep a venue's configuration indefinitely and encrypted, then restore it in place, as a new venue, or into another tenant.
- [Floorplans and floor maps](https://docs.neuralconfig.com/r1-mcp/features/floorplans/): Read a venue's floorplans with every AP and switch placed, and render a floor as an image with findings attached.
- [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/): The layers you can draw on a floor — clients, roaming, co-channel, predicted coverage, AP failure impact — and what each one can and cannot tell you.
- [The roam matrix](https://docs.neuralconfig.com/r1-mcp/features/roam-matrix/): How clients move between your APs, pair by pair: signal change, fast-roam share, placement concerns, and how to read it on a floor.
- [Location-based services (LBS)](https://docs.neuralconfig.com/r1-mcp/features/lbs/): Measured client positions, Locate, airtime and devices heard: what LBS needs, how a source is set up, and what it keeps.
- [GraphQL API support](https://docs.neuralconfig.com/r1-mcp/features/graphql/): Early Access. Query the four RUCKUS AI GraphQL services, and why introspection is unavailable.
- [Probe — on-LAN ground truth](https://docs.neuralconfig.com/r1-mcp/features/probe/): Early Access. Reconcile the RUCKUS One inventory against what a probe actually sees on the wire.
- [Data Studio dashboards](https://docs.neuralconfig.com/r1-mcp/features/data-studio/): Early Access. The 16 ds_* tools for building charts and dashboards from your network data.
- [Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/): Early Access. A browser page streaming a watched client's events, plotting RSSI, SNR, and Tx live.
- [VLAN probe](https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/): Early Access. Test whether each VLAN is reachable over wireless by putting up a temporary SSID and running Service Guard, then tearing it all down.
### More
- [Examples](https://docs.neuralconfig.com/r1-mcp/examples/): Worked examples of asking Claude to do real RUCKUS One work end to end.
- [Troubleshooting](https://docs.neuralconfig.com/r1-mcp/troubleshooting/): Failed connection tests, connector authorization loops, missing tools, 401s and 429s.
## How your credentials are handled
Your R1 client secret is encrypted at rest, decrypted only when minting a
RUCKUS token, and never sent to Claude or included in any model context. See
[Security model](https://docs.neuralconfig.com/r1-mcp/concepts/security/).
---
# Getting started
Source: https://docs.neuralconfig.com/r1-mcp/setup/getting-started/
Three steps: sign in, save your RUCKUS One credentials, add the connector to
Claude.
## 1. Sign in
Go to [r1-mcp.lanpulse.com](https://r1-mcp.lanpulse.com) and sign in with
Google. That Google account is your R1-MCP identity — the same account backs
both the web dashboard and the Claude connector.
Tick the Terms of Service checkbox first: sign-in is refused without it. If the
terms change later, you'll be asked to accept them again before you can change
connections or re-authorize the Claude connector.
## 2. Add a RUCKUS One connection
In the dashboard's **RUCKUS One connections** card, click **Add connection**
and fill in your R1 API credentials:
| Field | Where it comes from |
|---|---|
| **Label** | Your own name for this tenant, e.g. "Acme Production". Must be unique among your connections |
| **Environment (region)** | United States (North America), Europe, or Asia — must match where your tenant lives |
| **Client ID** | From your RUCKUS One tenant's API credentials |
| **Client secret** | Same place. Write-only — once saved it is never shown again |
| **Token URL** | Filled in for the region you picked (`https://api.ruckus.cloud/oauth2/token/{tenantId}` for the US). Leave it as is unless RUCKUS told you otherwise |
| **Tenant ID** | Your R1 tenant identifier. The form marks it optional, but the default token URL needs it — `{tenantId}` is filled from this field |
When you edit a saved connection, leave the secret blank to keep the stored
one. Changing the **Client ID** or **Token URL** needs the secret re-entered.
### Getting R1 API credentials
In RUCKUS One, create an API client under your tenant's administration
settings. You need the client ID, the client secret, and your tenant ID.
R1-MCP uses the OAuth2 `client_credentials` grant, so no user-interactive
RUCKUS login is involved.
The credential's permissions in R1 are the ceiling on what Claude can do —
R1-MCP cannot exceed them. If you want a read-only experience, issue a
read-only API client.
One exception to plan for: opening a live CLI session on an **AP** needs a
read-write API client — RUCKUS One refuses to issue an AP console token to a
read-only one. Switch CLI works with either.
### Regions
The region selects which RUCKUS One API host your calls go to:
| Region | API host |
|---|---|
| US | `api.ruckus.cloud` |
| Europe | `api.eu.ruckus.cloud` |
| Asia | `api.asia.ruckus.cloud` |
Picking the wrong region is the most common setup failure — the credentials are
valid but the tenant isn't there.
## 3. Test the connection
Click **Save**, then **Test** on the new connection's row. This mints a real
RUCKUS token with your credentials, so a pass means the whole chain works:
client ID, secret, region, and tenant ID.
A pass reads `Connection OK — minted an R1 token`. A failure reads
`Test failed:` followed by an error code and detail.
If it fails, see [Troubleshooting](https://docs.neuralconfig.com/r1-mcp/troubleshooting/#connection-test-fails).
## 4. Copy your MCP URL and connect Claude
Copy the MCP URL from the dashboard, then follow
[Connecting to Claude](https://docs.neuralconfig.com/r1-mcp/setup/connecting-claude/).
The URL is the same for every user — what identifies *you* is the OAuth token
Claude obtains when it connects, which is bound to your account.
## 5. Try it
Ask Claude something concrete:
> List my RUCKUS One venues.
Then something that needs discovery:
> How many APs are online at each venue, and which ones are down?
If it works, move on to the [prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) — they package the
higher-value workflows.
## Optional: turn on features
The default install covers the R1 REST API and the user guide. Everything else
— ICX documentation, webhook analytics, live CLI, test beds — is opt-in per
user with no password. See [Features](https://docs.neuralconfig.com/r1-mcp/reference/features/).
## Multiple tenants
If you manage more than one RUCKUS One tenant, add each as its own connection
and tell Claude which one to use. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/).
---
# Connecting to Claude
Source: https://docs.neuralconfig.com/r1-mcp/setup/connecting-claude/
R1-MCP is a **remote** MCP server. There is nothing to install locally — you
add one URL as a custom connector and authorize it.
## Add the connector
1. Copy your MCP URL from the
[R1-MCP dashboard](https://r1-mcp.lanpulse.com) —
`https://r1-mcp.lanpulse.com/mcp/`.
2. In Claude, go to **Settings → Connectors → Add custom connector**.
3. Paste the URL and add it.
4. Claude opens a consent page. Click **Allow**.
5. The connector shows as connected, and `code_mode` appears in Claude's tools.
## What the consent flow is doing
R1-MCP uses OAuth 2.1 with Dynamic Client Registration and PKCE:
1. Claude registers itself as an OAuth client automatically.
2. You are sent to R1-MCP to authorize, which requires your **Google session**
— if you aren't signed in, you'll be asked to sign in first.
3. R1-MCP issues Claude an access token bound to your user account. Access
tokens last one day; Claude renews them with a 90-day rotating refresh token,
so you don't have to re-authorize.
That token is what makes the single shared MCP URL personal: every request
Claude makes carries it, and R1-MCP resolves it to your account and your
RUCKUS credentials.
Tokens are stored hashed. R1-MCP never holds a raw copy of a token it issued.
## Where it works
Any Claude surface that supports custom connectors — Claude Desktop, Claude on
the web, and Claude Code. The [prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) appear in the **+**
menu on surfaces that support MCP prompts.
## Verifying it's working
Ask Claude:
> Using R1-MCP, list my venues.
If the connector is live but not authorized, Claude will say it can't
authenticate rather than returning an empty list — that distinction is useful
when debugging.
## When authorization loops or fails
- **Redirect loop / "too many redirects"** — usually a browser cookie problem
during the Google hop. Try in a normal (non-private) window, allow cookies
for `r1-mcp.lanpulse.com`, and re-add the connector.
- **Every call fails authentication** — the token was revoked or the
connector was added before you finished signing in. Remove the connector and
add it again.
- **Connected, but every call errors about credentials** — the MCP side is fine
and the *RUCKUS* side isn't. Go back to the dashboard and re-run **Test** on
the connection. See [Troubleshooting](https://docs.neuralconfig.com/r1-mcp/troubleshooting/).
## Revoking access
Remove the connector in Claude to stop Claude calling it. To revoke access on
the server side, click **Disconnect all Claude connectors** on the R1-MCP
dashboard: it revokes every access and refresh token issued to any of your
Claude clients. Revoking is immediate — the next request Claude makes fails the
bearer check.
Removing the connector does **not** delete your saved RUCKUS credentials; use
the dashboard to delete a connection if that's what you want. Deleting your
**last** connection also disconnects every Claude connector, the same as the
button above.
---
# Multiple RUCKUS One connections
Source: https://docs.neuralconfig.com/r1-mcp/setup/connections/
If you manage more than one RUCKUS One tenant — an MSP with several customers,
or a production and a lab tenant — you can save each as its own **connection**
and tell Claude which one to work against.
## Adding connections
The **RUCKUS One connections** card in the [dashboard](https://r1-mcp.lanpulse.com) is the
full manager. Each connection carries:
- A **label** you choose — this is what you'll say to Claude, so make it
memorable and unambiguous.
- Client ID, client secret (write-only), region, token URL, tenant ID.
- **Enabled** / disabled, and a **default** flag. The first connection you add
becomes the default.
Per-row actions: **Test**, **Edit**, **Disable** / **Enable**, **Make default**,
**Delete**. Labels must be unique among your connections.
## Choosing a connection in conversation
`list_connections` shows Claude your enabled connections — id, label, tenant
id, region, and which is default. Never secrets. So you can say:
> Using the Acme Production connection, list the venues.
Resolution rules for `call_r1` and the other tools that take a `connection`
argument:
| Situation | What happens |
|---|---|
| Connection named explicitly | That connection is used — if it's enabled |
| Named but disabled | Rejected with `connection_disabled` |
| Named but unknown | Rejected with `unknown_connection` |
| Not named, exactly one enabled | That one is used |
| Not named, more than one enabled | Rejected with `connection_required`, listing the choices |
| Not named, connections saved but all disabled | Rejected with `no_enabled_connection` |
| No connections saved at all | Rejected with `no_credentials` |
The fifth row is the important one: with several tenants live, R1-MCP will
**not** guess. It asks. An ambiguous call against the wrong customer's tenant
is not a mistake worth being convenient about.
A name matches exactly — the label, including its capitalization, or the
connection id. "acme production" does not match "Acme Production".
### Where the default connection is used
**`device_cli` is the exception to the table.** When you don't name a
connection, a live CLI session opens against your **default** connection
instead of asking — unattended MOP replays have nobody to answer the question.
That is what the default flag is for; for the tools in the table above it
changes nothing. A disabled default is refused (`connection_disabled`), never
swapped for another connection.
## Tenant isolation
RUCKUS tokens are cached per user *and per connection*. Tenant A's bearer token
can never be served for a tenant B call — they're separate cache entries by
construction, not by a check that could be forgotten.
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) reinforces this: the connection id is part
of the confirmation fingerprint, so a token you approved for tenant A cannot be
replayed against tenant B, and the confirmation preview names the target
tenant explicitly.
## Disabling versus deleting
**Disable** keeps the credentials but takes the connection out of circulation —
it stops appearing to Claude and any call naming it is rejected. Useful for a
customer you've paused work on.
:::caution[Disabling the default also stops device_cli]
A `device_cli` session opened without a `connection` uses your default
connection, and if that connection is disabled it is refused with
`connection_disabled` — it never falls back to another connection. Before
disabling your default, use **Make default** on another connection so unattended
MOP replays keep working.
:::
**Delete** removes it. The stored secret goes with it; there is no recovery.
If you delete the default, the oldest remaining connection becomes the default.
:::danger[Deleting your only connection disconnects Claude]
Deleting your **last** connection also revokes every access and refresh token
issued to your Claude connectors — every connected Claude client stops working
and has to be re-authorized. The dashboard warns you before it does this.
:::
## Good practice for MSPs
- Label by customer, not by environment — "Acme Production" beats "prod".
- Keep the default set to your least dangerous tenant — it is what
`device_cli` uses when no connection is named. There is always a default;
you can move it with **Make default** but not clear it.
- Enable [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) and read the tenant name in every
confirmation preview.
- Issue read-only R1 API clients for tenants where you only investigate — but
AP CLI needs a read-write one. On a read-only connection `device_cli` returns
`jwt_mint_forbidden` for an AP; name a read-write connection with `connection`.
A held CLI session keeps the connection it was opened with — naming another on
a later call returns `connection_mismatch`.
---
# How code mode works
Source: https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/
R1-MCP's `tools/list` returns exactly one tool: **`code_mode`**. Understanding
what happens inside it explains most of R1-MCP's behavior — including why it
sometimes takes a few seconds to answer a simple question.
## The problem it solves
RUCKUS One has more than 1500 API endpoints. Exposing one MCP tool per endpoint
would produce a tool list no model can choose from reliably, and tool
definitions large enough to crowd out the actual conversation.
## The approach
`code_mode` accepts a small TypeScript program. Inside that program, an `r1`
object provides primitives for discovering and calling endpoints. Claude writes
the program, R1-MCP runs it in a sandboxed V8 isolate, and only the *result*
comes back into the conversation.
The payoff: Claude can loop, filter, and join across many API calls in one
round trip, and only the answer — not thousands of intermediate JSON rows —
enters the context window.
## The workflow
A typical request follows this path:
1. **Orient** — `r1.list_tag_groups()` / `r1.list_tags()` to find the right
corner of the API taxonomy.
2. **Search** — `r1.search_endpoints("...")` or
`r1.list_endpoints_by_tag(...)` against a bundled index of every operation.
Results carry hints about the request body, response shape, pagination
style, and required parameters, so a follow-up lookup is usually
unnecessary.
3. **Read the details** — `r1.get_endpoint_details(...)` when the hints aren't
enough, returning the full schema plus any curated caveats.
4. **Call** — `r1.call_r1(...)` substitutes path parameters, builds the query
string, attaches your bearer token, and sends the request.
For "how do I…?" questions rather than "which endpoint?" questions, there's
`r1.search_docs(...)` — full-text search across the RUCKUS One Online Help, the
MSP Guide, and the Subscriptions & Licensing Guide, returning ranked snippets
with links to the source topic.
See [Core tools](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/) for the full list.
## Your credentials never leave the server
The program Claude writes runs on Cloudflare, not in Claude. When it calls
`call_r1`, R1-MCP mints a RUCKUS token server-side using your encrypted
credentials and attaches it. Claude sees the API response; it never sees your
client secret or your bearer token. See [Security model](https://docs.neuralconfig.com/r1-mcp/concepts/security/).
```mermaid
flowchart LR
claude["Claude writes the program"]
subgraph cf["Cloudflare (R1-MCP)"]
isolate["Sandboxed V8 isolate runs the program"]
secret[("Encrypted R1 credentials")]
end
r1["RUCKUS One API"]
claude -->|"code_mode(program)"| isolate
secret -->|"token minted server-side"| isolate
isolate -->|"call_r1 with bearer token"| r1
r1 -->|"API response"| isolate
isolate -->|"result only — never the secret or token"| claude
```
## Errors don't throw
`call_r1` never throws on an HTTP error. It returns a response object with
`ok`, `status`, and the body — so the program can inspect the failure and adapt
rather than dying. If Claude ever reports a specific R1 status code and error
body back to you, that's why.
## Retries
- **401** — exactly one automatic refresh-and-retry. Your RUCKUS token is
cached with a TTL just under its real expiry, so this is rare.
- **429** — automatically retried for idempotent methods (GET, PUT, DELETE),
honoring `Retry-After`, with the wait capped at **5 seconds** and at most
**2 retries**. **POST and PATCH are not auto-retried** unless explicitly opted
in, because replaying a create or a partial update is not safe.
- **406** — a few R1 resources reject the default `application/json` and name the
versioned media type they accept. The request is retried once with that
`Accept` header. If the 406 names no versioned type, it surfaces as-is.
Responses report how many retries happened.
## The run budget
Each `code_mode` run has a hard **30-second** wall-clock limit shared across
every API call it makes. Every `call_r1` response (and every `call_r1_gql` and
Data Studio call) carries a snapshot of it — calls made, total call time,
elapsed time, and the budget. At **20 seconds** that snapshot gains a warning
telling the program to return partial results and continue in a fresh run.
A run that reaches 30 seconds is stopped with a `timeout` error ("code_mode
exceeded its 30s wallclock limit"). Nothing resumes on its own — Claude has to
start a new run. Each individual RUCKUS One request also has its own
15-second timeout.
:::caution[After a timeout on a write, check before retrying]
Work a run already sent to RUCKUS One may still complete after the timeout. If
the run was making changes, confirm what landed before running it again — a
blind retry can apply a change twice.
:::
This is why a very broad request ("audit every venue") may come back in stages
rather than as one enormous answer. Asking for a narrower scope is usually
faster than asking for everything at once.
## Caching
Endpoint details are cached in three tiers — an in-memory LRU, a KV cache keyed
by spec version, and the full spec in object storage. The KV key includes the
spec version, so once a newer spec is deployed, entries cached from the old one
are never served.
## Which spec is live
The bundled API index records which RUCKUS consolidated OpenAPI spec it was
built from, and that metadata is surfaced to Claude at request time. If you
need to know exactly which spec version answered your question, ask — Claude
can see it.
R1-MCP does not pick up a new RUCKUS spec on its own. It checks once a day
whether RUCKUS has published a newer one and flags it to the service's
operator, but nothing is downloaded or applied until the operator rebuilds the
API index and redeploys. Until then, endpoint search and endpoint details come
from the spec currently deployed, so an endpoint RUCKUS has added since will not
show up.
## Notes on endpoints
`r1.save_endpoint_note(...)` lets you attach a short note to an endpoint — a
quirk the spec doesn't capture. Notes are private to you and resurface on
future `get_endpoint_details` calls for that endpoint, so a hard-won discovery
isn't lost. An admin can promote a note to be visible to everyone.
---
# Security model
Source: https://docs.neuralconfig.com/r1-mcp/concepts/security/
R1-MCP holds credentials to your RUCKUS One tenant, so how it handles them is a
fair question to ask before you connect it.
## Your R1 client secret
- **Encrypted at rest** with AES-256-GCM using a key derived via HKDF from a
Worker secret. The stored value is ciphertext.
- **Write-only in the dashboard** — once saved, it is never displayed again,
not even to you.
- **Decrypted only at token-mint time**, server-side, to obtain a RUCKUS bearer
token.
## What Claude can see
Claude writes the program that runs inside
[`code_mode`](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/), but that program executes on
Cloudflare, not in Claude. It calls `call_r1`, and R1-MCP attaches the bearer
token server-side.
So Claude sees **API responses**. It does not see your client secret, and it
does not see the RUCKUS bearer token.
`list_connections` returns id, label, tenant id, region, and the default flag —
deliberately never secrets.
## RUCKUS token lifecycle
Tokens are obtained with the OAuth2 `client_credentials` grant against your
region's token URL, and cached with a TTL set just under their real expiry. A
`401` triggers exactly one refresh-and-retry before the error surfaces.
Caching is keyed per user **and per connection**, so tokens for different
tenants are never interchangeable. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/#tenant-isolation).
## Two authentication flows, one identity
- **Web dashboard** — Google sign-in; the session cookie is stored as a hash,
never in the clear.
- **MCP connector** — OAuth 2.1 with Dynamic Client Registration and PKCE.
Claude registers as a client, your Google session authorizes it, and the
issued access token is stored **hashed** and bound to your user id.
Both resolve to the same account. Every MCP request is authenticated per user
before anything else happens; R1-MCP never holds a raw copy of a token it
issued.
The connector's access token also authenticates R1-MCP's HTTP APIs for native
clients and the r1-mcp companion extension (Console chat, floor maps, VLAN
probe). It grants what your account can do, nothing more. Floor map pages the
extension embeds use a separate launch token instead: read-only, one venue,
valid for 15 minutes.
## Your R1 permissions are the ceiling
R1-MCP can do exactly what your RUCKUS One API client is allowed to do — no
more. If you want a read-only experience, the reliable way to get one is to
issue a read-only API client in RUCKUS One, not to hope the model behaves.
(A read-only client cannot open AP CLI sessions — RUCKUS One issues AP console
tokens only to read-write clients.)
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) is a useful second layer on top of that,
not a replacement for it.
## Configuration R1-MCP stores for you
Some features keep a copy of your RUCKUS One configuration server-side: venue
[snapshots](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/), [backups](https://docs.neuralconfig.com/r1-mcp/features/backups/), and the
captured switch running-configs behind [test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/).
A venue's configuration is not innocuous — it can carry DPSK passphrases and
RADIUS shared secrets. So:
- **Snapshots and backups are encrypted at rest**, with the same envelope used
for your client secret, and are decrypted server-side only to diff them while
compiling a plan.
- **Test-bed configs are not in that envelope.** They are stored as full text
in a private storage bucket, under a per-account key prefix, because a
restore has to put back exactly what was captured.
- **No tool returns a configuration wholesale.** `venue_snapshot_get`,
`backup_list`, and `backup_get` return metadata only — venue, label, captured
domains, object counts, sizes. `config_diff` returns the changed lines of a
test-bed config (at most 400), and any line that looks like a credential is
replaced with `` — for example ``.
- **One export exists, and it bypasses Claude.** A test bed's archive download
carries each switch's full config text. It is served only to your signed-in
browser session and never passes through the model. Snapshots and backups
have no export path.
- **They are private to your account** and bounded — see
[Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/#stored-artifacts). Snapshots age out after
30 days; backups are retained until you delete them.
Write-only secrets are a related case worth knowing: where R1 masks a value on
read, R1-MCP never captured it in the first place. That is why a copy or restore
asks you to supply it at run time rather than reproducing it.
## What R1-MCP stores, and for how long
Everything R1-MCP keeps is tied to your account. This table lists what is
stored, whether it is encrypted, and when it goes away.
| What | Where | Encrypted | Kept |
|---|---|---|---|
| Your R1 **client secret** | Database | Yes (AES-GCM) | Until you delete the connection |
| RUCKUS **API bearer token** (minted from your secret) | Cache, keyed per connection | No | Until shortly before RUCKUS One expires it; dropped at once when you edit, disable or delete the connection |
| **Device CLI login token** (switch or AP console) | Cache, keyed per connection and device | No | At most **15 minutes**, regardless of the token's own lifetime |
| **Venue snapshots** | Private storage bucket | Yes | **30 days** |
| **Venue backups** | Private storage bucket | Yes | Until you delete them |
| **Test-bed switch configs** | Private storage bucket, per-account prefix | No | With the test bed — deleted after **365 days** untouched |
| **Floorplan images** mirrored from RUCKUS One | Private storage bucket, per-account and per-connection prefix | No | Not aged out. The oldest are deleted once you pass **50 per connection** |
| **Floor-map client list** (client MACs, hostnames, OS type, SSID, AP, signal) | Cache, per connection and venue | No | **15 minutes** |
| **Webhook events and derived client data** | Database | No | **7 to 365 days** depending on the event class — see [Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) and [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/) |
| **VLAN probe run records** | Database | No | **30 days**, longer while anything the run created is not yet confirmed deleted |
Some things are **never stored**:
- **The VLAN probe's temporary WLAN passphrase.** A random passphrase is generated
for each run, used once when the WLAN is created, and never written anywhere.
- **Write-only secrets R1 masks on read** — see [Your configurations](#configuration-r1-mcp-stores-for-you) above.
## Code execution
The TypeScript Claude writes runs in a sandboxed V8 isolate on Cloudflare, with
no filesystem and no network access beyond the `r1` primitives R1-MCP provides:
outbound `fetch()` and `connect()` are blocked by the Workers runtime. It cannot
reach anything you haven't given it a tool for.
## Revoking access
- **Disconnect all Claude connectors** on the dashboard revokes every access
and refresh token issued to your Claude clients — effective immediately; the
next request fails the bearer check. Removing the connector in Claude stops
Claude calling, but a token it already holds stays valid until it expires
(access tokens last one day).
- **Disable or delete a connection** to cut off a specific tenant. Deleting
removes the stored secret permanently, and deleting your last connection also
disconnects every Claude connector. A disabled connection is not used
anywhere — including by `device_cli` when it is your default and no connection
is named, which is refused instead. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/#disabling-versus-deleting).
- **Rotate the R1 client secret** in RUCKUS One and update the connection. The
old secret stops working wherever it was.
## Notes and shared data
Endpoint notes you save with `save_endpoint_note` are private to your account.
An administrator can promote a note to global visibility — so treat notes as
API knowledge, not as a place for tenant-specific detail.
---
# Core tools reference
Source: https://docs.neuralconfig.com/r1-mcp/reference/core-tools/
These are the tools every user gets, with no feature flags enabled: they let
Claude find any RUCKUS One API operation, call it on your tenant, search the
RUCKUS One guides, choose between your tenants, and run common multi-step jobs
such as RF analysis and topology diagrams. You don't call them directly — Claude
does, from inside [`code_mode`](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/) — but
knowing what exists helps you ask for the right thing.
## Discovery primitives
| Tool | What it does |
|---|---|
| `list_tag_groups` | Lists the top-level groups of the RUCKUS One API tag taxonomy |
| `list_tags` | Lists tags within the taxonomy — the way into a subject area |
| `search_endpoints` | Keyword search across every operation in the bundled API index |
| `list_endpoints_by_tag` | Every operation carrying a given tag |
| `get_endpoint_details` | Full schema for one operation, plus curated caveats and any saved notes |
| `save_endpoint_note` | Attach a note to an endpoint — private to you, resurfaced on later lookups. 5–500 characters, at most 10 per endpoint and 500 in total (`too_many_notes_for_endpoint`, `too_many_notes`). You can't delete your own notes yet — ask [support](https://support.neuralconfig.com/r1-mcp?from=docs) if you reach the limit |
`search_endpoints` results include hints — expected request body, response
shape and fields, pagination style, required parameters — so Claude usually
gets what it needs without a second round trip. Search covers body and response
property names too, so a query like "create venue with address" ranks endpoints
whose body actually has an `address` field.
## Calling the API
**`call_r1`** is the workhorse. It substitutes `{pathParam}` placeholders,
builds the query string, attaches your bearer token, and sends the request.
Behavior worth knowing:
- HTTP errors return a response object rather than throwing — `ok` and `status`
tell the story.
- A `401` triggers exactly one refresh-and-retry.
- A `429` auto-retries for GET, PUT, and DELETE honoring `Retry-After`. POST
and PATCH are not replayed automatically unless the call sets
`retryOn429: true`.
- Every response reports retry count and contributes to the run's
[budget](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget).
## Documentation search
**`search_docs`** is full-text, BM25-ranked search over **three** RUCKUS One
guides — **1,776 indexed sections** in total:
| Guide | Sections | Topics |
|---|---|---|
| RUCKUS One Online Help | 1,505 | 544 |
| RUCKUS One MSP Guide | 240 | 78 |
| RUCKUS One Subscriptions & Licensing Guide | 31 | — |
Results carry the section path, title, and a snippet. The two HTML-sourced
guides also carry a **link to the live topic**, so an answer can cite where it
came from; the licensing guide is PDF-sourced and cites a page number instead.
Use it when the question is "how does RUCKUS One do X?" rather than "which
endpoint returns X?" — and note that MSP and licensing questions are in scope,
not just the main user guide.
## Connections
**`list_connections`** returns the R1 connections enabled on your account —
`{id, label, tenantId, region, isDefault}`, never secrets — so Claude can pick a
tenant when you have more than one. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/).
## Task helpers
These compose the primitives above into common multi-call workflows, so Claude
doesn't have to reinvent them each time:
| Helper | What it does |
|---|---|
| `list_venue_wlans` | Every WLAN at a venue, resolved across the calls that takes |
| `await_request` | Polls an asynchronous R1 operation to completion |
| `analyze_rf` | RF analysis for a venue, or single-AP airtime when given an AP MAC |
| `diagram_topology` | Builds layered L1 (cabling), L2 (forwarding), and L3 (routing) diagrams of a venue, each with its own confidence note — Mermaid by default, or D2 and draw.io |
The helper catalog is generated from the live tool registry, so it's always in
sync with what the server actually offers.
Many R1 writes are asynchronous: the call returns `202` with a request id, and
the work happens afterwards. `await_request` polls that id until it reaches a
terminal state, for **60 seconds** by default (settable from 1 to 120). R1
answers **404** for an activity it has accepted but not yet made resolvable, so a
404 means *not yet* rather than *failed* — the poll continues. See
[Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/#a-404-while-awaiting-is-not-a-failure).
:::caution[A long wait outlives the run]
A single `code_mode` run stops at **30 seconds**, so a wait much longer than
about 25 seconds is cut off by the run budget before `await_request`'s own
timeout can report `timed_out`. For a slow operation, keep each wait short and
poll again in a fresh call.
:::
## Beyond the core
Everything else — FastIron docs, webhook analytics, live CLI, test beds,
[venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/), [GraphQL](https://docs.neuralconfig.com/r1-mcp/features/graphql/),
[probe](https://docs.neuralconfig.com/r1-mcp/features/probe/), [Data Studio](https://docs.neuralconfig.com/r1-mcp/features/data-studio/) — is behind a
[feature flag](https://docs.neuralconfig.com/r1-mcp/reference/features/) you enable per account.
Enabling **any** feature also adds `get_reference`, which reads the curated
reference documents that ship with the server — verified CLI patterns, GraphQL
schemas, and workflow playbooks. The listing is filtered to the features you
have on. See [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/).
---
# Workflow prompts
Source: https://docs.neuralconfig.com/r1-mcp/reference/prompts/
R1-MCP serves a set of curated **MCP prompts** — guided workflows that appear
in Claude's **+** menu. Each one is a well-tested sequence for a job people
actually do, so you don't have to describe the whole procedure yourself.
You only see prompts for [features](https://docs.neuralconfig.com/r1-mcp/reference/features/) you have enabled.
## Always available
| Prompt | What it does |
|---|---|
| **Explore the RUCKUS One API** | Orientation — find your way around the API taxonomy and try calls |
| **RF health check (venue)** | RF assessment for a venue over a time window |
| **Venue documentation packet (as-built)** | Assembles an as-built document for a site; you choose which sections |
| **Topology diagrams (L1 / L2 / L3)** | Network diagrams at the layers you pick |
| **Client deep-dive troubleshooting report** | Everything about one client MAC — connections, roams, incidents |
| **Configuration & state audit** | Audits configuration and current state across a scope you set |
## Webhooks feature
Requires the **webhooks** feature.
| Prompt | What it does |
|---|---|
| **Diagnose a client that can't connect** | Stitches RADIUS auth logs and Wi-Fi association events into one verdict for a client MAC, with the most likely fix |
| **Network health check (incidents)** | Health assessment driven by incident data |
| **Hunt infrastructure anomalies** | Looks for anomalies across infrastructure |
| **Admin / change audit trail** | Who changed what, and when |
| **Live reproduce-and-catch (watch & capture)** | Arms watches on a client or AP, then captures what happens while you reproduce a problem |
## ICX feature
| Prompt | What it does |
|---|---|
| **ICX BGP-EVPN fabric build / validate** | Builds or validates a BGP-EVPN fabric on ICX switches |
## Live CLI feature
| Prompt | What it does |
|---|---|
| **POC / QA test plan (author → run → report)** | Writes a test plan against an objective, runs it, and reports |
| **Deep-dive an ICX switch / fleet (live CLI)** | Investigates a switch or fleet against a symptom, on the live console |
## Test Bed feature
| Prompt | What it does |
|---|---|
| **Swap lab hardware to a saved test bed** | Moves lab hardware between saved configuration sets |
## Floorplan feature
Requires the **floorplan** feature. See [Floorplans](https://docs.neuralconfig.com/r1-mcp/features/floorplans/).
| Prompt | What it does |
|---|---|
| **Audit AP placement on a floor plan** | Draws a venue floor with every AP on it and audits the placement in real metres — unplaced APs, APs left at the origin, pairs too close together, isolated APs, and channel-overlap candidates confirmed or dismissed by distance. Read-only |
| **Map roaming on a floor** | Draws the AP-to-AP roam matrix on the floor and reads it against the real distances — busy pairs far apart, ping-pong pairs, full re-authentications, where clients first appear, and optionally one client's trail |
## VLAN probe feature (Early Access)
Requires the **vlan_probe** Early Access feature. See [VLAN probe](https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/).
| Prompt | What it does |
|---|---|
| **Sweep for VLAN probe SSIDs left on the air** | Finds WLANs and Service Validation specs a VLAN probe run may have left behind on a tenant, and reports what is still broadcasting. Read-only — it never deletes |
There is deliberately no prompt that starts a VLAN probe run: runs start from
the r1-mcp companion extension, not from Claude.
## Using a prompt
Pick it from the **+** menu, fill in the arguments it asks for (venue, time
window, client MAC, scope, and so on), and send. The prompt seeds the
conversation with the workflow; from there it's a normal conversation and you
can redirect it at any point.
You are never required to use prompts — everything they do can be asked for in
your own words. They exist because the good version of "give me an as-built
packet" is a page of instructions nobody wants to retype.
## If a prompt isn't showing
- Check that the [feature](https://docs.neuralconfig.com/r1-mcp/reference/features/) it belongs to is enabled on your
account.
- Reconnect the connector — prompt lists are fetched when the connector
refreshes, so a newly enabled feature may need a reconnect to appear.
- Confirm your Claude surface supports MCP prompts; not every client shows the
**+** menu.
---
# Features and feature flags
Source: https://docs.neuralconfig.com/r1-mcp/reference/features/
R1-MCP ships more capability than most people need at once. Rather than putting
everything in front of every user, features are **opt-in per account** — you
turn on what you use, and Claude's tool surface grows accordingly.
Manage them in the **Features** section of the
[R1-MCP dashboard](https://r1-mcp.lanpulse.com).
## Why they're flags and not just always on
Every enabled feature adds tools to the `code_mode` description Claude reads on
every request. Enabling everything makes Claude slower and less focused. Turn
on what you actually use.
## Generally available
No password — toggle them yourself.
### ICX
FastIron documentation search plus the end-to-end ICX switch configuration
workflow. Full-text search over the command reference and configuration guides,
scoped to a **specific firmware train** so the syntax you get matches the
switch you're configuring, plus a separate search over the ICX hardware
installation guides (`search_icx_hw_docs`). See [ICX switches](https://docs.neuralconfig.com/r1-mcp/features/icx/).
### Webhooks
An inbound webhook receiver plus analytics built on the events it collects:
incidents, client troubleshooting, admin audit trails, anomaly detection, event
watches, and roaming analysis. See
[Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/).
### Edge
Documentation search over RUCKUS Edge.
### Write Guard
Confirm-before-write for the API. Any mutating `call_r1` or `call_r1_gql` call
is previewed to you — including which tenant it targets — and must be confirmed
before it executes. Read-only `POST …/query` and `…/search` calls are exempt.
It does **not** cover `device_cli`, MOP and autopilot replay (so not venue
copy, element copy, backup restore, or test-bed apply either), or Data Studio
writes. If you let Claude near a production
tenant, turn this on. See
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/).
### Live CLI
A held console session to devices (`device_cli`), plus MOP — Method of
Procedure — authoring, recording, replay, and export, with an unattended
autopilot mode. See [Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/).
### Test Bed
Capture, plan, and apply lab hardware swaps between saved configuration sets,
with export/import and configuration restore, plus `config_diff` — what changed
on a switch since its captured baseline, with credential lines redacted. See [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/).
### Copy
Configuration capture, copy, backup, and restore. It covers three related jobs,
all compiled into a MOP rather than executed directly:
- **[Venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/)** — snapshot a venue's configuration, plan
a copy into another venue, another tenant, or a template, review it, run it,
verify it, and undo it.
- **[Element copy](https://docs.neuralconfig.com/r1-mcp/features/element-copy/)** — move a single WLAN, switch profile,
or AP ethernet-port profile, with its whole dependency closure, to another
tenant — or copy it under a new name within the same tenant.
- **[Backups](https://docs.neuralconfig.com/r1-mcp/features/backups/)** — keep a venue's configuration indefinitely,
encrypted, and restore it into the same venue, a new one, or another tenant.
Enabling Copy also gives you the `mop_*` tools, even without Live CLI.
### Floorplan
Reads a venue's floorplans with every AP and switch placed in metres, and
renders a floor as an image Claude can see plus an ASCII grid, with findings —
AP placement, coverage, co-channel pairs, roaming, client bands. Adds
`get_floorplan` and `floorplan_map`, and a browser Floor Map page. See
[Floorplans](https://docs.neuralconfig.com/r1-mcp/features/floorplans/) and the
[layer catalogue](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/).
## Early Access
Password-gated. Ask for access if one of these fits your work.
### GraphQL
`call_r1_gql` against the RUCKUS internal GraphQL services — analytics (network
health, incidents, config change, client and incident troubleshooting),
IntentAI, Service Validation, and Zoom Call QoE — plus schema reference docs.
Introspection is disabled on those services, so R1-MCP ships reference
documents instead; Claude fetches the relevant one before composing a query. See
[GraphQL API support](https://docs.neuralconfig.com/r1-mcp/features/graphql/).
### Probe
On-LAN ground truth via Probe MCP. R1 tells you what the
controller *believes*; the probe tells you what's actually on the wire. Linking
the two lets Claude reconcile them. See [Probe](https://docs.neuralconfig.com/r1-mcp/features/probe/).
### Data Studio
Sixteen `ds_*` tools driving a headless Apache Superset to build and publish
charts and dashboards from R1 data. See
[Data Studio dashboards](https://docs.neuralconfig.com/r1-mcp/features/data-studio/).
### Console
The Live Console page — a browser window that streams a watched client's events
and plots its RSSI, SNR, and Tx while you troubleshoot in Claude. `watch_client`
returns a deep link straight to it. It needs the **Webhooks** feature on too:
`watch_client` is a webhooks tool, and Console on its own adds no tools. See [Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/).
### VLAN probe
Checks whether a wireless VLAN is reachable at a venue where no WLAN exists to
test it with. A run puts a temporary SSID on the air from the venue's online
APs, runs a Service Validation test, then removes the SSID. It is driven from
the r1-mcp companion extension and has **no Claude tools** by design. It is
Early Access as a safety measure, because a run broadcasts a real SSID at a
live site. See [VLAN probe](https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/).
## Admin-granted
`ai_chat` powers the AI chat panel on the
[Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/) page. You cannot enable it
yourself — not with a toggle and not with the Early Access password. Only an
administrator can grant it.
## Effect on prompts
[Workflow prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) are gated the same way as tools — enabling
a feature adds both its tools and its prompts. After changing features, reconnect
the connector in Claude so it picks up the new list.
## Next steps
- [Core tools reference](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/): What every user gets before any feature is enabled.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): The caps, timeouts, and retention windows each feature brings with it.
- [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/): The 20 curated documents get_reference reads, filtered to your features.
- [Workflow prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/): The 18 guided workflows, and which feature each one needs.
---
# Bundled reference docs
Source: https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/
R1-MCP ships a set of curated reference documents that Claude reads on demand
through **`get_reference`**. They carry the knowledge that isn't in the RUCKUS
API spec or the user guide: verified CLI patterns, GraphQL schemas that
introspection can't reveal, and workflow playbooks proven against real hardware.
You don't invoke them. Claude fetches the relevant one before doing work that
needs it — but knowing what exists tells you what Claude has to work from, and
what to ask for by name.
## How it works
`get_reference` with no arguments lists the docs available to you, each with its
section titles. With a `doc` key it returns that document's table of contents;
with a `doc` and a `section` it returns that section's text. The section is
matched by exact title first, then as a case-insensitive substring. An unknown
doc returns `doc_not_found` and an unknown section `section_not_found`, each with
the list of what is available.
The tool appears once you have **at least one** [feature](https://docs.neuralconfig.com/r1-mcp/reference/features/)
enabled, and the listing only shows the docs for features you actually have on.
Write Guard, Console, and AI chat have no docs of their own, so with only those
enabled the listing is empty.
## The catalog
| Doc key | Feature | What it covers |
|---|---|---|
| `icx-workflow` | ICX | The end-to-end ICX config loop: backup, generate, verify, apply, read back, diff |
| `icx-bgp-evpn` | ICX | BGP-EVPN fabric configuration on FastIron 10.0.20 |
| `icx-evpn-playbook` | ICX | Lab-verified EVPN build and validation playbook |
| `icx-static-vxlan` | ICX | Static VXLAN configuration |
| `icx-ops-playbook` | ICX | Day-two operations on an ICX fabric |
| `icx-troubleshooting` | ICX | ICX switch troubleshooting |
| `stig-icx-l2s` | ICX | DISA STIG validation for ICX layer-2 switches |
| `stig-icx-router` | ICX | DISA STIG validation for ICX routers |
| `webhooks-setup` | Webhooks | Configuring the event receiver in RUCKUS One |
| `ap-cli-guide` | Live CLI | The AP CLI — what it accepts and how output reads |
| `mop-authoring` | Live CLI or Copy | Writing a MOP: steps, gates, provenance, rollback |
| `testbed-workflow` | Test Bed | Capture, plan, apply, and restore a test bed |
| `venue-copy-workflow` | Copy | The venue copy pipeline, safety gates, and support matrix |
| `probe-verify` | Probe | Which probe check verifies which class of R1 write |
| `data-studio` | Data Studio | The Superset console recipe, query shapes, and caveats |
| `floorplan-mapping` | Floorplan | The floorplan layers, what each one can state, the signal scales, and worked workflows |
| `vlan-probe` | VLAN probe | What a VLAN probe run does, and why there are no Claude tools for it |
| `gql-analytics` | GraphQL | The analytics surface, and IntentAI |
| `gql-troubleshooting` | GraphQL | Client and incident troubleshooting, and Call QoE |
| `gql-service-guard` | GraphQL | Service Validation |
## Why some of these exist at all
**The GraphQL docs are the only schema source.** Introspection is disabled on all
four RUCKUS AI GraphQL services, so there is nothing to probe — see
[GraphQL API support](https://docs.neuralconfig.com/r1-mcp/features/graphql/). They're organized by surface rather than
one per service, which is why IntentAI lives in `gql-analytics` and Call QoE in
`gql-troubleshooting`.
**The ICX docs are the verified-syntax backbone.** FastIron CLI is never emitted
from memory; it's checked against the indexed documentation and these playbooks
first. See [ICX switches and FastIron docs](https://docs.neuralconfig.com/r1-mcp/features/icx/).
**`data-studio` accumulates.** Learnings saved with `ds_save_note` — yours, plus
any an administrator has promoted for everyone — are returned as `learnedNotes`
whenever Claude opens the `data-studio` document, so a quirk discovered in one
session is in front of Claude in the next. See
[Data Studio dashboards](https://docs.neuralconfig.com/r1-mcp/features/data-studio/).
## See also
- [Core tools](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/) — the always-available tool surface
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/) — what enabling a feature adds
---
# Limits and quotas
Source: https://docs.neuralconfig.com/r1-mcp/reference/limits/
Most surprising R1-MCP behaviour is a limit doing its job. This page collects
them, with what each one does when you reach it.
## Timeouts
| Limit | Value | On reaching it |
|---|---|---|
| **`code_mode` run budget** | **30 seconds** wall clock, shared across every API call the program makes | The run is cut off. At **20 seconds** the `budget` snapshot on each response gains a `warning` — the program is expected to return partial results and continue in a fresh run |
| One `call_r1` request | 15 seconds | Surfaces as a structural error envelope; the measured time is still billed to the run budget |
| RUCKUS token mint | 15 seconds | `timeout` — the R1 token endpoint didn't respond |
| One Data Studio request | 20 seconds | `statusText: "timeout"` on the `ds_*` response |
| `await_request` poll loop | 60 seconds by default, settable **1–120**; polls every 2 seconds by default (0.5–10) | Reports the last activity state it saw rather than failing outright. A wait longer than about 25 seconds is cut off by the 30-second run budget first |
| Write Guard confirmation | **10 minutes** from the preview | Confirming a stale preview returns a **fresh preview** instead of executing |
:::note
The run budget is per `code_mode` **call**, not per conversation. Every new call
gets a fresh 30 seconds, which is exactly why the right response to a warning is
to split the work rather than retry it. See
[How code mode works](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget).
:::
### A 404 while awaiting is not a failure
`await_request` polls an asynchronous R1 operation to completion. R1 returns
**404** for an activity it has accepted but not yet made resolvable, so a 404 is
treated as *not yet*, not as failure — the loop keeps polling until its own
timeout bounds the wait. Once any poll has returned a real activity body, a
subsequent timeout is a genuine one.
## Retries
`call_r1` never throws on an HTTP error; it returns a response you can inspect.
What it retries automatically:
| Status | Behaviour |
|---|---|
| **401** | Exactly one refresh-and-retry |
| **429** | Auto-retried for **GET, PUT, DELETE** only — at most **2 retries**, honouring `Retry-After`, with the wait capped at **5 seconds**. POST and PATCH are not replayed unless you pass `retryOn429: true` |
| **406** | Retried once with the versioned media type R1 named. If the 406 names none, it surfaces as-is |
| **415** | A body-less request is retried once with the `Content-Type` R1 named |
`call_r1_gql` requests are POSTs, so they are **never** auto-retried on a 429
unless you opt in — and opting in is only safe for reads, since Service Validation
has real mutations.
Every response carries `retried`, so the retry count is always visible.
## Stored artifacts
Everything R1-MCP stores for you is bounded, per user.
| Artifact | Cap | Retention | At the cap |
|---|---|---|---|
| **Snapshots** (`venue_extract`, `element_extract`, and the working snapshot `backup_create` takes from a `venueId` — one shared cap) | 20 | 30 days | Refuses — `snapshot_limit_reached` |
| **Backups** (`backup_create`) | 50 | **Indefinite** | Refuses — `backup_limit_reached`, checked before anything is extracted, and nothing frees itself |
| **MOPs / test plans** you author | 50 | Untouched *drafts* age out after 30 days | Refuses — `mop_limit_reached` |
| **Copy MOPs** the engine compiles | 100 | 30 days | **Evicts the oldest** — except a copy MOP that still has a run on record, which is kept |
| **Test beds** | 50 (100 devices each) | 365 days untouched | Refuses — `testbed_limit_reached`; a save with more than 100 devices fails as `too many devices` |
| **Endpoint notes** (`save_endpoint_note`) | 10 per endpoint, 500 in total; 5–500 characters each | Kept | Refuses — `too_many_notes_for_endpoint` / `too_many_notes` |
| **Data Studio notes** (`ds_save_note`) | 10 per topic; 5–4,000 characters each | Kept | Refuses — `too_many_notes_for_topic` |
:::caution
Compiled copy MOPs are the one artifact that **evicts rather than refuses**.
Refusing would block the copy workflow itself over rows you never asked to keep —
but it does mean a compiled plan you care about should be `mop_export`ed rather
than left in the store. A copy MOP with a run on record is skipped by both the
eviction and the 30-day sweep, so `venue_copy_undo` can still find what it
created; once its runs age out (7 days, below) it becomes evictable, so the
count can sit above 100 until then.
:::
### Sizes
| Limit | Value | On exceeding it |
|---|---|---|
| Snapshot config | 5 MB | `snapshot_too_large` — restrict `domains` and re-extract |
| Backup config | 5 MB | `backup_too_large` — back up fewer domains separately |
| MOP steps | 200, or **400** for an API-only MOP | The plan is rejected as `plan_invalid`; split it by `domains` |
| Runs kept per MOP | 20 | Oldest dropped |
| `config_diff` output | 400 lines, with no paging | The diff is cut off and the response is marked `truncated` |
| Run retention | 7 days for a MOP, **90 days** for a test plan | Swept. A copy run's `runId` stops working for `venue_copy_undo` and for `element_copy_verify` after 7 days — they answer `run_not_found` |
A compiled copy plan gets the raised 400-step cap because it is API-only. An
over-cap plan is the signal to plan each subset of `domains` into its own MOP.
## Batches and pages
| Limit | Value |
|---|---|
| `device_cli` commands per batch | **20**, run sequentially in the held session |
| `search_endpoints` results | 20 by default, 50 maximum |
| `list_endpoints_by_tag` results | 50 by default, 200 maximum |
| `search_docs`, and the ICX, ICX hardware, and Edge doc searches | 10 by default, 20 maximum |
| Requests in one MCP JSON-RPC batch | 20 — more is refused as `batch_too_large` |
| Autopilot wall clock | `maxWallMin` — 30 minutes by default, **120** maximum |
| Autopilot runs | One at a time, per user |
A long configuration job is applied as several batches of twenty into the *same*
held session, not as one giant push. Autopilot expiry **pauses** a run; it never
fails it.
### Device CLI
| Limit | Value |
|---|---|
| Output per `device_cli` batch | 256 KB by default |
| Session transcript | 4 MB |
| Held session | Closed after **4 minutes** idle, and after **13 minutes** in all — reopen it to continue |
| Cached device login token | At most **15 minutes**, so a connection you edit, disable, or delete stops opening consoles quickly |
### Topology and reconcile
| Limit | Value |
|---|---|
| `diagram_topology` graph | 2,000 nodes, 4,000 edges |
| `diagram_topology` L1 AP LLDP lookups | 60 APs |
| `diagram_topology` L3 static-route reads | 60 switches |
| `probe_reconcile` inventory | 5,000 cloud devices |
| `probe_reconcile` rogue rows returned | 25 by default, 200 maximum (totals are always included) |
### Data Studio
| Limit | Value |
|---|---|
| One Data Studio request | 20 seconds (see Timeouts) |
| `ds_diagnose_charts` sweep | 15 charts by default, 60 maximum |
| `ds_list_charts` / `ds_list_dashboards` rows | 100 by default, 500 maximum |
RUCKUS also enforces its own guardrails on every Data Studio chart and
dashboard — these are platform limits, not R1-MCP ones:
| Guardrail | Value |
|---|---|
| Dimensions per chart | **6** (3–4 performs best); more fails as `DATASTUDIO-20010` |
| Time range | **31 days**. A longer relative range is capped to 31 days; a longer custom range is rejected |
| Unpaginated table | **500 rows**, whatever `row_limit` says — turn on server pagination for more |
| Charts per dashboard | **40** across all tabs (20 recommended) |
## Images and floorplans
Any tool that returns a picture — today, [`floorplan_map`](https://docs.neuralconfig.com/r1-mcp/features/floorplans/) —
sends it as an image block Claude can see, within these caps. An image over a
cap is **refused**, not trimmed, with a note to ask for the map link instead.
| Limit | Value | On exceeding it |
|---|---|---|
| Image blocks per response | **4** | `too_many_images` |
| One image block | **1.5 MB** | `image_too_large` |
| All image blocks in one response | **4 MB** | `total_image_budget_exceeded` |
| Floorplan map image | **800,000 pixels**, ≤ 900 KB encoded; widths 1000, 760, 560, then 400 px are tried in turn | Rendered again at the next smaller width |
| Inline SVG map | **60 KB** | Refused rather than trimmed — use the map link |
| ASCII floor grid | 160 × 80 characters | — |
| Source floorplan image from R1 | **20 MB** | `image_too_large` |
| PNG decode | 30 megapixels | `image_too_large` |
| Mirrored floorplan images | **50 per user per connection** | The oldest are evicted |
| Cached image metadata | 30 days | Re-read |
| Client snapshot cache | 15 minutes | Re-queried from R1 |
| Roam arrows / co-channel pairs drawn | 80 / 40, busiest first | The rest are counted, not drawn |
| Client roster rows | 1,500 | — |
| Floor Map launch link | **15 minutes**, one venue, read-only; it cannot renew itself | Mint a new one |
## VLAN probe runs
The [VLAN probe](https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/) puts a real SSID on the air, so
its limits are about getting it off again.
| Limit | Value |
|---|---|
| Rows (VLANs) per run | **15** |
| Run deadline | Three times the estimate, never under **15** or over **60 minutes** — at the deadline the run is torn down |
| Waiting for the Service Validation test to appear | 3 minutes |
| Test polling per row | Every 15 seconds, 24 times (about 6 minutes) |
| Confirmation after preflight | 10 minutes |
| Progress stream | Re-opened every 10 minutes (a `bye` frame tells the client to reconnect) |
| Cleanup request | Up to 50 named ids |
| Run record | 30 days, and kept longer while anything it created is not yet deleted |
## Webhook event retention
The [webhooks feature](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) stores what it receives,
per user, with **retention that varies by event class**. This is why a
month-old client event is gone while a month-old incident is not.
| Event class | Kept | Row cap |
|---|---|---|
| Client stream (`event`), including admin **login** events | 7 days | 20,000 |
| AP infrastructure (`ap_event`) | 30 days | 5,000 |
| RADIUS / auth (`radius`) | 30 days | 4,000 |
| Activity — "what changed before the outage" | 90 days | 2,000 |
| Admin audit (admin actions other than logins) | 90 days | 2,000 |
| **Incidents** | **365 days** | 1,000 |
| Test / unknown | 7 days | 400 |
| Any other type | 30 days | 4,000 |
Purging happens on insert, scoped to the class that just arrived — and an
hourly sweep also enforces the time windows for every user — and each class
purges against **its own** budget. The high-volume client stream
therefore cannot evict a rare incident or admin-audit row to make room for itself. Admin **login** events are the exception: they ride the client stream, so they share its 7-day window and 20,000-row budget.
Anything you ask about outside these windows isn't missing data; it is data that
was never retained. Derived stores have their own windows: the client registry
keeps 180 days (up to 100,000 devices), roam pairs 90 days (up to 40,000
pairs), event counters 120 days (up to 20,000 counters).
The webhook receiver accepts a payload of up to **64 KB**; a larger one is
answered `413 payload_too_large`.
### Watches
| Limit | Value |
|---|---|
| Watch expiry | 24 hours by default, set in **whole hours** |
| Maximum | 168 hours (7 days) |
| Active watches | **100** per user — more is refused as `watch_limit_reached` |
| Watch notices | 1,000 per user; delivered ones kept 7 days, undelivered 30 days |
| [Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/) watch started from the page | 2 hours by default, 24 hours maximum |
Expiry is mandatory — there is no permanent watch.
## Sign-in and access
| Limit | Value | On reaching it |
|---|---|---|
| Claude connector access token | 1 day | Claude refreshes it automatically |
| Claude connector refresh token | 90 days, renewed each time it is used | Reconnect the connector if it sits unused that long |
| Dashboard sign-in session | 30 days | Sign in again |
| Early Access password attempts | 10 per 15 minutes | `429 too_many_attempts` — wait and retry |
| Connector registrations | 5 per minute | Retry shortly |
## Feature gates are a kind of limit too
A tool you cannot see is not a broken tool. R1-MCP exposes a single MCP tool —
`code_mode` — and inside it the `r1` object carries **13 always-on tools**.
Everything else appears only when its [feature](https://docs.neuralconfig.com/r1-mcp/reference/features/) is enabled.
`get_reference` itself appears only once you have at least one feature on.
After enabling a feature, **reconnect the connector in Claude** so it picks up
the new tool list.
## Next steps
- [How code mode works](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/): The run budget in context — why broad requests come back in stages.
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/): Which tools each feature adds, and what is Early Access.
- [Troubleshooting](https://docs.neuralconfig.com/r1-mcp/troubleshooting/): Errors you may hit, and which limit each one comes from.
---
# ICX switches and FastIron docs
Source: https://docs.neuralconfig.com/r1-mcp/features/icx/
The **ICX** feature adds full-text search over the RUCKUS FastIron
documentation set and an end-to-end workflow for configuring ICX switches.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com).
## What's indexed
The release-tagged FastIron documentation set — the command reference plus the
configuration guides:
`commandref` · `l2guide` · `l3guide` · `securityguide` · `managementguide` ·
`monitoringguide` · `dhcpguide` · `ipmulticastguide` · `trafficguide` ·
`switchstackingguide` · `debugcommand` · `featuresupportmatrix` · `licensing` ·
`mibreference` · `upgradeguide`
The 10.0.10 train also includes `fipscc-config` and `scalingguide`.
Results come in two kinds:
- **`command`** — one section per CLI command: syntax, parameters, modes,
examples.
- **`concept`** — configuration-guide prose.
There's also a hardware documentation search, `search_icx_hw_docs`, over the
install guides and technical specifications for ICX 7150, 7250, 7450, 7550,
7650, 7750, 7850, 8100, and 8200 — port counts, PoE budgets, power supplies,
stacking limits, and other physical facts.
## Firmware trains matter
FastIron syntax differs between trains, and this is the single most important
thing to get right.
R1-MCP scopes every search to **one release**. By default it uses the newest
train, but the correct behavior is to search against the **target switch's**
firmware train — read `switchFirmwareVersion` from R1, or run `show version`
live, and search that.
- The **minor** matters: 10.0.10 versus 10.0.20.
- The **patch level does not** — `10.0.20b_cd1` normalizes to the 10.0.20
train.
- Do not mix trains within one switch's configuration.
- A train that isn't indexed (anything other than 10.0.10 or 10.0.20 today)
silently falls back to the newest train. Every result names the `release` it
searched, so check it.
BGP-EVPN, for example, exists only on 10.0.20. Asking against the wrong train
produces syntactically wrong CLI that looks plausible.
:::tip
When you ask for switch config, name the firmware: "generate the config for
VLAN 200 tagged on 1/1/1-1/1/8 on a switch running 10.0.20". It removes the
guesswork entirely.
:::
## Syntax is checked against the docs
R1-MCP instructs Claude to verify FastIron CLI against the indexed documentation
before emitting it, rather than writing it from memory, and to record the
section it came from. That is an instruction to the model, not something the
server can enforce — which is why the export marks what wasn't checked. When a configuration is exported as a [MOP](https://docs.neuralconfig.com/r1-mcp/features/live-cli/),
each step carries a citation of the form:
> validated against *[doc]* *[release]* — *[section title]* (p*[page]*)
A step with no such provenance is exported marked as **not** validated against
documentation. That's deliberate: an unverifiable config change is worth less
than an honest "I didn't check this."
## The configuration workflow
For a multi-command job, the default path is:
1. **Verify syntax** against the FastIron docs for the switch's train.
2. **Back up** the running configuration.
3. **Apply** through a held [`device_cli`](https://docs.neuralconfig.com/r1-mcp/features/live-cli/) session — the
same live console the R1 web UI gives you.
4. **Read back** — take a post-apply backup and compare it with the first. R1's
backup comparison returns both full configs, not a diff, so the comparison
is done client-side; on a captured [test bed](https://docs.neuralconfig.com/r1-mcp/features/testbed/#what-changed-since-the-baseline),
`config_diff` gives you the diff directly.
The alternative apply path is CLI templates, for unattended or staged pushes.
Both verify the same way — via config backups plus a `device_cli` read-back.
## BGP-EVPN fabrics
There's a dedicated [workflow prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) — **ICX BGP-EVPN fabric
build / validate** — that runs the build or validation end to end. It's the
fastest way in for fabric work.
The feature also unlocks ICX [reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/)
Claude reads on demand: `icx-workflow`, `icx-bgp-evpn`, `icx-evpn-playbook`,
`icx-static-vxlan`, `icx-ops-playbook`, `icx-troubleshooting`, and the DISA STIG
validation docs `stig-icx-l2s` and `stig-icx-router`.
## Related
- [Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/) — running commands on the device
- [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/) — swapping lab hardware between config sets
- [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) — confirm before anything changes
---
# Live CLI and MOPs
Source: https://docs.neuralconfig.com/r1-mcp/features/live-cli/
The **Live CLI** feature gives Claude a real console session to your devices,
plus tooling to turn what happens in that session into a documented, repeatable
procedure.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com).
## `device_cli` — a real console
`device_cli` opens a live interactive CLI to a RUCKUS ICX switch or an AP over
the same R1 web-UI WebSocket the R1 web console uses. It is the full CLI —
any command, real output.
To open a session Claude needs the **venue**, the **device type**, and the
device's **serial number** (not its MAC), plus an ordered batch of commands.
Commands run sequentially at the switch enable prompt or the AP `rkscli:`
prompt. On ICX you can interleave config and `show` commands in one batch,
because `show` works from config mode.
**AP CLI needs a read-write connection.** RUCKUS One issues the AP console token
only to an API client with the ADMIN role, so if your default connection is
read-only, an AP session fails with `jwt_mint_forbidden`. Pass `connection`
naming a read-write connection (see [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/)).
Switch CLI works on either. A session belongs to the connection it was opened
with: naming a different one on a later batch returns `connection_mismatch`.
A batch carries at most **20 commands**. By default a session is one-shot: it
logs in, runs the batch, and closes as soon as the batch completes. For
multi-batch work Claude opens the session with `keepOpen: true`, which holds the
logged-in session so later batches, sent with its `sessionId`, run with no
re-login — which is how a long configuration job gets applied: several batches
of twenty into one live session, not one giant push. A held session closes on
`action: "close"`, or on its own after about 4 minutes idle (hard cap about 13
minutes).
### Long-running commands
Logging in takes a few seconds, so a first call can come back `connecting: true`
with a `sessionId` and no output yet; Claude then polls with `action: "poll"`. A
long command such as `show tech` also returns in pieces through `poll` until
`complete: true`. For a command that never ends on its own (an un-counted
`ping`, `iperf3 -s`), `action: "interrupt"` sends Ctrl-C and keeps the session
open.
### Reading the output
Each completed command comes back with its real console output. R1-MCP's rule
is that this output is surfaced **verbatim** in Claude's reply — in a fenced
code block, labeled with its command — and then interpreted. You should always
get to see what the device actually said, not only a paraphrase of it.
Occasionally a result carries a marker meaning completion took a fallback path
— the device kept talking after the prompt, or the command echo was never
recognized. When that happens the attribution of output to command may be
imperfect, and it's worth reading that block yourself rather than trusting the
summary.
### When it fails
A prompt timeout usually means the **device is offline or unreachable**, not
that the request was malformed. Confirm the device is online before retrying —
each first-call retry opens a fresh session, so blind retries against a dead
target just pile up.
Other errors are explicit: `switch_credentials_unavailable`, `jwt_mint_failed`,
`jwt_mint_forbidden` (read-only connection, AP), `ws_upgrade_failed`,
`login_incorrect`, `no_commands`, `too_many_commands`. On a held session:
| Error | Meaning |
|---|---|
| `busy` | Another call on the same session is still executing — wait for it, then retry (`close` always works) |
| `command_in_flight` | A command is still streaming — poll it out first |
| `no_command_to_interrupt` | `interrupt` was sent but nothing was running |
| `session_lost` | The socket dropped or the session idled out — open a fresh session |
## MOPs — Method of Procedure
A MOP is a change runbook: ordered steps, each with the command, its intent,
where the syntax was verified, the observed output pinned as the expected
baseline, a verification gate, and rollback commands.
Tools: `mop_save`, `mop_list`, `mop_get`, `mop_edit`, `mop_delete`,
`mop_export`, `mop_replay`.
The MOP tools also ship with the [Copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) feature, because a
venue copy compiles into a MOP and is run by this same engine. Enabling either
feature gives you them. `device_cli` itself — and so recording a live session and
replaying CLI steps — needs Live CLI.
### Recording a live session
The fast way to author one:
1. Save a **draft** MOP with just a title — you get back a MOP id.
2. Pass that id to `device_cli` as the record target.
3. Every command you run is captured as a draft step with its real output
pinned as the baseline — one step per command, structural lines such as
`configure terminal` and `end` included.
4. Enrich the draft afterwards — intent, gates, rollback, provenance.
### Provenance is required
For every switch configuration step, the syntax must first be verified against
the [FastIron documentation](https://docs.neuralconfig.com/r1-mcp/features/icx/) for the device's firmware train, and
the section recorded on the step. Exported MOPs print that citation. A step
without provenance exports as "no provenance recorded", and the sign-off footer
states plainly that the commands were **not** validated against documentation.
This is the difference between a runbook a change board will accept and a
transcript.
### Test plans
The same artifact with `kind: "test_plan"` turns the steps into **test cases**
with declared expectations that *gate* on replay — a case with no gate defaults
to requiring a human OK rather than silently passing. Test-plan runs keep 90
days of regression history.
The `kind` is immutable once saved: decide up front whether you're writing a
change procedure or a test plan.
### Replaying and autopilot
`mop_replay` runs a saved MOP. By default it runs **one step per call**, so you
see each result before the next command goes out, and `dryRun: true` walks the
whole plan without touching anything.
`action: "start_auto"` runs the whole plan **unattended** instead: a server-side
driver executes every step and returns `{ runId, autopilot: true }` immediately.
Poll `action: "status"` for progress.
Autopilot is preflight-gated, and the gates are the point. It refuses if:
- the plan isn't live-ready;
- it contains config-changing steps without an explicit `unattended: true`
acknowledgement — **the server cannot tell a bench from production, so you are
the one declaring it**;
- `onFail: "rollback"` was asked for but a config step has no rollback commands;
- preflight raised warnings and you didn't pass `acceptWarnings: true`.
What happens on failure is a policy you choose. `onFail: "pause"` (the default)
stops on any failed gate or device error with the position preserved;
`"rollback"` runs the consolidated reverse rollback and marks the run failed;
`"continue"` records failures and keeps going, which is for lab-build momentum
and not for change windows. A test plan is different again: a failed gate is
recorded and the run continues, a device error retries the case once and then
marks it blocked, and **two consecutive blocked cases pause the run** on the
assumption the device has gone away.
One autopilot run per user at a time, capped at 30 minutes of wall clock by
default and 120 at most. **Expiry pauses a run; it never fails one** — resume it
with `action: "resume_auto"`, which also re-arms a run whose progress has
stalled. `action: "abort"` stops at the next step boundary.
:::note
On a paused run, `action: "step"` is a permanent **manual takeover** — it clears
autopilot ownership, and `resume_auto` no longer applies. If you only want to get
past one case, use `action: "skip"`, which keeps ownership intact.
`skip` applies to test plans only: `skipAs: "skipped"` (the default) doesn't fail
the run, and `skipAs: "blocked"` does. A MOP whose API steps write to named
connection targets also needs `armWrites: true` to create a run
(`write_arming_required` lists the tenants) — a separate gate from
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/).
:::
### Steps can be API checks too
A step doesn't have to be a CLI command. An API step carries an R1 call plus
expected-status and comparison gates, authored from a response you actually
observed. Useful when the verification is "the controller now reports X"
rather than "the console prints Y".
### Exporting a MOP
`mop_export` turns a saved MOP or test plan into a print-ready document. Every
export also returns a `download_url` that opens only in your own signed-in
browser.
| `format` | What you get |
|---|---|
| `both` (default) | The structured JSON plus the standalone HTML document |
| `json` | The structured MOP |
| `html` | The print-ready runbook (or test plan) document |
| `report` | A test report across the recorded replay runs — needs at least one run, else `no_runs_to_report` |
| `pdf` | Link only — the `download_url` serves a PDF of the document |
| `docx` | Link only — the `download_url` serves a Word document |
Documents use your saved branding (the dashboard's Branding card) and embed the
venue topology when the MOP names a venue; pass `include_topology: false` to omit
it.
## POC and QA test plans
The **POC / QA test plan (author → run → report)** [prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/)
runs the whole cycle: writes a plan against an objective, executes it, and
reports the results. The **Deep-dive an ICX switch / fleet (live CLI)** prompt
runs a deep dive of a venue's switches over the real CLI, read-only by default.
## Limits worth knowing
| Limit | Value |
|---|---|
| Commands per `device_cli` batch | 20 |
| MOPs / test plans per user | 50 — untouched drafts age out after 30 days |
| Steps per MOP | 200, or 400 for an API-only MOP |
| Runs kept per artifact | 20, oldest dropped |
| Run history | 7 days for a MOP, 90 days for a test plan |
The MOPs a [venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) compiles are counted and swept
separately — see [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/#stored-artifacts).
## Next steps
- [ICX switches and FastIron docs](https://docs.neuralconfig.com/r1-mcp/features/icx/) — where step syntax is verified
- [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) — confirm-before-write on mutating calls
- [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/) — lab hardware swaps
- [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) — the other feature that ships the `mop_*` tools
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/) — every cap in one place
---
# Webhooks and analytics
Source: https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/
The **Webhooks** feature turns R1-MCP into an event sink for your RUCKUS One
tenant, and adds a set of analytics tools that answer questions the REST API
alone can't.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com).
## Setting up the receiver
`get_webhook_receiver` creates your receiver and returns a **webhook URL and a
secret**. Both are shown **once** and stored only as hashes, so save them; a later
call returns the receiver's metadata without them. `rotate: true` (or the
dashboard's **Webhooks** card) mints a new pair and invalidates the old URL.
In RUCKUS One, go to **Network Control → Service Catalog → Webhooks → Add**,
choose the **RUCKUS One** payload type, and paste both. Enable only the topics you
need: RADIUS logs and client connect/disconnect are high-volume, and should be on
only while you're actively troubleshooting. The receiver rejects a request with
the wrong secret (`401 unauthorized`) or a body over 64 KB
(`413 payload_too_large`).
Once events start flowing, each delivery is stored verbatim — never
de-duplicated, so counts are approximate — alongside normalized fields, and the
analytics tools have something to work with.
The analytics are only as good as the event history you've collected — a
receiver configured five minutes ago can't tell you about last month.
## What you can ask about
### Incidents
`list_incidents`, `get_incident`, `correlate_incident` — the incident feed, and
a causal timeline around one incident (or a moment you name): `correlate_incident`
gathers admin changes, AP reboots and firmware events, switch config failures
and the incident itself, and ranks the disruptive events that preceded it as
candidate root causes rather than a list of symptoms.
The **Network health check (incidents)** [prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) runs a full
assessment from this data.
### Clients
`list_clients`, `diagnose_client`, `get_client_profile` — a persistent client
registry, per-client diagnosis, and a device profile. The registry outlives the
event cache (see [retention](#how-long-events-are-kept)). Profiles carry a
**manufacturer** derived from the MAC's IEEE OUI, which is far more reliable than
RUCKUS's OS fingerprint (`os_type` is frequently wrong); it is empty for
randomized (private) MACs. `list_clients` filters by OS, encryption, band, and
manufacturer.
The **Diagnose a client that can't connect** prompt stitches RADIUS and
association events into one verdict. The **Client deep-dive troubleshooting
report** prompt — available without this feature — assembles everything known
about one MAC into a single report.
### Anomalies
`detect_anomalies` plus the **Hunt infrastructure anomalies** prompt — looks
for infrastructure behaving unlike itself, rather than tripping a fixed
threshold.
### Admin and change audit
`list_admin_audit`, `get_change_chain` — who changed what, when, and what
followed from it. The **Admin / change audit trail** prompt packages this.
When a network "just started" misbehaving, the change chain is usually the
fastest path to the answer.
### Roaming
`roam_matrix`, `get_client_roams`, `find_ping_pong_clients` — the roaming
picture across your APs, including clients bouncing between two APs, which is
one of the most common invisible causes of a bad wireless experience. How to read it: [The roam matrix](https://docs.neuralconfig.com/r1-mcp/features/roam-matrix/).
### Events and counts
`query_events`, `get_event_counts`, `get_notifications`, `get_ap_health`,
`webhook_event_summary`, `list_webhook_events`, `get_webhook_event` — the raw
event layer underneath the analytics, when you need to look yourself.
`query_events` falls back to RUCKUS One's activity log when the store has nothing
for your filter, and `get_ap_health` adds a live R1 read of the AP unless you
pass `includeLive: false`.
## Watches: reproduce and catch
Watches are for problems you can trigger but not predict:
- `watch_client`, `watch_ap`, `watch_incidents` — arm a watch, with a TTL.
- `list_watches`, `clear_watch` — see and cancel what's armed.
A watch expires after **24 hours** by default and **7 days** at most. The expiry
is mandatory — there is no permanent watch. Up to 100 watches can be active at
once (`watch_limit_reached` beyond that).
What a watch catches surfaces as a short `_notices` line on your next
`webhook_event_summary`, `list_webhook_events`, or `diagnose_client` call, rather
than being pushed to you; `get_notifications` returns the full notices, filtered
by `mac` or `since`. P1–P2 incidents surface this way even with no watch set —
`watch_incidents` widens or narrows that threshold (`min_severity`) for the
watch's lifetime.
The workflow is the **Live reproduce-and-catch (watch & capture)**
[prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/): arm a watch on the client or AP, go reproduce the
fault, and come back to exactly the events that happened during the window —
instead of scrolling a firehose hoping to spot it.
This is the single best reason to enable the webhooks feature.
## How long events are kept
Retention **varies by event class**, which is why a month-old client event is
gone while a month-old incident is not:
| Event class | Kept | Row cap |
|---|---|---|
| Client stream | 7 days | 20,000 |
| AP infrastructure | 30 days | 5,000 |
| RADIUS / auth | 30 days | 4,000 |
| Activity (config change) | 90 days | 2,000 |
| Admin audit | 90 days | 2,000 |
| **Incidents** | **365 days** | 1,000 |
Each class purges against its own budget, so the high-volume client stream cannot
crowd out a rare incident or configuration-change row. The exception: admin
logins and other admin-activity events arrive on the client event stream and
share its 7-day window, so `list_admin_audit` reaches back 90 days only for
activity and admin rows. Test and unrecognised event types are kept 7 days
(400 rows).
Some summaries built from events outlive the raw events, so these tools answer
beyond the windows above:
| Store | Kept | Used by |
|---|---|---|
| Client registry | 180 days after the device was last seen (100,000 devices) | `get_client_profile`, `list_clients` |
| Roam-pair matrix | 90 days (40,000 pairs) | `roam_matrix` |
| Event counters | 120 days (20,000) | `get_event_counts`, `detect_anomalies` |
Past those windows, a question isn't hitting a bug — the data was never
retained.
:::note
Retention starts when the receiver is set up. Nothing is backfilled, so an
analytics question about last month only works if the receiver was collecting
last month.
:::
## Next steps
- [Features](https://docs.neuralconfig.com/r1-mcp/reference/features/) — enabling this and the other flags
- [Prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) — the guided versions of these workflows
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/#webhook-event-retention) — retention, watch TTLs, and every other cap
- [Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/) — watching a client's events stream in a browser
---
# Write Guard
Source: https://docs.neuralconfig.com/r1-mcp/features/write-guard/
**Write Guard** makes every mutating RUCKUS One API call that Claude composes
itself — through `call_r1`, and `call_r1_gql` for GraphQL mutations — stop and
ask you first. It is opt-in, and if you point R1-MCP at a production tenant you
should turn it on.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com).
## How it works
1. Claude attempts a mutating call **without** a confirmation token.
2. The call **is not sent.** Instead the tool returns a `confirm_required`
envelope containing a **preview** — what would run, and against which tenant
— plus a single-purpose token.
3. Claude shows you the preview and waits for an explicit OK in the
conversation.
4. On your OK, Claude re-sends the *identical* call with the token, and it
executes.
:::note
The bounce is not an HTTP error. It comes back as `ok: false`, `status: 0`,
`statusText: "confirm_required"`, with the preview and token under `guard` — so
code that only checks `ok` should not read it as a failed request.
:::
The preview names the target connection — its label and tenant ID — so a
confirmation tells you which tenant you're about to change. With
[multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/) configured, that matters.
## The token can't be reused elsewhere
The confirmation token is an HMAC over your user id and a canonical fingerprint
of the exact call — method, path, parameters, query, body, headers, and the
resolved connection id. Object keys are sorted recursively so a re-send that reorders fields still
matches.
The consequences:
- Changing **anything** about the call after the preview invalidates the token
— the fingerprint no longer matches, and you get a fresh preview instead of a
silent execution of something you didn't approve.
- A token minted for tenant A cannot be replayed against tenant B, because the
connection id is part of the fingerprint.
- Tokens expire **ten minutes** after the preview. Confirming an old preview
gets you a new one rather than an execution.
- A token is not single-use. It stays valid for its ten minutes against that
exact call — the guard is a deliberate two-step safety net, not a security
boundary. The security boundary is your
[R1 credential's own permissions](https://docs.neuralconfig.com/r1-mcp/concepts/security/#your-r1-permissions-are-the-ceiling).
So "approve once, then quietly do something else" is not a failure mode
available to the model.
## What counts as a write
The rule is mechanical:
| Call | Treated as |
|---|---|
| `GET`, `HEAD` | Read — sent without asking |
| `POST` whose last path segment is `query` or `search` | Read |
| Any other `POST`, and every `PUT`, `PATCH`, `DELETE` | Write — asks first |
| GraphQL document containing a `mutation` | Write — asks first |
The guard errs toward over-asking. Some operations that are technically
non-destructive — exports, comparisons, validations — still ask for
confirmation. That's a deliberate trade: a spurious confirmation costs you a
sentence, and a missed one costs you a production change.
## What it does not cover
Write Guard gates only `call_r1` and `call_r1_gql`. These have their own safety
models and do not pass through it:
- `device_cli` — switch configuration over the live console
- `mop_replay` and autopilot runs — `dryRun`, the `unattended` acknowledgement,
and `armWrites` for connection-targeted writes
([Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/#replaying-and-autopilot))
- test-bed swaps and the switch restore tools with `apply: true` — preview by
default
- venue copy, element copy, and backup restore — reviewable plans run through
`mop_replay`
- Data Studio writes
- the web console's AI chat, where Write Guard is switched off — pin that chat
to a read-only connection unless you intend a write
## Reading a preview
Before you say yes, check three things:
1. **The tenant** — is this the connection you meant?
2. **The operation** — the method and path, not just Claude's summary of it.
3. **The body** — the preview lists the body's field names, not their values.
For anything that replaces rather than patches, ask Claude to show the exact
body it will send before you say yes.
## When you don't need it
A read-only R1 API client can't write regardless, so Write Guard adds only
friction there. The stronger control is always the credential's own permissions
in RUCKUS One — Write Guard is a second layer, not a substitute for issuing the
right API client.
## Related
- [Security model](https://docs.neuralconfig.com/r1-mcp/concepts/security/) — credentials, tokens, and what Claude can see
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/) — why the preview names a tenant
---
# Test beds
Source: https://docs.neuralconfig.com/r1-mcp/features/testbed/
The **Test Bed** feature is for labs where the same physical hardware has to
become a different setup on demand — a demo rig on Monday, a customer
reproduction on Tuesday.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com).
## The model
A **test bed** is a saved set of device configurations. Swapping to one means
moving the hardware you have into that state — which is more than restoring a
file, because serials, ports, and stack members don't line up between setups.
Tools: `testbed_save`, `testbed_list`, `testbed_get`, `testbed_delete`,
`testbed_capture`, `testbed_plan`, `testbed_apply`, `testbed_export`,
`testbed_import`, plus `switch_config_copy` and
`switch_config_restore_via_probe` for single-switch restores, and `config_diff`
to see what changed on a switch since its capture.
You can keep up to **50** test beds, each with up to **100** devices. A bed left
untouched for 365 days is deleted, together with its stored configs.
## The workflow
1. **Capture** — `testbed_capture` records the current state of the lab as a
test bed you can return to. Each switch needs its `venueId` and `switchId`
(the MAC). Capture takes a fresh R1 config backup — which evicts the oldest of
R1's roughly 7 retained backups for that switch — unless you pass an existing
`backupId`. The config text is mirrored to durable private storage and is
never shown to Claude; the capture reports only size and whether the config
contains secrets.
2. **Plan** — `testbed_plan` works out what has to change to get from where you
are to the target test bed. Read the plan before applying it; this is where
a mismatch between the saved bed and the hardware actually present shows up.
3. **Apply** — `testbed_apply` compiles the plan into a transition MOP, saves
it, and returns its `mopId`. It changes nothing on the devices itself. The
swap runs when you drive that MOP with
[`mop_replay`](https://docs.neuralconfig.com/r1-mcp/features/live-cli/#replaying-and-autopilot): step by
step, or unattended with `action: "start_auto", unattended: true`. Run
`mop_replay` with `dryRun: true` first. An empty plan is refused with
`nothing_to_apply`.
The **Swap lab hardware to a saved test bed** [prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) runs
this end to end and asks you for the target bed and mode.
## Export and import
`testbed_export` and `testbed_import` move a test bed between accounts or
environments — useful for handing a reproduction setup to someone else.
The `bundle` that `testbed_export` returns is **definition only**: inventory,
placement, and per-switch config metadata, with no config text. Importing it
creates the bed with each switch listed in `configsPending`, so you re-capture
each switch with `testbed_capture` on the new bench before planning.
The export's `download_url` depends on `format`:
| `format` | The download |
|---|---|
| `json` (default) | The full off-box archive, **with each switch's config text embedded**. Importing it restores the configs. |
| `html`, `pdf`, `docx` | A printable test-bed definition document — inventory, topology, and config metadata only, never config text |
:::caution
The `json` archive contains the switches' password hashes and SNMP communities.
It opens only in your own signed-in browser — keep the downloaded file out of
version control and shared drives. The definition bundle and the printable
documents carry no config text.
:::
## Config restore
Two restore paths exist for switches, and which one applies depends on whether
R1 still holds the switch's captured backup. R1 retains only a bounded number of
backups per switch, so an old one ages out.
- **In-place restore to startup config** — `switch_config_copy`, the normal path
while the captured backup is still retained. It reports the switch as
`restorable`, and `apply: true` issues the R1 restore, which overwrites the
startup config and **reloads the switch** — roughly ten minutes offline. It
warns loudly when the switch now runs a different firmware train from the one
the config was captured on, or when the captured train is unknown; the restore
is still allowed, so read the warning first. Other states: `restored`,
`offline`, `no_config`, `no_backup_id`.
- **Probe TFTP restore** — `switch_config_restore_via_probe`, for a switch whose
backup has aged out of R1. That state is reported as `evicted`, and once it
happens the in-place restore is gone: R1 has no API to re-inject a config. This
path carries the durable copy back onto the box over a TFTP download served by
an on-LAN [probe](https://docs.neuralconfig.com/r1-mcp/features/probe/), then reboots the switch onto it. It needs a
linked Probe MCP account (the dashboard's **Probe (config restore)** card) and
a probe on the same LAN as the switch, named by `probeId`. `reboot: false`
writes the startup config without rebooting (state `copied_no_reboot`).
Both default to a **preview**: without `apply: true` they report what would
happen and change nothing.
## What changed since the baseline?
`config_diff` answers "what changed on this switch since I captured it", line by
line — including after R1's own backup comparison can't help because the
baseline has aged out of R1's roughly 7 slots.
- **Baseline:** a stored capture — `baseTestbedId` plus the switch `serial`.
- **Compared against:** the switch's current config, taken from R1's newest
successful backup (the default), or another stored capture
(`compareTestbedId`).
- **Read-only:** it never takes a new R1 backup, because that would evict one.
With no usable backup it stops with `no_live_backup` — run `testbed_capture`
to get one.
- **Secrets stay hidden:** a credential line (passwords, SNMP communities,
RADIUS/TACACS keys) still shows up as changed, with its value replaced by
``.
- **Capped:** at most 400 emitted lines, with no paging — it reports what
changed, and can't be used to read a config back out. Two configs too
different for a useful line diff come back as counts plus a note.
`context` (0–10, default 2) sets how many unchanged lines surround each change.
## Working with test plans
Test beds pair naturally with [test plans](https://docs.neuralconfig.com/r1-mcp/features/live-cli/#test-plans): the
bed puts the hardware in a known state, and the test plan verifies behavior
against it with gated expectations and 90 days of regression history.
## A caution
Driving the transition MOP changes real hardware. Run it against a lab, read the
plan first, and dry-run it with `mop_replay` before you run it live.
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) does not gate test-bed swaps or the
switch restores — their own previews and `unattended` acknowledgement are the
safety net.
---
# Venue config copy
Source: https://docs.neuralconfig.com/r1-mcp/features/venue-copy/
The **Copy** feature snapshots a venue's configuration and replays it into
another venue — in the same RUCKUS One tenant or a different one. A copy is
never executed directly: it compiles into a [MOP](https://docs.neuralconfig.com/r1-mcp/features/live-cli/) that you
review, run under arming, and can reverse.
Enable it under Features in the [dashboard](https://r1-mcp.lanpulse.com). It is
generally available — no password.
## The pipeline
Six steps, two of them gates:
```mermaid
flowchart TD
extract["venue_extract snapshot the source venue"]
plan["venue_copy_plan diff vs target → apply-MOP"]
dry["mop_replay dryRun:true review every step"]
run["mop_replay / start_auto armWrites:true"]
verify["venue_copy_verify residual deltas"]
undo["venue_copy_undo compile a delete-MOP"]
extract --> plan
plan -->|"gate: acceptWarnings if target not empty"| dry
dry -->|"gate: armWrites names the target tenant"| run
run --> verify
run -.->|"if you need to reverse it"| undo
```
`venue_extract` produces the snapshot. `venue_copy_plan` diffs that snapshot
against the target venue and compiles the apply-MOP — it writes nothing. You
review the compiled steps with `mop_replay { dryRun: true }`, then run it with
`armWrites: true`, which names the target tenant before any write executes.
`venue_copy_verify` re-diffs afterwards to report what did not land, and
`venue_copy_undo` compiles a delete-MOP that reverses the run.
The copy engine is built **on** the MOP machinery rather than beside it. There
is no separate copy runner, so a copy is reviewable, resumable, and auditable
exactly like any other MOP. Enabling `copy` gives you the `mop_*` tools even if
you don't have [Live CLI](https://docs.neuralconfig.com/r1-mcp/features/live-cli/) enabled.
## Step 1 — extract a snapshot
`venue_extract` walks the venue's config surface into a portable snapshot: venue
metadata; WLAN activations plus the full shared WLAN definitions; the services
WLANs bind — DPSK pools, passphrases and identity groups, portal service
profiles, RADIUS server profiles, VLAN pools, Wi-Fi calling profiles, and
access-control profiles with their L2/L3 ACL, device and application policies;
switch profiles / VLANs / ACLs; AP ethernet-port profiles; AAA servers; AP groups;
17 venue settings singletons (radio, mesh, LED, syslog, SNMP agent, and others);
and the switch inventory. `venue_extract_domains` lists all 46 domains.
It is **chunked** for the 30-second [run budget](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget).
One call walks a bounded batch of domains and returns
`{ snapshotId, complete, domainsDone, domainsRemaining }`. If `complete` is
false, it must be called again with the same `snapshotId` until it is true — a
plan built on an incomplete snapshot skips objects whose definitions were never
captured.
A domain that errors — a feature the tenant hasn't provisioned returns 404, or a
transient 5xx — is recorded with its status and never aborts the run. Partial
snapshots are useful and resumable.
The config blob itself is never returned to the conversation, because it can
carry WLAN and RADIUS secrets. You get per-domain counts and a size.
| Tool | What it does |
|---|---|
| `venue_extract` | Capture (or continue capturing) a venue into a snapshot |
| `venue_extract_domains` | List the config domains a snapshot can capture |
| `venue_snapshot_list` | Your snapshots — venue, tenant, status, counts, size |
| `venue_snapshot_get` | One snapshot's metadata (never the config blob) |
| `venue_snapshot_delete` | Delete a snapshot |
:::note
Snapshots are useful on their own, before any copy is involved — a point-in-time
venue configuration capture and an as-built documentation artifact. They are
*working* artifacts, though: 20 per user, aged out after 30 days. To keep one,
seal it as a [backup](https://docs.neuralconfig.com/r1-mcp/features/backups/), which is retained indefinitely.
:::
## Step 2 — plan the copy
`venue_copy_plan` diffs a completed snapshot against a target and compiles the
apply-MOP. You give it the `snapshotId` and exactly one of:
- `target.venueId` — copy into an existing venue, or
- `target.newVenue.{name, address}` — create the venue as part of the copy.
**The mode is chosen by `targetConnection`:**
| Mode | How you select it | What happens to shared objects |
|---|---|---|
| **Same-tenant** | Omit `targetConnection`, or name the snapshot's own source connection | The WLANs and switch profiles already exist — the plan re-does the *activation* joins against their existing ids. Nothing shared is created. |
| **Cross-tenant** | Name a different saved [connection](https://docs.neuralconfig.com/r1-mcp/setup/connections/) | The shared objects don't exist in the target tenant, so each is **created** there, its dependencies bound, and then activated. |
| **Template** | `mode: "template"` | Builds a reusable venue **template** on the R1 console's own `/rec/templates/venues` surface instead of a real venue, so the result appears on the operator's Templates screen. Requires `target.newVenue`. |
`target.connection` and a top-level `connection` are accepted as aliases for
`targetConnection`; two that name different connections are refused with
`ambiguous_target_connection`. Unknown keys are rejected rather than silently
ignored — there is no `dryRun` on `venue_copy_plan`, because the plan never
writes; review it with `mop_replay { dryRun: true }`.
Per object, the diff resolves to **create**, **skip-identical**, or
**collision**. Which collision policy applies depends on what kind of object it
is — see below.
The plan returns `{ mopId, target, mode, crossTenant, collisionPolicy,
venueCreate, perDomain, stepsByDomain, totalWrites, stepCount, warnings,
operatorInputRequired, next }`. **Read the warnings before running** — they
name the cases the copy could not resolve on its own. If the target already
matches the snapshot, it returns "Nothing to copy … No MOP was created" with
no `mopId`.
See [What a venue copy carries](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/) for the per-domain
support matrix, and call `venue_copy_support` for the authoritative version
derived from the planner's own write registry.
## When the name already exists in the target
Copying into a tenant you have copied into before is the normal case, not the
exception, and **two different settings** govern it. They are not
interchangeable.
| Setting | Applies to | Values |
|---|---|---|
| `collisionPolicy` | Venue-scoped objects — AAA servers, AP groups, the settings singletons | `skip` (default) leaves a differing object alone; `update` overwrites it |
| `sharedCollision` | Tenant-scoped shared objects — WLANs, switch profiles, ethernet-port profiles, portals, RADIUS profiles, DPSK pools, identity groups, VLAN pools, Wi-Fi calling profiles, and the access-control family | `adopt` (**default**), `overwrite`, or `skip` |
Objects that are already identical are skipped under either setting.
**`adopt` is the default, and it is the behavior to understand.** The existing
target object is reused as it is: everything that referred to the copied object
is wired to *its* id instead, and if it is the kind of object a venue activates,
it is activated on the new venue. The object itself is never modified, and none
of this copy's profiles are bound to it.
**`overwrite` rewrites the existing object from the source** and binds this
copy's profiles to it.
**`skip` leaves it alone and doesn't wire or activate it**, so the copy lands
without that object.
In **template mode** the target tenant is not searched for existing template
objects, so `adopt` never finds one: a template copy creates its shared objects
afresh.
:::caution
**Matching is by name only — contents are never compared.** An `adopt` can join
your copy to an object that merely shares a name, and an `overwrite` can stomp
one. An overwritten shared object may be in use by **other venues in that
tenant**, which will see the new configuration.
Every adopted or overwritten object is named in the plan's `warnings`. Read them.
:::
:::note
**Nothing adopted or overwritten is ever deleted by `venue_copy_undo`**, and an
overwrite cannot be reversed — the previous body is not retained. The undo is
safe by construction rather than by flag: it can only delete ids the copy itself
created.
:::
## Write-only secrets
Some secrets are write-only: the source API accepts them on create but masks
them on read. A copy can only carry such a value verbatim when the source tenant
returns it in the clear.
- **Readable at the source** — the value copies through verbatim. Nothing to do.
- **Masked at the source** — the field becomes a `{{binding}}` placeholder and is
listed in the plan's `operatorInputRequired` manifest as
`{domain, name, field, hint, binding}`. The run **refuses** with
`missing_capture` until you supply the value in a `bindings` map at run start.
The affected fields are RADIUS shared secrets (AAA servers and 802.1X RADIUS
server profiles), AAA bind passwords, the guest-portal external key and
social-login OAuth app secrets, and DPSK passphrases.
A masked secret is never silently dropped and never invented. A plan against a
tenant that masks secrets is not a failure — it is telling you exactly which
values to hand it.
## The two safety gates
**Live-target guard (plan time).** Copying into an *existing* venue that already
has onboarded devices or activated config refuses with `error: "target_not_empty"`,
reporting the target's AP, switch, activated-WLAN, and switch-profile counts. Pass
`acceptWarnings: true` to proceed. A brand-new `target.newVenue` is always empty
and is never gated — the server cannot know which venue is production, so
populating one has to be a conscious decision.
**Run arming (run time).** The generated MOP declares one connection target that
every write step runs against, so `mop_replay` / `start_auto` require
`armWrites: true`, and arming names the exact tenant before any write executes.
These are separate boundaries and both apply.
:::caution
Never copy into a live production venue without an explicit per-operation OK.
Cross-tenant end-to-end runs belong on test tenants.
:::
## Step 3 — verify
`venue_copy_verify` re-diffs the source config against the now-populated target
venue and reports residual deltas — what would *still* be created or updated. Run
it after applying a plan to confirm the copy landed. Pass exactly one source —
the `snapshotId` you planned with, or a [`backupId`](https://docs.neuralconfig.com/r1-mcp/features/backups/) — plus
`targetVenueId` and the same `collisionPolicy`, so the residual counts line up.
It returns `{ complete, residualWrites, perDomain, warnings, verifyLimits,
subCollections }` and is read-only: it never writes (it issues GETs and
read-only `…/query` POSTs).
**`complete` does not mean "everything was checked".** Read `verifyLimits` for
what a re-diff structurally cannot cover:
- **Fields R1 never returns on a read** — DPSK passphrases, RADIUS and AAA
secrets — cannot be compared by any re-diff, in either direction.
- **A sub-collection is judged from its parent**, not compared item by item. The
passphrases under a DPSK pool are the case that matters, so `subCollections`
reports a per-parent source-versus-target **row count** as the strongest
evidence available. A count mismatch is ambiguous — either the children were
never created, or the parent was adopted and keeps its own — so it is reported
and deliberately never folded into `complete`.
### Verifying a template copy
A template copy has no venue to re-extract, so pass `mode: "template"` and
`targetTemplateId` instead of `targetVenueId`. Settings domains are re-read and
compared field by field; everything else is checked by **exact name**. It returns
`{ complete, checked, missing, differing, unverified, checks, verifyLimits,
plannedSkips, warnings, next }` plus the template's id and name.
**Template verify is the confirmation that a template copy landed — the run's
own steps are not.** On the console template surface R1's activity status is
unreliable in both directions, so a template write whose activity never
resolves is passed with a note rather than failed; only a terminal failure
fails the step.
- **`kind: "bind"` checks** confirm that a WLAN's DPSK pool, VLAN pool, Wi-Fi
calling, access-control or RADIUS profile is actually **joined** to the WLAN
template, read from the profile's own `/query` row. A missing bind means
re-issue that one bind, not re-run the copy.
- **`checkFailed: true`** means the read failed; **`nothingCompared: true`**
means the read succeeded but the template answered with none of the fields the
copy wrote. Both count in `unverified` and neither is a match or a miss.
- **`plannedSkips`** lists objects the plan deliberately did not write, with the
reason. They are not reported as missing.
`complete` requires zero `missing`, zero `differing` and zero `unverified`.
:::caution
Read `scope` on each check. `scope: "tenant"` means the name exists somewhere
among the tenant's templates — it does **not** prove that object is attached to
*this* venue template.
:::
## Step 4 — undo, if you need it
`venue_copy_undo` compiles a **delete-MOP** that reverses a completed copy. Pass
the `runId` of the copy run (`mop_replay` / `start_auto` report it).
The undo is driven by exactly what the copy captured: the venue it created —
deleting which cascades its settings, AAA servers, AP groups, and WLAN
activations — plus any shared objects a cross-tenant copy created in the target
tenant. Deletes run in reverse dependency order: the venue first, then WLANs,
switch profiles, ethernet-port profiles, RADIUS server profiles, DPSK pools
(their passphrases first), any identity groups R1 auto-generated from those
passphrases, portal profiles, VLAN pools, Wi-Fi calling profiles, access-control
profiles, their child L2/L3 ACL, device and application policies, and finally
identity groups. For a copy into an existing venue, each created WLAN is
deactivated and each switch profile disassociated on the venue before it is
deleted.
Like every other step it compiles but does not run. Review with
`mop_replay { mopId, dryRun: true }`, then run it armed.
Its limits are worth knowing before you rely on it:
- A **same-tenant clone** joins existing shared objects and creates nothing new,
so there is nothing to undo — only a newly created venue is deletable.
- A copy into an **existing venue** does not delete that venue, and the
venue-scoped objects it created there are not captured with reversible ids, so
only the shared objects it created are undone. You are warned when this
applies.
- Only a run that was **armed** can be undone.
- The run's record is kept for **7 days** after it started. After that
`venue_copy_undo` returns `run_not_found` and anything the copy created has to
be removed by hand.
:::danger
An undo issues real DELETEs against the target tenant. Review the compiled steps
before arming it.
:::
## Limits
| Limit | Value |
|---|---|
| Snapshots per user | 20 — shared with element snapshots and the working snapshots `backup_create` leaves; at the cap `venue_extract` returns `snapshot_limit_reached`, so delete one with `venue_snapshot_delete` |
| Snapshot retention | 30 days |
| Snapshot size | 5 MB of captured config; over it returns `snapshot_too_large` — restrict `domains` and re-extract |
| Compiled copy MOPs | 100 per user, kept 30 days — see the caution below |
| Undo window | 7 days from the run's start — the run record is then swept and `venue_copy_undo` returns `run_not_found` |
Snapshot config blobs are **encrypted at rest**, because they can carry DPSK
passphrases and RADIUS secrets, and no tool ever returns one.
:::caution
The MOPs the copy engine compiles are capped differently from the ones you
author. At 100, the **oldest is evicted** rather than the new one refused — the
alternative would be a copy workflow that blocks on rows you never asked to keep.
If a compiled plan is one you need to retain, `mop_export` it. A compiled MOP
that still has a run is never evicted or aged out while that run exists — undo
needs it — so the count can sit above 100 until the run expires.
:::
`venue_extract` and `venue_copy_verify` never write to R1. The only writes happen
when you **run** a `venue_copy_plan` MOP, armed.
## Next steps
- [What a venue copy carries](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/): The per-domain matrix: what carries same-tenant, cross-tenant, and into a template.
- [Copying one object](https://docs.neuralconfig.com/r1-mcp/features/element-copy/): Copy a single WLAN or profile with its dependency closure, without a venue.
- [Venue backups](https://docs.neuralconfig.com/r1-mcp/features/backups/): Keep a venue's configuration indefinitely, encrypted, and restore it later.
- [Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/): The engine that reviews, arms, and runs a compiled copy plan.
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/): How a cross-tenant target is named and kept isolated.
- [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/): Confirm-before-write, on top of run arming.
---
# What a venue copy carries
Source: https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/
Not every part of a venue's configuration copies, and what copies depends on
whether you are cloning within a tenant, copying across tenants, or building a
template. This page is the reference; the
[Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) page is the workflow.
**Call `venue_copy_support` for the authoritative answer.** It takes no
arguments, is read-only, and is derived from the planner's own write registry —
so it tracks what a copy actually does. The table below is that matrix in prose
form.
## The matrix
| Domain | Same-tenant | Cross-tenant | Template | Notes |
|---|---|---|---|---|
| Venue metadata + address | Created | Created | Created | Async (202); the new id threads into every later write. Created only when you plan into `target.newVenue` (or build a template); an existing `target.venueId` is diffed, never recreated |
| Venue settings singletons (radio, mesh, LED, …) | Updated | Updated | Updated | 17 domains: switch, AAA, radio, AP mesh, AP management-traffic VLAN, load balancing, directed multicast, DoS protection, mDNS fencing, BSS coloring, client admission control, AP LAN-port, LED, rogue AP, RADIUS options, syslog, SNMP agent. Syslog, SNMP-agent, and AP LAN-port settings have **no template equivalent**; mesh has a [narrower template enum](#template-mode-is-the-most-restricted) |
| AAA / RADIUS servers | Created | Created | Created | Shared secret and bind password are write-only — readable copies verbatim, masked becomes an operator-input binding. A server with `purpose: "DEFAULT"` is not created |
| AP groups + per-group radio | Created | Created | Created | AP serial membership is stripped — it's physical. The default AP group is auto-provisioned, not copied |
| WLAN activations | Re-activate the existing id | Create → resolve → bind dependencies → activate | WLAN template create → resolve → activate | The dependency binds that carry across are listed below |
| Portal service profiles (guest captive portal) | Reuse existing id | Create → resolve → bind to the WLAN | **No portal object** — the guest portal travels inline on the WLAN template | Base64 images ride inline in the create body. In a template, the guest-portal config travels as `wlan.guestPortal` and only the profile's branding images are lost |
| DPSK service pools | Reuse existing id | Create → resolve → bind to the WLAN | Created and bound | In template mode the pool is created **without** an identity group, and has no passphrases |
| DPSK passphrases | Ride the pool | Created under the recreated pool | **Not supported** | Readable copies verbatim; masked becomes an operator-input binding |
| Identity groups | Reuse existing id | Create → resolve | **Not supported** | Container only — member identities are not copied |
| RADIUS server profiles (Cloudpath / 802.1X) | Reuse existing id | Create → resolve → bind to the ethernet-port profile and/or WLAN | Created and bound to the template WLAN | Shared secret is write-only. Ethernet-port profiles aren't carried into a template at all, so there is no template ethernet-port RADIUS binding |
| AP LAN-port (ethernet-port) profiles | Re-activate existing | Create → resolve → activate per AP model and port | **Not supported** | Per-AP-serial overrides are **not** copied |
| Switch profiles (+ VLANs / ACLs) | Re-associate the existing id | Create → resolve → associate | Profile template create → resolve → associate | Children — VLANs, ACLs, trusted ports, voice VLANs, CLI template — embed inline in the create body |
| VLAN pool profiles | Reuse existing id | Create → bind to the WLAN | Created and bound | A per-AP-group bind widens to the whole WLAN. A WLAN whose pool didn't copy still activates, without VLAN pooling |
| Wi-Fi calling service profiles (ePDG) | Reuse existing id | Create → resolve by name → bind to the WLAN | Created and bound | Cross-tenant, its create returns no id, so it resolves by exact name (switch profiles do the same) |
| Access control profiles | Reuse existing id | Children created first → profile created → bound to the WLAN | Created and bound | Carries its four child policies by id in its own create body |
| L2 / L3 ACL policies | Reuse existing id | Created before the profile that references them | Created | Reached **only** through an access-control profile. A policy captured with no rules is skipped (see warnings) |
| Device policies | Reuse existing id | Created before the profile that references them | Created | OS / device-type rules |
| Application policies | Reuse existing id | Created before the profile that references them | Created | DPI signature rules copy verbatim; `USER_DEFINED` rules are rejected by R1 |
| Switch inventory | **Not copied** | **Not copied** | **Not copied** | Physical devices; re-onboard them at the target |
## The headline rules
**Physical devices are never copied.** Switch inventory is not part of a copy in
any mode, and AP serial membership is stripped from AP groups. Hardware is
re-onboarded at the target.
**Cross-tenant copies recreate shared objects and bind their dependencies.** A
guest-passphrase WLAN gets its portal service profile recreated and bound; a DPSK
network gets its service pool, identity group, and passphrases recreated and
bound; a Cloudpath / 802.1X WLAN and a RADIUS ethernet-port profile get their
RADIUS server profiles recreated and bound. Each of those bindings is what makes
the copied WLAN actually activatable in the target tenant.
**Not every missing binding blocks activation, and the difference matters.** If a
portal, DPSK pool, or RADIUS profile can't be copied, the WLAN is created but
left **un-activated** — it would come up broken, so it doesn't come up. If a VLAN
pool, Wi-Fi calling profile, or access-control profile can't be copied, the WLAN
**is** created and activated, just without that capability: no VLAN pooling, no
ePDG, or — in the access-control case — **unfiltered**, with no ACLs, no device or
application policy, and no rate limiting. Every one of those is named in
`warnings`; none is a silent drop.
**Reverse linkages are discovered, not read off the WLAN.** Portals, RADIUS
profiles, VLAN pools, Wi-Fi calling profiles, and access-control profiles are all
bound to a WLAN from the *profile's* side — the WLAN body carries no reference to
them — so the copy finds them by querying each profile family for the WLANs it
lists. A policy bound **directly** to a WLAN rather than through an access-control
profile is on a separate linkage path that is **not copied** and is invisible to
this discovery.
**Template mode is the most restricted**, and its exclusions are a property of
R1's template surface rather than of the copy engine:
| Skipped in template mode | Why |
|---|---|
| Portal service profiles | No `/rec/templates` portal object — the guest-portal config travels inline on the WLAN template instead; only the profile's branding images stay behind |
| DPSK passphrases | No passphrases sub-collection under a template pool |
| Identity groups | No standalone template create surface — which is why a template DPSK pool is created group-less |
| AP LAN-port profile activations | The template surface can't carry them |
| Syslog settings | A template expresses syslog as a server-profile *activation*, not the settings PUT the copy engine writes |
| SNMP-agent settings, AP LAN-port settings | No venue-level template equivalent |
| AP mesh settings, **conditionally** | A template accepts only `2.4-GHz` / `5-GHz` for `radioType`. A source venue holding anything else has the whole domain skipped rather than written with a different radio — harmless when mesh is off, which is the common case |
:::note
The template surface is the R1 console's own (`/rec/templates/venues`), so a
template a copy builds appears on the operator's Templates screen in the UI.
Templates are accessible and usable within the tenant without MSP. MSP
delegation and cross-tenant template sharing are untested and may behave
differently.
:::
## Warnings you should expect to read
`venue_copy_plan` returns a `warnings` array. These are the cases where the copy
could **not** resolve something on its own:
| Warning case | What it means |
|---|---|
| Guest-passphrase WLAN with no captured portal | The WLAN is created but may be left un-activated |
| DPSK network whose pool could not be copied | Typically its identity group was not captured; the WLAN is created but left un-activated |
| RADIUS / 802.1X profile not captured or copied | 802.1X will not function until a profile is created and bound |
| AP-group-scoped source activation | Widened to **all** AP groups — the source's AP-group ids don't map across tenants |
| AP-group-scoped VLAN pool bind | Widened to the whole WLAN, for the same reason. Re-scope per AP group at the target if it matters |
| VLAN pool or Wi-Fi calling profile not copied | The WLAN activates anyway, without that capability |
| Access-control profile not copied | The WLAN activates **unfiltered** — no ACLs, no device or application policy, no rate limiting |
| A child policy could not be copied | Blocks its access-control profile rather than creating one that is only partly wired |
| A policy captured with no rules (L2/L3 ACL, device, application) | Skipped — R1 refuses a rule-less policy — which blocks its access-control profile, so the WLAN activates unfiltered. R1's detail read of L3 ACL and application policies can drop their rules (an R1 bug); the warning says whether rules were confirmed lost (re-run `venue_extract`) or the policy is genuinely empty at the source |
| A tenant-default object (default DPSK pool, identity group, and similar) | Skipped: R1 auto-provisions its own in the target tenant, which may differ from the source's. Nothing was written, so verify does not check it |
| An application policy with `USER_DEFINED` rules | R1 rejects these server-side (202, then an async failure). Signature rules are unaffected — this is an R1 defect, not a copy defect |
| A shared object of the same name already exists | Adopted, overwritten, or skipped per [`sharedCollision`](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/#when-the-name-already-exists-in-the-target); every affected object is named |
| WLAN / switch profile / ethernet-port profile with no captured definition | The extract fan-out didn't finish. Re-run `venue_extract` to completion, then re-plan |
| Write-only secret masked at the source | Listed in `operatorInputRequired`; the run refuses with `missing_capture` until you supply it |
| Template: a domain the template surface can't carry | Skipped at plan time, per the table above |
## Next steps
- [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/): The extract → plan → run → verify → undo workflow this matrix describes.
- [Copying one object](https://docs.neuralconfig.com/r1-mcp/features/element-copy/): Element copy carries the tenant-scoped part of this matrix, without the venue.
- [Venue backups](https://docs.neuralconfig.com/r1-mcp/features/backups/): The same capture, kept indefinitely and encrypted, with a restore path.
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/): How the target tenant of a cross-tenant copy is chosen.
---
# Copying one object
Source: https://docs.neuralconfig.com/r1-mcp/features/element-copy/
Sometimes you don't want a venue. You want **one WLAN** — with its portal, its
RADIUS profile, its DPSK pool, and everything else it quietly depends on — moved
into another tenant.
That is **element copy**. It ships with the **Copy** feature, alongside
[venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/), and reuses the same MOP engine, the same
review-and-arm cycle, and the same undo.
## What you can start from
Three element types:
| `type` | The object |
|---|---|
| `wlan` | A WLAN (Wi-Fi network) |
| `switchProfile` | A switch profile, with its VLANs and ACLs |
| `ethernetPortProfile` | An AP ethernet-port (LAN-port) profile |
The point is the **closure**, not the object. Extracting a WLAN pulls in the
shared objects it binds — portal service profile, RADIUS server profiles, DPSK
pool and its identity group, VLAN pool, Wi-Fi calling profile, access-control
profile and its four child policies — because a WLAN recreated without them is
not a working WLAN.
Call `element_copy_support` for the authoritative list of which domains an
element copy carries. It is a filtered view of
[the venue-copy matrix](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/): the tenant-scoped shared
objects reachable downstream of an element, and nothing venue-scoped.
## The pipeline
1. **`element_extract`** — identify the object by `type` plus either `id`
(preferred, unambiguous) or `name` (matched **exactly**, and refused if more
than one object shares it). Optionally `connection` to read from a
non-default tenant. Like `venue_extract` it is chunked: if it comes back
`complete: false`, call it again with the same `snapshotId`.
2. **`element_copy_plan`** — pass the completed `snapshotId` and
`targetConnection`. It compiles an apply-MOP that creates the element and its
whole closure in the target tenant and wires them to each other. It writes
nothing. `connection` is accepted as an alias for `targetConnection`; passing
both with different values is refused with `ambiguous_target_connection`, and
an unknown key is an error rather than being ignored.
3. **`mop_replay { mopId, dryRun: true }`** — review every step.
4. **`mop_replay { mopId, armWrites: true }`** — run it. Arming names the target
tenant first.
5. **`element_copy_verify { runId }`** — confirm it landed.
Reverse it with `venue_copy_undo { runId }`. No venue is deleted, because none
was created.
:::caution[Undo is available for about 7 days]
`venue_copy_undo` and `element_copy_verify { runId }` both need the run's record,
and run records are swept 7 days after the run started. After that both return
`run_not_found`, and the created objects have to be removed by hand.
:::
## Two things that surprise people
### Same tenant needs a rename
:::caution
**A same-tenant element copy writes nothing and produces no MOP unless you rename
it.** The copy names every object exactly as the source does, so each one collides
with itself and R1 refuses the duplicate name.
Pass `rename` to `element_copy_plan` to make it write:
| `rename` | What gets created |
|---|---|
| `{ name: "Guest-2" }` | The element only, under the new name. Its shared services (DPSK pool, portal, RADIUS, VLAN pool, Wi-Fi calling, access-control profile and its policies) keep their names, are **adopted**, and the new element is bound to the very same objects. |
| `{ prefix: "COPY-", scope: "closure" }` | Every object the copy creates is renamed — a fully independent duplicate that shares nothing. The default `scope` is `element`, which renames only the element. `suffix` works the same way. |
| `{ map: { "": "" } }` | Specific objects, by exact source name. Wins over `prefix`/`suffix`. |
| `{ ssid: "…" }` | The WLAN's broadcast SSID. |
A renamed WLAN **keeps the source SSID** — renaming never moves the SSID on its
own, so without `ssid` the copy broadcasts the same network name as the original
(the plan warns). Anything ambiguous — a `map` key that matches nothing, a rename
that yields the same name, two objects renamed onto one name — is refused rather
than half-applied.
Cross-tenant copies need no rename. If you want the object on another venue in the
*same* tenant rather than a second copy of it, that is a
[venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/).
:::
### Nothing is activated
An element copy has no venue to activate on, so the element and its closure are
created and fully wired — and then left **unactivated**. Activate them where you
want them live afterwards.
This is the deliberate difference from a venue copy, which activates as it goes.
It also means element copy carries no venue-scoped configuration at all: no AP
radio, mesh, LED, or syslog settings, no AAA servers, no AP groups. Those belong
to a venue.
## Name collisions in the target
The second copy into a tenant you have copied into before is the normal case, and
`sharedCollision` governs it — the same setting, the same three values, and the
same default (`adopt`) as a
[venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/#when-the-name-already-exists-in-the-target).
Matching is **by name only**; contents are never compared.
`element_copy_plan` has no `collisionPolicy` — that setting governs
venue-scoped objects, and an element copy has none. Passing it is refused as an
unknown argument. Use `sharedCollision` to decide what happens to a same-named
object.
:::note
`adoptExisting` still works and is **superseded** by `sharedCollision`, where
`adoptExisting: false` means `sharedCollision: "skip"`. Prefer `sharedCollision`
— it is the only one that offers `overwrite`.
:::
## Verifying
**After the copy has run, verify with `runId`** — the plan returns it as
`verifyAfterRunWith`. Every object the run created is re-read by the id the run
captured, and its live name compared with the name the create sent; every bind is
re-read from the bound profile's `/query` row. It needs no other arguments.
Objects the copy adopted are not checked, because the run never wrote them.
**Before a run**, pass `snapshotId` instead. That mode queries the target tenant
for the exact name of every object the copy would create, and reports present or
missing. Its checklist comes from the same plan the copy compiled, so **pass the
same `sharedCollision`, `domains` and `rename` the copy used** (the plan returns
them as `verifyWith`) — a different policy checks a different list than the copy
created.
:::caution
Don't use `snapshotId` mode after the copy has run. The copy's own objects are in
the target by then, read as pre-existing, and are adopted off the checklist — so a
**successful** copy reports `checked: 0, complete: false`. Use `runId`.
:::
In `snapshotId` mode it separates three outcomes:
- **Checked** — objects the copy creates, name-verified in the target.
- **`adoptedObjects`** — objects that already existed and were adopted. These are
never name-checked, because the name that would prove them present belongs to
the pre-existing object.
- **`plannedSkips`** — objects the compiler deliberately dropped.
:::note
Neither mode is a **field-level re-diff**. An element copy has
no target venue to re-extract, so it cannot reach
[`venue_copy_verify`](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/#step-3--verify)'s depth — and it says so
in its own response.
:::
## Next steps
- [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/): The whole-venue pipeline, and the collision policies element copy shares.
- [What a venue copy carries](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/): The full per-domain matrix that element_copy_support filters.
- [Venue backups](https://docs.neuralconfig.com/r1-mcp/features/backups/): Keeping a whole venue's configuration rather than moving one object.
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/): Saving the target tenant an element copy writes to.
---
# Venue backups
Source: https://docs.neuralconfig.com/r1-mcp/features/backups/
A **backup** is a venue's configuration captured and kept. It is the durable
sibling of a [venue-copy snapshot](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/): the same capture, but
retained indefinitely, encrypted at rest, and restorable.
Backups ship with the **Copy** feature — enable that under Features in the
[dashboard](https://r1-mcp.lanpulse.com) and the `backup_*` tools appear.
## Backup or snapshot?
They capture the same thing. What differs is what happens to it afterwards.
| | Snapshot (`venue_extract`) | Backup (`backup_create`) |
|---|---|---|
| Retention | 30 days, then swept | **Indefinite** — nothing expires it |
| How it goes away | Ages out, or `venue_snapshot_delete` | **Only** `backup_delete` |
| Per user | 20 | 50 |
| Encrypted at rest | Yes | Yes |
| Purpose | The working input to a copy | The artifact you keep |
Use a snapshot to *do* something now. Use a backup to be able to do something
later.
```mermaid
flowchart TD
venue["venue_extract or backup_create venueId"]
snap["Snapshot 20 per user, 30 days"]
backup["Backup encrypted, kept until deleted"]
plan["backup_restore compiles an apply-MOP"]
inplace["Same venue restore in place"]
newvenue["A new venue"]
other["Another tenant via targetConnection"]
venue --> snap
snap -->|"backup_create snapshotId seal, no re-read of R1"| backup
backup --> plan
plan -->|"review dryRun, then run armed"| inplace
plan --> newvenue
plan --> other
```
Both capture paths end in the same sealed artifact, and a restore from it can
target the venue it came from, a brand-new venue, or a different tenant.
:::caution
There is **no TTL on a backup**. Nothing frees a slot for you — at 50 you must
delete one before taking another, and `backup_delete` is irreversible.
:::
## Taking one
There are two ways in, and the cheap one is worth knowing.
1. **Capture a venue directly.** Pass `venueId`, optionally `connection` and
`domains`. This runs the same extract a copy does, so it is **chunked** for
the 30-second [run budget](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget): if it
needs more calls it returns `{ status: "building", snapshotId,
domainsRemaining }` and must be called again with that `snapshotId`. It seals
itself once the extract completes. Pass `label` and `note` on the final call.
The backup cap is checked **before** anything is extracted. The working
snapshot it builds counts against your 20 snapshots (`snapshot_limit_reached`
at the cap) and is left behind after sealing — `venue_snapshot_delete` frees
its slot.
2. **Or seal a snapshot you already have.** Pass the `snapshotId` of a completed
`venue_extract` instead. Nothing is re-read from R1, so this is cheap — if you
have just extracted a venue in order to copy it, sealing that same snapshot
costs one call.
`backup_create` returns `{ id, venueId, venueName, label, note, domains,
domainsIncomplete, objectCounts, plaintextBytes, encrypted, createdAt }`.
:::note
**Read `domainsIncomplete`.** A backup sealed from a partial extract is a partial
backup, and a restore can only ever restore what was captured. The field names
exactly what is missing.
:::
## The tools
| Tool | What it does |
|---|---|
| `backup_create` | Capture and seal a venue, from a `venueId` or a completed `snapshotId` |
| `backup_list` | Your backups, newest first — venue, label, source tenant, domains, counts, size. Filter by `venueId` or `connection` |
| `backup_get` | One backup's metadata |
| `backup_restore` | Compile a restore into a reviewable MOP |
| `backup_delete` | Delete the D1 row and its encrypted blob — irreversible |
## The config blob is never returned
No tool returns a backup's configuration, and **there is deliberately no export
path**. `backup_list` and `backup_get` return metadata only — venue, label,
captured domains, per-domain object counts, sizes, timestamps.
The reason is what a venue config contains: DPSK passphrases and RADIUS secrets.
The blob is encrypted at rest with the Worker's key and only ever decrypted
server-side, to diff it while compiling a restore.
## Restoring
`backup_restore` does **not** run anything. It diffs the stored config against a
target and compiles exactly the same reviewable apply-MOP that
[`venue_copy_plan`](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) produces — which means the review, arm,
verify, and undo steps are identical, and so are the limits.
Pass `backupId` and exactly one of:
- **`target.venueId`** — restore into an existing venue, *including the one it came
from*. This is restore-in-place.
- **`target.newVenue.{name, address}`** — rebuild it as a fresh venue.
Optionally `targetConnection` (a different saved connection makes it a
**cross-tenant restore**, recreating shared objects in that tenant exactly as a
cross-tenant copy does), `domains` to restore a subset — just the WLANs, say —
plus `collisionPolicy`, `sharedCollision`, `acceptWarnings`, and `mode`.
`connection` and `target.connection` are accepted as aliases for
`targetConnection`; two that name different connections are refused with
`ambiguous_target_connection`, and an unknown key is an error rather than being
ignored.
Then the familiar cycle:
1. Review with `mop_replay { mopId, dryRun: true }`.
2. Run it with `mop_replay { mopId, armWrites: true }` — arming names the target
tenant before any write executes.
3. Confirm with `venue_copy_verify { backupId, targetVenueId }`.
4. Reverse it with `venue_copy_undo { runId }` if you need to — within 7 days of
the run; after that the run record is gone and undo returns `run_not_found`.
:::danger
**A restore overwrites configuration in the target venue.** Restoring into a
non-empty existing venue refuses with `target_not_empty` unless you pass
`acceptWarnings: true` — that gate is the only thing standing between a
restore and a production venue. Never point one at production without an
explicit go-ahead.
:::
### What a restore cannot bring back
Everything a copy cannot carry, a restore cannot either — with one addition that
catches people out:
- **Masked write-only secrets were never captured.** Where R1 masked a secret
on read — a RADIUS or AAA shared secret, a bind password, the guest-portal
external key, a social-login app secret, or a DPSK passphrase — it comes back
as an `operatorInputRequired` binding you supply at run start; the run
**refuses** with `missing_capture` rather than restoring a venue with silently
missing secrets. Secrets the source returned in the clear were captured and
restore verbatim.
- **Physical devices are never restored.** Switch inventory and AP serial
membership are not part of a backup in any mode.
- **A partial backup restores partially** — see its `domainsIncomplete`.
If a restore can't load the backup: `backup_not_found` means no such backup for
you; `backup_blob_missing` means the row exists but its encrypted blob is gone
(delete the row); `backup_unreadable` means the blob could not be decrypted with
the deployment's current key — the backup is intact, so don't delete it.
## Limits
| Limit | Value |
|---|---|
| Backups per user | 50 — `backup_limit_reached`, and nothing frees itself |
| Retention | Indefinite; `backup_delete` is the only removal |
| Size | 5 MB of captured config; over it returns `backup_too_large` — back up fewer `domains` separately |
## Next steps
- [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/): The extract → plan → run → verify → undo pipeline a restore reuses.
- [What a venue copy carries](https://docs.neuralconfig.com/r1-mcp/features/venue-copy-support/): The per-domain matrix — the same one governs what a restore puts back.
- [Copying one object](https://docs.neuralconfig.com/r1-mcp/features/element-copy/): Move a single WLAN or profile between tenants instead of a whole venue.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): Every cap and retention window in one place.
---
# GraphQL API support
Source: https://docs.neuralconfig.com/r1-mcp/features/graphql/
The **GraphQL** feature adds `call_r1_gql`, which queries the RUCKUS AI internal
GraphQL services — the data behind Network Health, Incidents, IntentAI, Service
Validation, and Zoom Call QoE. It answers questions the REST API doesn't expose.
This is an [Early Access](https://docs.neuralconfig.com/r1-mcp/reference/features/#early-access) feature: unlock Early
Access on your account, then turn it on in the **Early Access** card of the
[dashboard](https://r1-mcp.lanpulse.com). Its toggles appear once the password
is accepted; the **Features** card holds only the generally available features.
## The four services
`call_r1_gql` takes a `service` argument that picks the endpoint. All four run on
the same host and the same bearer token as REST for the connection you query, so
there is no extra credential to configure.
| `service` | What it covers |
|---|---|
| `analytics` | Network Health, Incidents, Config Change, client and incident troubleshooting |
| `intentAI` | IntentAI |
| `serviceGuard` | Service Validation — **has real mutations** |
| `callQoe` | Zoom Call QoE |
Beyond `service` and `query`, it accepts `variables`, `operationName` for a
document that defines several operations, `retryOn429`, and `connection` — the
label or id of the RUCKUS One connection to query. With more than one connection
enabled, `connection` is required: leaving it out returns `connection_required`
(see [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/#choosing-a-connection-in-conversation)).
## Introspection is disabled
All four services refuse introspection. That is a property of the RUCKUS
services, not a restriction R1-MCP adds — so there is no way to discover the
schema by probing it.
Instead, R1-MCP ships curated schema documents that Claude fetches with
[`get_reference`](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/) before composing a query:
| Doc | Covers |
|---|---|
| `gql-analytics` | The analytics surface, and IntentAI |
| `gql-troubleshooting` | Client and incident troubleshooting, and Call QoE |
| `gql-service-guard` | Service Validation |
The docs are organized by **surface**, not one per service — which is why
IntentAI lives in `gql-analytics` and Call QoE in `gql-troubleshooting`.
## Always check `gqlErrors`
A GraphQL request can fail while returning HTTP 200, because execution-time
errors arrive in-band. `call_r1_gql` hoists both `data` and `gqlErrors` onto the
response so this is hard to miss: `gqlErrors` is `null` when the query was clean
and populated whenever the service returned errors. A request that fails before
the service answers (a network error, a connection that can't be resolved) has
`ok: false` with `gqlErrors: null`, so **check `ok` and `gqlErrors` together. A
populated `gqlErrors` means the query failed, whatever the HTTP status says.**
Validation failures arrive as HTTP 400. On `analytics`, `intentAI`, and
`serviceGuard` those errors are **generic** — `DATAAPI-10102` or
`SERVICEGUARD-10102` — and do not name the offending field. Only `callQoe`
identifies the bad field. So when a query fails validation, the fix is to
re-check it against the reference doc rather than to expect the error to point at
the problem.
## Rate limits and retries
GraphQL requests are always POSTs, so a `429` is **never** auto-retried by
default — unlike the idempotent REST methods described in
[How code mode works](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#retries).
`retryOn429: true` opts in, and is safe only for read queries. `serviceGuard` has
real mutations, which are not safe to replay.
:::caution
Without [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/), a `serviceGuard` mutation
runs as soon as it is sent. With Write Guard on, any document containing a
`mutation` does not run on first send: it returns a `confirm_required` preview,
and runs only when re-sent unchanged with its `confirmToken`.
:::
Everything else behaves like `call_r1`: the same 401 refresh-and-retry, the same
structural error envelope, and the same shared run
[budget](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget).
## See also
- [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/) — `get_reference` and the schema documents
- [Core tools](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/) — the REST side, `call_r1`
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/) — unlocking Early Access
---
# Probe — on-LAN ground truth
Source: https://docs.neuralconfig.com/r1-mcp/features/probe/
The **Probe** feature lets Claude check what RUCKUS One *believes* against what
is actually on your LAN. R1 tells you a controller's view; a probe on the wire
tells you whether that view is true.
This is an [Early Access](https://docs.neuralconfig.com/r1-mcp/reference/features/#early-access) feature: unlock Early
Access, then turn it on in the **Early Access** card of the
[dashboard](https://r1-mcp.lanpulse.com). Its toggles appear once the password
is accepted; the **Features** card holds only the generally available features.
## You connect one connector, not two
You add **only R1-MCP** to Claude. R1-MCP calls Probe MCP itself, machine to
machine over a private binding — there is no second connector to install.
What you do need is a **one-time consent link** on the Probe MCP side, which is
what authorizes R1-MCP to drive your probes on your behalf.
```mermaid
flowchart LR
claude["Claude"]
r1mcp["R1-MCP"]
probemcp["Probe MCP"]
lan["Your LAN switches, APs, syslog, SNMP"]
consent["One-time /link consent opened in your browser"]
claude -->|"probe_call"| r1mcp
r1mcp -->|"private binding signed identity assertion"| probemcp
consent -.->|"authorizes this pairing"| probemcp
probemcp -->|"live queries"| lan
```
Claude issues `probe_call` to R1-MCP; R1-MCP forwards it to Probe MCP over the
private binding, signing an identity assertion for your account; Probe MCP
resolves that against its own consent table and queries your LAN. Until you
complete the consent link, that resolution fails and the call returns
`not_linked` with a `link_url` — open it once in a browser and it stops
happening.
Once the feature is on, the dashboard also shows a **Probe connection** card. It
reads "Connected to probe-mcp as …" when you're linked, or offers a **Connect
probe-mcp** button that opens the same consent page — the easiest way to do the
one-time link.
`probe_link_status` reports the current state: `{ linked: true, email }` when
connected, `{ linked: false, link_url }` when not. Call it first when a probe
call comes back `not_linked`, or before starting a probe-backed workflow.
## The four R1-MCP tools
| Tool | What it does |
|---|---|
| `probe_link_status` | Whether your account is connected to Probe MCP, and the link URL if not |
| `probe_describe` | The probe tools available, with a JSON Schema for each |
| `probe_call` | Invoke one read-only probe tool |
| `probe_reconcile` | The cloud-versus-LAN divergence sweep (see below) |
Schemas live on the probe side and can gain fields between deploys, so
`probe_describe` is fetched before composing `probe_call` arguments rather than
assumed. It works before your account is linked — schemas only, no data.
## What `probe_call` can reach
The exposed surface is read-only and deliberately narrower than what Probe MCP
itself can do:
| Group | Tools |
|---|---|
| Inventory | `list_probes`, `probe_status`, `list_devices`, `inventory`, `reconcile_inventory` |
| Onboarding | `auth_sessions` — real 802.1X / RADIUS / DHCP outcomes seen on the wire |
| Switch ports | `poe_status`, `port_diag` |
| Topology | `topology` — live LLDP and association data |
| Logs | `query_syslog`, `search_syslog`, `syslog_rollups` |
| SNMP | `snmp_get`, `snmp_walk`, `snmp_metrics` |
CLI, packet capture, traffic, and egress tools are **not** exposed through
R1-MCP, and `probe_describe` filters them out of the schema listing.
`probe_call` will not accept a tool name outside this list.
### Two boundaries, not one
Probe MCP's side of the link and R1-MCP's side draw different lines, and it is
worth knowing which one you are reading about.
| | Set by | Covers |
|---|---|---|
| **Security boundary** | Probe MCP's companion allowlist | **36 of the 43** probe functions — what a linked R1-MCP is *permitted* to call. It is deny-by-default, and it is the control that matters for what your consent grants |
| **Product boundary** | R1-MCP's own exposed list | The **15** read-only tools above — what R1-MCP actually offers the model today |
The 15 are a deliberate subset of the 36. So when
[Probe MCP's linking page](https://docs.neuralconfig.com/probe-mcp/linking-with-r1-mcp/) says the grant includes the
SSH device CLI, that is accurate about the *permission* — and R1-MCP ships no way
for the model to use it. Widening the product boundary later needs no change on
the Probe MCP side, which is exactly why the permission you approve is the one to
read carefully.
Four granted functions sit outside the exposed 15 because R1-MCP calls them
itself, never the model:
| Function | When R1-MCP calls it |
|---|---|
| `serve_tftp`, `stop_tftp` | During [test bed config restore](https://docs.neuralconfig.com/r1-mcp/features/testbed/) |
| `r1_forward_configure`, `r1_forward_remove` | When a location (LBS) source is set up or removed — these **write** the probe's LBS forwarding configuration |
A fifth, `forward_status`, is granted but not called by R1-MCP today.
For a live CLI session to R1-managed switches and APs, the tool you want is
`device_cli` under [Live CLI](https://docs.neuralconfig.com/r1-mcp/features/live-cli/) — not the probe.
## `probe_reconcile` — the divergence sweep
`probe_reconcile` is the composite worth knowing by name. It joins the R1 AP and
switch inventory against what the probe actually sees, in one call, and returns
divergent devices first.
| Verdict | Meaning |
|---|---|
| `confirmed_online` | Cloud and LAN agree — collapsed to a count unless you ask for the detail |
| `dead` | Offline in both |
| `disconnected_from_cloud` | Cloud says offline, but the device is **alive** on the LAN — the cloud path is broken, the device is fine |
| `missing_from_lan` | Cloud says online, but the probe can't see it |
Matched devices can also carry `mismatches` — an `ip` mismatch is often just a
management interface versus a LAN interface, not a fault.
:::caution
`missing_from_lan` is real divergence only for devices that share the probe's LAN
segments. Devices at other sites are invisible to the probe by design, so scope
the sweep with a `venueId` before reading anything into that verdict.
:::
It also reports `rogue` devices — things on the LAN that RUCKUS One does not
manage. The default filter shows alive infrastructure-role devices only and is
capped; ask for all rogues, or none, if the default isn't what you want.
The R1 side of the sweep always comes from your **default**
[connection](https://docs.neuralconfig.com/r1-mcp/setup/connections/): `probe_reconcile` has no `connection`
argument, so with several tenants connected it reconciles only the default one.
## Verifying a write
The probe's other use is confirming that a change to R1 actually took effect on
the wire. The `probe-verify` [reference doc](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/) maps each
class of write to the check that verifies it — `auth_sessions` for WLAN and AAA
changes, `port_diag` and `poe_status` for port configuration, `probe_reconcile`
for anything that affects inventory, and topology / syslog / SNMP for the rest.
## Error envelopes
Probe MCP's errors pass through **verbatim** — R1-MCP never rewrites them — so
they can be acted on directly:
| Error | What to do |
|---|---|
| `not_linked` (with `link_url`) | Open the link once in a browser to consent |
| `probe_offline` | The probe itself isn't reachable; check it before retrying |
| `tool_failed` | The probe tool ran and failed; the probe's own message says why |
| `companion_unavailable` | This deployment has no probe integration wired |
| `ambiguous_connection` | More than one probe connection matched; the envelope echoes the choices |
| `unknown_tool` | The tool is not in R1-MCP's allowlist on the Probe MCP side |
| `no_identity` | Your account has no Google identity to link against — returned by every probe tool |
| `probe_unreachable` | R1-MCP could not reach Probe MCP at all; `detail` says why. Retry later |
| `bad_assertion` | Probe MCP rejected R1-MCP's signed identity — a deployment problem, not yours; contact [support](https://support.neuralconfig.com/r1-mcp?from=docs) |
| `companion_disabled` | Probe MCP has no companion key configured — also a deployment problem |
`probe_reconcile` adds `ambiguous_probe` when your account has more than one
probe and you didn't name one; it auto-resolves when there is exactly one. It can
also return `no_probes` (no probe registered on your Probe MCP account),
`no_cloud_devices` (nothing in the R1 inventory — or in the `venueId` you gave —
to reconcile), and `r1_query_failed` (the R1 inventory read failed; R1's status
and body are passed through).
## See also
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/) — unlocking Early Access
- [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/) — the probe also serves TFTP config restore for an evicted switch
- [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/) — the `probe-verify` playbook
---
# Data Studio dashboards
Source: https://docs.neuralconfig.com/r1-mcp/features/data-studio/
The **Data Studio** feature lets Claude build charts and dashboards in RUCKUS
One's Data Studio — the Apache Superset console over Druid — without you
touching the UI. A published dashboard is a first-class deliverable: you ask for
it in conversation, and a human opens it in Data Studio afterwards.
This is an [Early Access](https://docs.neuralconfig.com/r1-mcp/reference/features/#early-access) feature: unlock Early
Access, then turn it on in the **Early Access** card of the
[dashboard](https://r1-mcp.lanpulse.com). Its toggles appear once the password
is accepted; the **Features** card holds only the generally available features.
No extra credential is involved. The tools drive Data Studio with the same
RUCKUS bearer token R1-MCP already mints from your
[connection](https://docs.neuralconfig.com/r1-mcp/setup/connections/).
Every Data Studio tool except the two notes tools takes an optional `connection`
(label or id). With more than one connection enabled you must name one, or the
call returns `connection_required`; with no connection at all it returns
`no_connection`.
## The build order that works
Doing these out of order is the main way a dashboard comes out empty or broken:
1. **Discover the dataset** — `ds_list_datasets`, then `ds_dataset_fields`.
Dataset ids are per-tenant integers and must always be discovered, never
assumed.
2. **Validate the query** — `ds_query` runs a Superset query *without* saving
anything, so you can see real venue data and refine metrics, filters, and
scope before committing.
3. **Create the dashboard shell** — `ds_build_dashboard`.
4. **Create each chart attached to it** — `ds_build_chart` with
`dashboards: []`.
5. **Lay it out and publish** — `ds_update_dashboard` with `positionJson`, and
`published: true`.
6. **Check it renders** — `ds_diagnose_charts`.
:::caution
**Attaching a chart is what creates dashboard membership.** Referencing chart ids
inside `positionJson` does *not* register them as members, and those charts will
not render. Each chart must be created (or updated) with
`dashboards: []`. When a `positionJson` references non-member
charts, the response carries a `membershipWarning` naming them.
:::
`ds_build_chart` checks two things before it writes:
- **The dataset id must agree** across `datasourceId`, `params.datasource`, and
the query context. If they differ, the write is refused with
`datasource_id_mismatch` — such a chart would save but render empty.
- **The viz type** is checked against a list of types known to render. A type that
is known not to render, or isn't on the list, gets a `vizTypeWarning`. The chart
still saves, so read the warning.
Dashboard calls return a `dashboardUrl` — the link to open the dashboard in Data
Studio.
## RUCKUS's chart limits
RUCKUS enforces performance guardrails on every Data Studio chart and dashboard.
A chart outside them errors on save or render, so reduce it rather than retrying:
| Limit | Value |
|---|---|
| Dimensions per chart | At most 6 (`DATASTUDIO-20010`); 3–4 performs best |
| Time range | At most 31 days — use `Last month`, not `Last quarter` |
| Time grain | Must be one supported for the chosen range |
| Unpaginated table | At most 500 rows — enable server pagination for more |
| Charts per dashboard | At most 40 across all tabs; 20 or fewer recommended |
## New dashboards are drafts
A newly created dashboard defaults to **draft**, and a draft is visible only to
its owner — which is the API client, not you. If you look in Data Studio and the
dashboard isn't there, this is almost always why.
Pass `published: true` — on `ds_build_dashboard` at creation, or on
`ds_update_dashboard` afterwards — to make it visible to everyone in the tenant.
Charts and dashboards created this way are **API-managed**: the API client owns
them, and they show as "Modified by Application …" in the UI. You can still add
them to your own dashboards there. Only API-owned charts and dashboards can be
updated or deleted through these tools; anything else returns 403 or 404, passed
through for you to inspect. `ds_list_dashboards` likewise sees only the
dashboards the API client owns, not ones you built by hand.
:::caution
You can't delete API-managed charts or dashboards in the Data Studio UI.
`ds_delete_chart` and `ds_delete_dashboard` are the only way to clean them up,
and deleting a dashboard leaves its charts in place — delete those separately.
:::
## The 16 tools
| Group | Tools |
|---|---|
| Discovery | `ds_list_datasets`, `ds_dataset_fields` |
| Ad-hoc query | `ds_query` |
| Authoring | `ds_build_chart`, `ds_build_dashboard` |
| Diagnosis | `ds_diagnose_charts` |
| Learned notes | `ds_save_note`, `ds_list_notes` |
| Chart lifecycle | `ds_list_charts`, `ds_get_chart`, `ds_update_chart`, `ds_delete_chart` |
| Dashboard lifecycle | `ds_list_dashboards`, `ds_get_dashboard`, `ds_update_dashboard`, `ds_delete_dashboard` |
`ds_dataset_fields` returns each column and named metric with its `format` — the
d3-format or unit string such as `BPS`, `BYTES`, or `,.2%`. That's what resolves
axis units and the fraction-versus-percent question, so it's worth asking for
when a chart's numbers look wrong by a factor of 100.
## When a chart saves but won't render
A chart can save successfully, and its bare query can pass `ds_query`, and it
still throws "Unexpected Error" in the Data Studio UI. That happens when a
*render-time* field is invalid — the classic case being an `annotation_layers`
entry missing the required `showMarkers`, which is only validated once the render
injects the layers into the query.
`ds_diagnose_charts` reproduces the real render: it replays each chart's query
context **with** its annotation layers injected, and reports Superset's own error
verbatim plus a recognition hint for known classes. It is read-only.
Point it at a specific `dashboardId` after building a dashboard — that checks
exactly that dashboard's member charts, with no tenant-wide noise.
Failed `ds_query` calls surface the same way: the response carries a top-level
`queryErrors` array holding Superset's own error text, which usually names the
offending column or metric.
## Notes that survive the conversation
`ds_save_note` records a quirk you or Claude worked out — a viz type that needs a
particular field, a post-processing shape Superset insists on — under a free-form
`topic`. Notes are private to your account and resurface automatically on
`ds_list_notes` and on the `data-studio`
[reference doc](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/), so a hard-won discovery isn't
re-learned next session.
## See also
- [Bundled reference docs](https://docs.neuralconfig.com/r1-mcp/reference/reference-docs/) — the `data-studio` recipe and caveats
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/) — unlocking Early Access
- [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/) — which tenant's Data Studio you're building in
---
# Live Console
Source: https://docs.neuralconfig.com/r1-mcp/features/live-console/
The **Live Console** is a page in the R1-MCP dashboard that keeps updating while
you talk to Claude. A conversation is turn-based; a client's signal is not. The
console covers that gap — you watch a client's events and metrics tick
continuously in one window while you work the problem in another.
This is an [Early Access](https://docs.neuralconfig.com/r1-mcp/reference/features/#early-access) feature: unlock Early
Access, then turn it on in the **Early Access** card of the
[dashboard](https://r1-mcp.lanpulse.com). Its toggles appear once the password
is accepted; the **Features** card holds only the generally available features. Open it at
`https://r1-mcp.lanpulse.com/console`.
## It's driven by watches
The console shows **watches** — the same watches the
[webhooks feature](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/#watches-reproduce-and-catch)
uses. There are two ways to start one:
- **Ask Claude.** `watch_client` arms a watch on a client MAC. It belongs to the
[Webhooks](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) feature, so that must be
on too — with only the console enabled, Claude has no way to start a watch.
With the console feature enabled, that call also returns a `consoleUrl` — a
deep link straight to the live window for that watch, which Claude will hand
you.
- **Add it on the page.** Enter a client MAC in the console itself.
There is deliberately no separate "console" tool. `watch_client` is the single
registration point; enabling the feature is what makes it hand back the link.
A watch Claude starts while the page is already open is pulled into the list
without a refresh.
A watch added on the page lasts **2 hours**; one Claude starts with
`watch_client` lasts 24 hours by default. You can have up to **100** active
watches; past that, a new one is refused with `watch_limit_reached`. Because the
page and Claude share one set of watches, **Stop** on a card cancels the watch
everywhere — including the in-chat notices Claude was relying on for it.
## What each watch shows
**An event feed**, newest first, of the webhook events mentioning that client,
pushed the moment they're ingested. This is the near-realtime half.
**Three sparklines** — RSSI in dBm, SNR in dB, and Tx in Mbps — built from
polled R1 metrics. These are labelled as roughly three minutes delayed, because
that's the API's own latency, not the page's.
:::note
Events carry their own RSSI in RUCKUS-positive relative units, which is a
different scale from the dBm sparkline. The console shows it as feed text and
deliberately never plots the two together — a rising number in the feed and a
rising line on the chart do not mean the same thing.
:::
The page stops polling R1 while the browser tab is hidden, so leaving it open in
a background tab doesn't keep generating API calls. Metric polling also pauses
altogether **15 minutes** after the page opens, hidden time included — the
sparklines freeze and a banner offers **Resume**. Events keep streaming
regardless.
## What it needs to show anything
The event feed is fed by the [webhooks](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/)
receiver. If you haven't configured RUCKUS One to deliver events to your
receiver URL, the sparklines will still fill in from the API but the feed stays
empty.
## Using it with Claude
The pattern this exists for:
1. Ask Claude to arm a watch on the client you're investigating.
2. Open the `consoleUrl` it gives you.
3. Go reproduce the fault, watching the feed and the signal charts live.
4. Come back to Claude and ask what was caught — the same watch data is
available to the analytics tools.
## Who sees the AI chat panel?
Some accounts also see an **AI chat** panel near the top of the console. It drives
the same tools through a Cloudflare Workers AI model and shows each tool call as
it runs.
The panel appears only when the console feature is on **and** an administrator
has granted AI chat to your account. You can't turn it on from the dashboard; to
ask for it, contact [support](https://support.neuralconfig.com/r1-mcp?from=docs). Without the
grant the panel simply isn't there — no message, no error.
:::caution
[Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) does not apply in the chat panel: a
write the model decides to make runs without a confirmation step. Pick a
read-only connection in the panel's **Connection** selector unless you intend a
change.
:::
## See also
- [Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) — the watch tools and the event receiver
- [Workflow prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) — **Live reproduce-and-catch** does this as a guided workflow
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/) — unlocking Early Access
---
# Floorplans and floor maps
Source: https://docs.neuralconfig.com/r1-mcp/features/floorplans/
The **Floorplan** feature shows you where every AP and switch sits on a venue
floor, **measured in real metres**, and tells you what is wrong with the layout.
RUCKUS One knows where each device is on a plan and how the plan is calibrated,
but never puts the two together. R1-MCP does: "AP-Lobby and AP-Cafe are 3.2 m
apart and both on channel 36" is the kind of answer you get.
**The findings in text are the deliverable; the picture is the attachment.**
Claude reads the findings — unplaced APs, APs left at (0,0), pairs closer than
6 m, APs more than 40 m from any neighbour, a plan with no scale — and the map
is how you confirm them by eye.
## How do I turn it on?
Floorplan is a generally available feature, so there is **no password**. Turn on
**Floorplan Mapping** in the Features section of the
[dashboard](https://r1-mcp.lanpulse.com). That adds two tools, `get_floorplan`
and `floorplan_map`, and a **Floor Map** link in the dashboard navigation.
As with every feature, the tools appear in new Claude conversations, not in one
that is already open.
## What can I ask?
- "Audit the AP placement on level 3 of the HQ venue."
- "Which APs on this floor share a channel, and are they actually close?"
- "Show me the roaming on the ground floor over the last 24 hours."
- "What would we lose if the AP by the lifts failed?"
Placement audits and co-channel checks need nothing but the floor itself.
Client, roaming and coverage questions use [layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/)
drawn over the floor.
## Reading a floor: `get_floorplan`
`get_floorplan` reads a floor and returns it as data: the plan, its image
metadata, its metric scale, and every AP and switch resolved to a position. Call
it with just a `venueId` to list the venue's plans (id, name, floor number, and
whether a scale is set).
| Parameter | Default | What it does |
|---|---|---|
| `venueId` | required | The venue. Alone, it lists the venue's floorplans |
| `floorplanId` | — | One plan by id. With only one plan in the venue you can omit it; with several, omitting it returns the list |
| `name` | — | Select a plan by exact name (case-insensitive) |
| `floorNumber` | — | Select a plan by floor number |
| `includeDevices` | `true` | Resolve AP and switch positions. `false` returns just the plan, its image and its scale |
| `includeSwitches` | `true` (with devices) | Include placed switches |
| `floorWidthMeters` | — | Real width of the plan in metres, used **only** when R1 has no scale. Gives a low-confidence frame; never overrides a scale R1 has |
| `refreshImage` | — | Re-fetch the plan image from R1 instead of the stored copy |
| `connection` | — | Which saved [connection](https://docs.neuralconfig.com/r1-mcp/setup/connections/) to read, by label or id |
Positions come back as **percentages of the image, 0–100, origin top-left** —
that is how R1 stores them. The `scale` block converts them to metres.
Neither tool writes. Uploading a plan, setting its scale or moving an AP is done
in RUCKUS One, or by Claude through the ordinary R1 API with `call_r1`.
## Rendering a floor: `floorplan_map`
`floorplan_map` draws the floor and returns the findings. The map arrives as a
real image Claude can look at, plus an **ASCII grid** traced from the same plan,
so the building outline survives even in a client that drops images.
| Parameter | Default | What it does |
|---|---|---|
| `venueId` | required | The venue |
| `floorplanId` / `name` / `floorNumber` | — | Which plan; with several plans and none named, you get the list |
| `layers` | `["aps"]` | What to draw — see [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/) |
| `format` | `["image","ascii"]` | Any of `image`, `ascii`, `svg`. SVG is vector markup returned as text |
| `width` | `1000` | Render width in pixels, capped by the pixel budget |
| `asciiCols` | `72` | Columns in the ASCII grid |
| `inline` | `false` | Embed the plan image inside the SVG. Costly — those bytes are read as text |
| `includeSwitches` | `true` | Draw placed switches. `false` skips the switch query and reports no switch count at all, rather than zero |
| `legend` | `true` | Draw the legend panel on the SVG. The legend entries are returned either way |
| `refreshClients` | `auto` | Client data freshness: `auto` re-queries R1 when the cached snapshot is over 2 minutes old, `force` always re-queries, `cache` never calls R1 |
| `coverageBand` | 5 GHz | Band for the predicted layers: `2.4g`, `5g` or `6g` |
| `roamWindow` | `24h` | `1h`, `6h`, `24h`, `7d` or `30d`. The roam trail covers this period; `roams` draws the pairs active in it, with their [running totals](https://docs.neuralconfig.com/r1-mcp/features/roam-matrix/#how-to-read-a-roam-matrix-pair) |
| `roamMode` | `signal` | How roam arrows are coloured: `signal` or `fastroam`. The findings are the same either way |
| `roamClient` | — | A client MAC, for the one-client roam trail |
| `lbsClient` | — | A device MAC, for the `heardBy` layer |
| `floorWidthMeters`, `refreshImage`, `connection` | — | As for `get_floorplan` |
**APs are circles and switches are squares**, so the two are told apart by shape
as well as colour. Markers are lettered A, B, C… in reading order, and the
letters stay the same between renders, so "AP C" means the same AP next time.
## What will it refuse to tell me?
Each of these is a real limit of R1's data. A floorplan tool that ignored them
would produce an answer that looks right and isn't.
### No metric scale, no metres
If the plan has no usable calibration in R1, the scale comes back as
`{ ok: false, reason }` and **no distance is reported at all** — never a guessed
one. The audit becomes topological: which APs are placed, not how far apart they
are. The predicted coverage layers refuse outright, and co-channel pairs are
listed as unconfirmable.
The one way round it is `floorWidthMeters`: tell Claude how wide the floor
really is, and it builds a low-confidence frame from that. The better fix is to
calibrate the plan in RUCKUS One.
:::note
R1 normally calibrates only **one axis** of a plan. Measuring the other needs
the image's aspect ratio, which is why R1-MCP fetches and measures the plan
image itself rather than just linking to it.
:::
### Connected clients are not drawn as dots
R1 has no client coordinates, so there is nowhere honest to draw an associated
client. Instead, connected clients appear as **a count badge on each AP**, a
**per-AP table**, and a **roster** with one row per client (MAC, hostname, AP,
SSID, band, signal and age). A dot is drawn only for a client whose position was
actually measured, and that needs a location source most venues don't have.
:::caution
**A floor with no client dots is not an empty floor.** On most venues, a floor
carrying two hundred clients renders with no client dots at all. Ask for the
count — Claude reads it from the badges and the roster, not from the picture.
:::
### No distance from a signal
Every metre on a floor map comes from the plan's own calibration. RUCKUS One
exposes no measured AP-to-AP signal, so nothing here estimates a distance or a
position from signal strength, and **there is no automatic AP placement**.
### Assigned is not placed
R1 can report an AP as belonging to a floorplan without ever having been dragged
onto it. Such APs are returned as **unplaced**, with a reason — no coordinates,
unassigned, on another floorplan, or out of range. A floor whose APs are all
unplaced reads as "12 APs, none placed", never as an empty floor. The Floor Map
page lists them under **Assigned but not placed**.
## Two signal scales that never mix
Client signal arrives from two sources, measured on **different scales**, and
they are kept in separate columns:
| Source | Field | Scale |
|---|---|---|
| The R1 client snapshot | `rssiDbm` | **dBm** — negative, lower is weaker |
| A live webhook event | `rssiRelative` | RUCKUS **relative units** — positive, higher is stronger. Not dBm |
Roam signal changes are also relative units, and the predicted coverage field is
**modelled** dBm, not a reading. Never compare a number from one scale with a
number from another: a +3 relative reading is not "stronger than −67 dBm".
## The Floor Map page
**Floor Map** (`/floormap`) is the same view in your browser, with room to look
properly. It appears in the dashboard navigation once the feature is on.
- **Pickers** for connection, venue and floorplan.
- **A checkbox per layer**, each with a hover hint. Access points are always on.
- **Re-read clients**, when the clients layer is on, to fetch a fresh snapshot.
- **Live** (off by default): streams client joins, roams and leaves as your
webhook receiver ingests them, and re-renders the floor at most once every
30 seconds.
- Band, roam-window and roam-colour selectors, a client MAC box for a roam
trail, and a device MAC box for `heardBy`.
- A side panel with **Findings**, **Assigned but not placed**, and the
**Legend**, plus per-layer data tables including the full client roster.
### The links Claude gives you
Every `floorplan_map` result carries two links, and neither costs Claude any
context:
| Link | Opens |
|---|---|
| `pageUrl` | The Floor Map page, on this floor — the better link for a person |
| `mapUrl` | The picture alone, as an SVG — for embedding or printing |
Both carry the layers and options Claude rendered with, so you open what you
were just shown. They open with your dashboard sign-in. The one setting
deliberately left out is `refreshClients`: a link gets opened repeatedly and
forwarded, and baking in `force` would re-query R1 on every open.
The r1-mcp companion extension can also show a floor map, using a short-lived
link scoped to one venue that is read-only and expires after 15 minutes.
## Limits
| Limit | Value |
|---|---|
| Image Claude receives | About **800,000 pixels** (roughly 1,050 tokens); tried at smaller widths if it encodes over 900 KB, then **refused** with a pointer to the map link |
| Inline SVG (`inline: true`) | **60 KB** — refused rather than trimmed |
| Stored plan images | **50 per user per connection**; the oldest are evicted |
| Source plan image | 20 MB |
| Interlaced PNG and JPEG plans | Cannot be decoded — positions are drawn on a blank frame and the reason is stated |
More caps are on the [limits page](https://docs.neuralconfig.com/r1-mcp/reference/limits/#images-and-floorplans).
## Prompts and the reference guide
Two prompts in Claude's **+** menu use this feature:
| Prompt | What it does |
|---|---|
| `floorplan_ap_audit` | Audits AP placement on a floor in metres — unplaced APs, APs at (0,0), pairs too close, isolated APs, and co-channel candidates confirmed or dismissed. Read-only |
| `floorplan_roaming` | Draws the roam matrix on a floor and reads it against the real distances, optionally with one client's trail. Makes no R1 call |
Claude can also fetch the **`floorplan-mapping`** reference guide with
`get_reference`. It covers the refusals, the layer catalogue, the signal scales
and worked workflows in depth.
## Next steps
- [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/): Every layer you can draw on a floor, and what each one can and cannot state.
- [Webhooks and event analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/): Set up the receiver that feeds the roam layers and the live client strip.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): Image, cache and roster caps alongside every other limit.
- [Prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/): The floorplan prompts and every other workflow in the + menu.
---
# Floor map layers
Source: https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/
A **layer** is one question asked of a floor. `floorplan_map` accepts **13
layers**; you name the ones you want in `layers`, and each adds its own
findings, and usually something drawn, on top of the
[floor map](https://docs.neuralconfig.com/r1-mcp/features/floorplans/). With no `layers` argument you get
`["aps"]`.
Every layer is judged by what it can **state**, not what it draws. Some layers
report measured facts, some run a model, and some need data that only exists
once something else is set up. The table below says which is which.
## The layer catalogue
| Layer | What it shows | Kind | Needs | Extra R1 call |
|---|---|---|---|---|
| `aps` | Every AP and switch on the plan, and the plan's own defects | Measured | Nothing — always on | No |
| `clients` | Per-AP client counts, a per-AP table and a per-client roster | Measured | The R1 client query; webhook events refine it | **Yes** |
| `bands` | Which radio each AP's clients chose, per AP and floor-wide | Measured | The client query (turned on automatically) | **Yes** |
| `roams` | The AP-to-AP roam matrix as arrows, with the distance between each pair | Measured | Stored webhook roam events | No |
| `roamTrail` | One client's hops across the floor, newest brightest | Measured | Stored webhook roam events, plus `roamClient` | No |
| `entry` | Where clients first appear on the floor, ranked | Measured | Stored webhook roam events | No |
| `cochannel` | Channel-overlap pairs confirmed or dismissed by distance | Measured | A metric scale to judge distance | No |
| `coverage` | A predicted signal heat field and weak areas in m² | **Predicted** | A metric scale; the plan image for walls | No |
| `blastRadius` | What each single AP failing would cost | **Predicted** | Same as `coverage` | No |
| `demand` | Live per-AP load against the area each AP is predicted to serve | **Predicted** + measured | Same as `coverage`, plus the client query | **Yes** |
| `airtime` | Each radio's measured channel occupancy | Measured | An [LBS](https://docs.neuralconfig.com/r1-mcp/features/lbs/) source | No |
| `footfall` | Distinct devices each AP heard, including passers-by | Measured | An [LBS](https://docs.neuralconfig.com/r1-mcp/features/lbs/) source | No |
| `heardBy` | One device's measured position and every AP that heard it | Measured | An LBS source, plus `lbsClient` | No |
The **client query** is the only extra R1 call any layer makes. Roam and entry
layers read the matrix the [webhooks feature](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/)
has already stored.
## What each layer can and cannot state
### `aps` — the plan's own defects
`aps` is **always** in the stack, even if you only ask for `clients`, because
its findings invalidate everything drawn over them.
- **States:** APs assigned to the floor but never placed; APs left at (0,0),
R1's default for an AP nobody dragged onto the plan; pairs closer than 6 m;
APs more than 40 m from any neighbour; APs on other floorplans; a missing or
low-confidence scale.
- **Cannot state:** any distance, when the plan has no metric scale.
### `clients` and `bands` — who is connected
- **States:** how many clients each AP has, where weak signal concentrates,
and a lopsided split between two APs that are metres apart. `bands` breaks the
counts down by radio and separates an AP whose 5 GHz radio is on air but going
unused from one with no 5 GHz radio reporting a channel.
- **Cannot state:** where a client is. Connected clients are **not drawn as
dots** — they're on the AP badges, the per-AP table and the roster. And `bands`
is an **association count, not a capability census**: it says which band a
client chose, not which bands it supports.
The client data is the R1 snapshot, with webhook joins, leaves and roams since
then applied on top. The roster is capped at **1,500 rows**, ranked weakest
signal first, so read a missing MAC as "not in the roster", not "not on this
floor".
### `roams`, `roamTrail` and `entry` — movement
These three draw the roam data your webhook receiver has already stored, joined
to the distances R1 never puts beside it: "clients cross between these two APs
300 times" becomes "…and they are 44.7 m apart".
- **States:** busy pairs that are far apart, pairs trading clients back and
forth without either gaining signal, pairs that fully re-authenticate on most
roams, roams leaking to other floors, and one client's path.
- **Cannot state:** anything, until the webhook receiver is set up — the layer
reports `no_roam_data` rather than a quiet floor. Counts are approximate,
because webhook deliveries are stored as received and never de-duplicated.
- **`entry` shows where clients appear, not where the doors are.** A phone
waking at a desk or a laptop coming off a dock counts as an arrival too.
Roam signal changes are RUCKUS **relative units, not dB** — never compare them
with a client's dBm reading. Up to **80** roam arrows are drawn, busiest first;
the rest are counted and reported.
### `cochannel` — confirm or dismiss overlap
`analyze_rf` can say two APs share a channel; this layer adds the distance.
| Distance between the two APs | Verdict |
|---|---|
| 12 m or less | Confirmed |
| Up to 30 m | Marginal |
| More than 30 m | Dismissed |
- **States:** which candidates are real and, just as usefully, which to stop
chasing — "both on channel 36 but 48 m apart" is channel reuse working.
- **Cannot state:** a verdict without a metric scale; candidates are then listed
as unconfirmable. Offline APs are excluded and named, because their channel
is a last-known value, not what is on the air.
### `coverage`, `blastRadius` and `demand` — the predicted layers
These three share **one prediction**, so they always describe the same floor.
It radiates each online AP's reported transmit power through a log-distance
path-loss model and charges a few dB for each wall it can see in the plan image.
:::caution
**A predicted layer is a model, not a measurement.** RUCKUS One measures no
coverage anywhere and there is no survey data to calibrate against. Every
coverage prediction carries a `coverage_model` finding stating its assumptions,
and a green map is the model's opinion of the AP layout, not evidence the floor
works. Treat every weak area as a place to check.
:::
- **No metric scale, no prediction** — the layer refuses with
`coverage_unpredictable` rather than guess.
- **Without the plan image** there are no walls to count, so the prediction is
optimistic, and it says so.
- **Offline APs**, and APs whose transmit power R1 reports only as a setting
such as `"max"`, are excluded and named. A weak area near one of them may be
the model missing an AP, not a hole.
- `coverageBand` picks the band, 5 GHz by default. If no placed AP has a usable
radio on that band, another is predicted instead and a finding says so.
`blastRadius` removes each AP in turn and reports the floor area that would drop
below the cell edge, and how much of it nothing else reaches. It models **no
recovery** — R1 raises neighbours' power and re-picks channels afterwards — and
removes **one AP at a time**, so it says nothing about a switch or PoE budget
taking several down. A client count beside it means clients that must
**reassociate**, never clients that lose service.
`demand` crosses the prediction with the live client count per AP. Every
finding is about an **AP, never a place**. Its sharpest one is clients on an AP
the model never picks as strongest anywhere — a sign that an input is wrong,
such as a stale AP position or a wall the image doesn't show.
### `airtime`, `footfall` and `heardBy` — the LBS layers
These three, and the measured client dots in `clients`, need an **LBS source**
on the venue: its APs reporting the devices they hear through RUCKUS
location-based services. [Location-based services (LBS)](https://docs.neuralconfig.com/r1-mcp/features/lbs/)
covers what that needs and how a source is set up. A venue with no source gets
a finding (`lbs_not_enabled`) instead of numbers.
- `airtime` states each radio's **measured** channel occupancy. It is a
different quantity from the `analyze_rf` airtime estimate, which covers beacon
overhead only.
- `footfall` states the distinct devices each AP **heard** in the last
60 seconds — a wider net than connected clients. The per-AP counts don't add
up to the floor total, and none of it is a headcount.
- `heardBy` traces one named device: its measured position and a line to
every AP that heard it. A stronger reading from another AP is a roam
**candidate**, never a verdict.
## Which layer wins when two compete?
A map has **one heat field** and each AP marker has **one badge**, so some
layers compete. The loser's findings are always complete — only the drawing is
affected — and it says so in a finding of its own.
| Slot | Priority, winner first | The loser reports |
|---|---|---|
| Heat field | `footfall` → `coverage` → `blastRadius` | `_field_not_drawn`, naming the field that was drawn and how to see its own |
| AP badge | `clients` → `airtime` → `footfall` → `bands` → `entry` | `_badges_not_drawn`, pointing to its per-AP table in the same response |
So `coverage` and `blastRadius` together draw the coverage field. To see the
failure field, ask for `blastRadius` without `coverage`. With `clients` on, the
AP badges show client counts; drop `clients` to see the band mix or arrival
counts on the markers instead.
## What no layer does
No layer infers a distance or a position from a signal, places APs
automatically, or tracks channel changes over time or how long clients stay on
an AP. Nothing stores a history of channel changes, and the roam data keeps
counts, not durations.
## Next steps
- [Floorplans and floor maps](https://docs.neuralconfig.com/r1-mcp/features/floorplans/): The two floorplan tools, the refusals, the Floor Map page and its links.
- [Location-based services (LBS)](https://docs.neuralconfig.com/r1-mcp/features/lbs/): What the LBS layers need, and how a source is set up.
- [The roam matrix](https://docs.neuralconfig.com/r1-mcp/features/roam-matrix/): What the roams layer draws, and how to read a pair.
- [Webhooks and event analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/): The receiver that feeds the roam and entry layers.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): Roster, edge and image caps for floor maps.
---
# The roam matrix
Source: https://docs.neuralconfig.com/r1-mcp/features/roam-matrix/
The **roam matrix** counts how Wi-Fi clients move between your access points.
Every time a client roams from one AP to another, RUCKUS One sends a roam event.
R1-MCP adds each one to a running tally per **AP pair** (from one AP to
another), so thousands of roams become one row per pair that you can read.
Ask for it in plain words, for example "how do clients roam between the APs on
the second floor?", or call `roam_matrix` directly.
## Where does the roam matrix data come from?
From the **Webhooks** feature, not from a RUCKUS One API call. The matrix is
built from the `UserConnectedToAnotherAP` (209) events your
[webhook receiver](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) stores, as they
arrive.
- **No receiver, no matrix.** Until webhooks are set up and events have arrived,
there is nothing to read. A floor map reports `no_roam_data` rather than a
quiet floor.
- **A pair's tally runs until the pair goes quiet.** It is dropped only after 90
days with no roam between those two APs (and the oldest go first past 40,000
pairs). It is built as each event arrives, so it outlasts the raw event cache.
- **Counts are approximate.** Webhook deliveries are stored as received and
never de-duplicated.
## How to read a roam matrix pair
`roam_matrix` returns the pairs busiest first, each going **from** one AP **to**
another:
| Field | What it tells you |
|---|---|
| `count` | Roams from the first AP to the second, in total since the pair was first seen |
| `avg_rssi_delta` | Average signal change across the roam. **Negative means clients landed on a weaker AP** |
| `neg_delta_ratio` | Share of roams that did not improve signal |
| `pmk_ratio` / `full_auth_count` | Share of roams that used PMK fast roaming, and how many re-authenticated in full |
| `fst_ratio` / `fst_count` | Share of roams whose client context came through FST rather than the session manager |
| `band_steer` | The two ends are the **same AP**: a client moving between its radios, not between APs |
| `placement_concern` | More than half of at least 20 roams between two different APs lost signal |
The signal change is in RUCKUS **relative units, where higher is stronger.
It is not dB.** Never compare it with a client's dBm reading.
Arguments: `apMac` narrows the matrix to roams to or from one AP. `limit` sets
how many pairs come back (default 100, maximum 500). `window` (`1h`, `6h`,
`24h`, `7d` or `30d`) chooses **which pairs** come back: those with a roam in
that period. **It does not narrow the counts.** With `window: "24h"`, a pair
active today still shows every roam since it was first seen, so read `count` as
a running total, not a daily rate.
## What a placement concern means
A **placement concern** flags two APs where clients roam often and mostly end
up with a weaker signal. That points at a coverage gap or two cells overlapping
between those APs. A band steer is never a placement concern, because it
involves only one AP.
## The roam matrix on a floor map
With the [Floorplan](https://docs.neuralconfig.com/r1-mcp/features/floorplans/) feature on, the `roams`
[layer](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/) draws the matrix as arrows between
the APs on a floor, with the **distance between each pair in metres**.
"Clients cross between these two APs often" becomes "…and they are 44.7 m
apart". `roamWindow` picks which pairs are drawn, as `window` does above; the
counts on them are still running totals. The **Map roaming on a floor** prompt walks through it.
- **Arrows point the way clients moved.** By default (`roamMode: "signal"`) they
are green when roams gain signal, grey when there is no meaningful change,
orange when they lose it, and red for a placement concern.
- **`roamMode: "fastroam"`** colours by fast-roam share instead: blue at 80% or
more PMK, grey from 50%, magenta below 50%. The findings are the same in both
modes.
- **A band steer is a ring on one AP**, never an arrow.
- **Up to 80 arrows** are drawn, busiest first. The rest are counted and
reported, and roams to APs on other floors are counted, not dropped.
Findings the map calls out:
- **A busy pair far apart.** Clients roaming directly between two APs more than
35 m apart probably cross a spot with no usable coverage.
- **A ping-pong pair.** Both directions busy, and neither improving signal.
`find_ping_pong_clients` names the devices doing it.
- **Full re-authentication.** A busy pair where fewer than half the roams used
PMK. Each full 802.1X exchange is a gap of roughly half a second or more,
audible on a call. Check the WLAN's 802.11r/OKC setting first.
## What the roam matrix cannot tell you
- **Sticky clients.** A client that clings to a distant AP never roams, so it
never appears here.
- **Which device is roaming.** The matrix counts pairs. For one client, use
`get_client_roams`, or the `roamTrail` layer with `roamClient` set.
- **Exact counts, or counts for a period.** Deliveries are not de-duplicated,
and a pair's count is a running total whatever the window.
## Next steps
- [Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/): Set up the receiver that feeds the roam matrix, and the other roaming tools.
- [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/): The roams, roamTrail and entry layers, and every other layer you can draw on a floor.
---
# Location-based services (LBS)
Source: https://docs.neuralconfig.com/r1-mcp/features/lbs/
**LBS** stands for **location-based services**. With LBS on, a venue's RUCKUS
APs report every Wi-Fi device they hear and its signal strength, plus how busy
each radio's channel is. R1-MCP uses those reports to place clients on the floor
plan from measured signal, instead of drawing them on the AP they're connected
to.
## What LBS adds
| Where | What you get |
|---|---|
| **Locate**, on the Floor Map page | Live client positions, updated every second, in 2-D or 3-D |
| `clients` layer | A dot for each client with a measured position, with a ring showing how uncertain it is |
| `airtime` layer | Each radio's measured channel occupancy |
| `footfall` layer | The distinct devices each AP heard in the last 60 seconds, passers-by included. It isn't a headcount |
| `heardBy` layer | One device's measured position and every AP that heard it. Set `lbsClient` to its MAC |
The layers are described in full on [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/#airtime-footfall-and-heardby--the-lbs-layers).
Without LBS, they return a finding such as "This venue has no LBS source, so no
AP is reporting measured airtime", and Locate shows clients on their AP only.
## What LBS needs
- The **Floorplan Mapping** feature, turned on under Features in the
[dashboard](https://r1-mcp.lanpulse.com).
- AP firmware 7.0.300 or later.
- APs placed on the venue's floor plans, for positions. Airtime and devices
heard work without placement.
- 2.4 or 5 GHz. RUCKUS LBS doesn't report 6 GHz.
## Setting up an LBS source
You can't add an LBS source from the dashboard yet.
Adding one creates an LBS server profile named `r1-mcp f-…` in RUCKUS One
(Policies & Profiles → LBS Server) and activates it on the venue. RUCKUS One
allows **one LBS profile per venue**, so this replaces any LBS profile the venue
already uses. Removing the source deactivates and deletes the profile.
The APs report to a broker that R1-MCP hosts. A [probe](https://docs.neuralconfig.com/r1-mcp/features/probe/)
on your LAN can be the broker instead, but only at an address reachable from the
internet. RUCKUS One connects to the broker before it tells the APs to, so a
LAN-only address never works.
## How accurate are LBS positions?
A position is worked out from the signal strength at the strongest four APs that
heard the device on one band.
- A device heard by only one AP gets a ring around that AP, not a point.
- A position with a large uncertainty is shown as "somewhere on this floor (±N
m)".
- A position older than 30 seconds is treated as stale.
## What LBS keeps
- Positions are held live, in memory. R1-MCP keeps no position history, and the
trails in Locate exist only in your browser.
- Randomised MAC addresses are counted, but never listed or kept.
- The LBS password R1-MCP generates for the profile is stored encrypted.
## Known limits
- If the connection to the broker drops, RUCKUS One can take up to an hour to
reconnect, and LBS data stops until it does.
- Locate draws up to 400 positions per floor. The rest are counted.
## Next steps
- [Floor map layers](https://docs.neuralconfig.com/r1-mcp/features/floorplan-layers/): The airtime, footfall and heardBy layers, and every other layer you can draw on a floor.
- [Floorplans and floor maps](https://docs.neuralconfig.com/r1-mcp/features/floorplans/): Turn on Floorplan Mapping, read a floor, and use the Floor Map page.
---
# VLAN probe
Source: https://docs.neuralconfig.com/r1-mcp/features/vlan-probe/
The **VLAN probe** tells you whether a VLAN is actually reachable over the air
at a venue — even when no WLAN carries that VLAN yet. For each VLAN you name, it
puts up a temporary SSID on that VLAN, has RUCKUS Service Guard run a virtual
client from every online AP (associate, take a DHCP lease, ping the gateway),
reports a verdict per VLAN with a per-AP breakdown, and then removes everything
it created.
:::caution[A run broadcasts a real SSID]
Every run creates a real, temporary WPA2-PSK SSID and puts it **on the air from
every AP of the venue for several minutes**. On a production venue, customers'
devices will see it. Each run needs an explicit confirmation, has a hard
deadline that tears everything down, and leaves a trail you can sweep for — but
treat starting one as a change to a live site.
:::
## What question does it answer?
**Wireless VLAN reachability where no WLAN exists to test with.** It is not
general "VLAN validation", and the difference matters:
| Tool | What it tests | From where |
|---|---|---|
| R1 Service Validation → **Wired** tab | VLANs | Switches |
| R1 Service Validation wireless test | An **existing** WLAN | APs |
| **VLAN probe** | A VLAN with **no WLAN on it** | APs, over a temporary SSID |
A VLAN that no WLAN carries cannot be tested over wireless natively at all. That
gap is what this feature fills. If a VLAN already has a WLAN, R1's own wireless
test covers it; if you want the switch view, use the Wired tab.
## How do I turn it on?
VLAN probe is an [Early Access](https://docs.neuralconfig.com/r1-mcp/reference/features/#early-access) feature:
unlock Early Access with the password, then turn on **VLAN Probe** in the
**Early Access** card of the [dashboard](https://r1-mcp.lanpulse.com).
It is Early Access **on purpose**. The feature is new, and because a run
broadcasts at a live site, the password is a deliberate speed bump before
anyone can start one.
## Where do I run it?
**From the r1-mcp companion extension, not from Claude.** The extension's card
runs the preflight, starts the run and shows its progress. The run itself is
driven by the R1-MCP server, so teardown doesn't depend on your browser tab
staying open.
:::note
**Claude has no tools for this feature**, by design. Claude cannot start, stop
or read a run. What Claude can do is explain a run you're looking at, advise
before you start one, and sweep a tenant for SSIDs a run may have left behind.
:::
## What happens during a run?
For each VLAN row — a venue, a VLAN id and the gateway IP to ping — the run
works through the same steps, in order:
```mermaid
flowchart TD
wlan["Create a WPA2-PSK WLAN on the row's VLAN"]
act["Activate it on the venue SSID goes on the air"]
spec["Create a Service Guard spec scoped to the venue's online APs"]
test["Run the test and poll results associate, DHCP, ping gateway"]
teardown["Delete the spec, deactivate, delete the WLAN"]
stop["Deadline reached or run aborted"]
wlan --> act --> spec --> test --> teardown
stop -->|"tears down"| teardown
```
1. **Create a WLAN** — WPA2-PSK, carrying the row's VLAN.
2. **Activate it on the venue.** This is the moment the SSID goes on the air from
every AP of the venue.
3. **Create a Service Guard spec**, scoped to the venue's **online** APs, with a
virtual client that associates, takes a DHCP lease and pings the row's
gateway.
4. **Run it and poll** the results.
5. **Tear down** — delete the spec, deactivate the WLAN, delete the WLAN.
Reaching the run's deadline, or aborting it, goes straight to the same
teardown. There is no way to stop a run that leaves the SSID up.
**Why it takes minutes.** Service Guard can take up to **3 minutes** before a new
test is visible at all. An AP runs only one virtual-client test at a time, so
rows are run in rounds whose AP sets don't overlap. All rows' WLANs exist at the
same time. A handful of VLANs at one venue takes several minutes, not seconds.
## Before a run: the preflight
The extension calls a **preflight** first, and the preflight **writes nothing**,
so re-running it costs nothing. It reports the names the run would create, a
time estimate, SSID capacity, what your connection's credential looks like,
warnings, and blockers.
| Blocker | Why it stops the run |
|---|---|
| `venue_not_found` | The connection can't see a venue with that id |
| `venue_name_ambiguous` | Another venue in the tenant has the same name. The test is scoped by venue **name**, so it could test the wrong one |
| `venue_check_unavailable` | The venue list couldn't be read, so uniqueness is unknown |
| `aps_unreadable` | The venue's AP list couldn't be read |
| `no_eligible_aps` | No AP is online with a MAC to scope a test to — a run would broadcast and answer nothing |
A confirmation token is issued **only** when there are no blockers, and it is
valid for **10 minutes**. A read-only credential produces a **warning**, not a
blocker. Sending the same token twice doesn't start a second run.
## The deadline
Every run has a deadline, and reaching it tears the run down:
| Rule | Value |
|---|---|
| Deadline | **Three times** the preflight estimate |
| Never less than | **15 minutes** |
| Never more than | **60 minutes** |
A run stopped by its deadline ends `interrupted`, never `failed` — its VLANs
were not answered, which is not the same as failing. An abort is a teardown too:
the run shows `aborted` once the teardown has actually run, not when you ask.
## Reading the result
One verdict per VLAN. Four of the five are ways of **not** being a failure —
don't read them as one.
| Verdict | Means |
|---|---|
| `pass` | A client associated, got a lease on the VLAN, and pinged the gateway cleanly |
| `partial` | The VLAN answered — a lease and some replies — but not everywhere or not cleanly. Not a failure |
| `fail` | A stage genuinely failed, or every ping was lost |
| `inconclusive` | The VLAN was never answered, for a known reason — for example every scoped AP was offline, the test never became visible, or the run was aborted. Nothing is claimed about the VLAN |
| `errored` | Something broke, or a retry the run owed never ran. Not a statement about the VLAN |
Each verdict comes with per-AP outcomes: `pass`, `partial-ping`, `fail`,
`did-not-run`, `transient` and `rerun-alone`. `did-not-run` is an **offline AP**,
never a failure. `transient` and `rerun-alone` describe the **test** — for
example two tests colliding on one AP — not the VLAN.
Every run also reports **`onAir`**: how many of its objects may still be on the
air, read from the run's own record of what it created. On any run that didn't
finish cleanly, read that first. A teardown that didn't complete doesn't fail the
run, but it is named in the run's error, because something is still broadcasting.
## Finding anything left behind
**The names are the recovery mechanism.** Everything a run creates carries its
run id:
| Object | Name |
|---|---|
| WLAN name and SSID | `R1PP-VLAN-` |
| Service Guard spec | `R1PP--v` |
The extension's leftovers scan sorts every `R1PP-` object into four groups:
yours from a finished run, yours from a run that is **still live**, not created
by this feature, and unattributable. Cleanup takes **named ids only** — there is
no wildcard delete in any form — and it **always refuses** to delete an object
from a run that is still live, with no override. Objects the feature didn't
create are removed only if you explicitly acknowledge them.
From Claude, the **`vlan_probe_strays`** prompt sweeps a tenant for `R1PP-`
WLANs, and Service Guard specs too if you also have the
[GraphQL](https://docs.neuralconfig.com/r1-mcp/features/graphql/) feature on, decodes which run each came
from, and reports what is still on the air. It is **read-only by default**:
Claude can't see the run records, so it can't tell an abandoned object from one
belonging to a run in progress, and it tells you to remove strays with the
extension's cleanup. If you ask Claude to delete one directly instead, it first
confirms the specific object with you and checks its run is not one you still
have open.
Claude can also fetch the **`vlan-probe`** reference guide with `get_reference`
to explain verdicts, per-AP outcomes and preflight results in depth.
## Limits
| Limit | Value |
|---|---|
| VLANs per run | **15** — every row's WLAN exists at the same time, and R1 documents 15 WLANs per AP (7 on the R310) |
| VLAN ids | 1–4094 |
| Confirmation token | 10 minutes after the preflight |
| Cleanup request | Up to 50 named ids |
| Run records | 30 days after the run ends, and kept longer while anything it created is not yet deleted |
The WLAN ceiling is a documented firmware figure, not a limit the API enforces,
so the preflight counts against it and says so. All limits are on the
[limits page](https://docs.neuralconfig.com/r1-mcp/reference/limits/#vlan-probe-runs).
## Next steps
- [Features and feature flags](https://docs.neuralconfig.com/r1-mcp/reference/features/): How Early Access works and how to unlock it.
- [Prompts](https://docs.neuralconfig.com/r1-mcp/reference/prompts/): The stray-SSID sweep prompt and the rest of the + menu.
- [GraphQL API support](https://docs.neuralconfig.com/r1-mcp/features/graphql/): Needed to see Service Guard specs when sweeping for strays.
- [Limits and quotas](https://docs.neuralconfig.com/r1-mcp/reference/limits/): Run deadlines, row caps and retention in one place.
---
# Examples
Source: https://docs.neuralconfig.com/r1-mcp/examples/
R1-MCP works best when you ask for an *outcome* and let it work out the calls.
These are patterns that reliably produce good results.
## Inventory and orientation
> List my venues, and for each one show the AP count and how many are offline.
Claude searches the API index for the relevant endpoints, calls them, joins the
results inside the sandbox, and returns a table. You get the answer, not 400
rows of JSON.
> Which of my switches are running a firmware train older than 10.0.20?
Good first question for any [ICX work](https://docs.neuralconfig.com/r1-mcp/features/icx/) — it tells you which
firmware train to target for syntax.
## RF and coverage
> Do an RF health check on the Charleston venue for the last 24 hours.
The **RF health check (venue)** [prompt](https://docs.neuralconfig.com/r1-mcp/reference/prompts/) is the guided
version. For a single AP:
> What's the airtime utilization on AP `xx:xx:xx:xx:xx:xx` this week, and is it
> the worst in its venue?
## Client troubleshooting
> Client `aa:bb:cc:dd:ee:ff` keeps dropping. Give me the full picture —
> connections, roams, and any related incidents.
With the [webhooks feature](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/) enabled this gets
much richer, because incident and roaming history are available. The **Client
deep-dive troubleshooting report** prompt packages it.
For an intermittent fault you can reproduce (this one needs the webhooks
feature):
> Arm a watch on this client for the next hour — I'm going to reproduce
> the problem.
Then go reproduce it, come back, and ask what was caught. Watches expire in
whole hours — one hour is the shortest.
## Diagrams and documentation
> Draw me L2 and L3 topology diagrams for this venue.
Diagrams come back as Mermaid by default; you can ask for D2 or draw.io
(importable mxGraph XML) instead.
Read the confidence note on each layer — they come from different sources.
L2 is the controller's forwarding graph and is high confidence but cached. L1
is built from LLDP and is best-effort. L3 reflects routing *intent* from
VE/SVI subnets and static routes, not live adjacency — for live OSPF or BGP
state, ask for `show ip ospf neighbor` or `show ip bgp summary` over
[live CLI](https://docs.neuralconfig.com/r1-mcp/features/live-cli/).
> Build an as-built documentation packet for the Charleston venue.
## Switch configuration
> This switch is on 10.0.20. Generate the config to add VLAN 200 tagged on
> ports 1/1/1 through 1/1/8, verify the syntax against the FastIron docs, and
> show me the commands before applying anything.
Naming the firmware train is the highest-value thing you can do here — see
[ICX](https://docs.neuralconfig.com/r1-mcp/features/icx/#firmware-trains-matter). Ask to see the commands first, and
turn on [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/) if this is production.
To make it repeatable:
> Turn what we just did into a MOP with rollback steps, and export it.
MOPs need the Live CLI (or Copy) feature. See [MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/#mops--method-of-procedure).
## Multi-tenant
> Using the Acme Production connection, list the venues and how many APs are
> offline at each.
Always name the connection when you have more than one enabled — the API tools
refuse to guess rather than act on the wrong tenant. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/).
## Questions about RUCKUS One itself
> How does RUCKUS One handle DPSK, and where do I configure it?
This goes to `search_docs` against the RUCKUS One user guide rather than the
API, and comes back with links into the live documentation.
## Tips
- **Scope narrowly.** "Audit every venue" burns the
[run budget](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget) and comes back in
stages. One venue at a time is faster.
- **Ask for the evidence.** "Show me the raw output" is always a reasonable
request, and for live CLI it's the default behavior.
- **Say the tenant and the firmware.** Those two facts remove most of the
ambiguity in most requests.
---
# Troubleshooting
Source: https://docs.neuralconfig.com/r1-mcp/troubleshooting/
## Connection test fails
**Test** on a connection's row mints a real RUCKUS token, so a failure is
always in the credentials chain. The row shows `Test failed:` followed by a code:
| Code | Usual cause |
|---|---|
| `token_mint_failed` (with `upstream HTTP` and a status) | RUCKUS refused the credentials — wrong region, tenant ID, or secret (see the list below) |
| `invalid_token_url` | The token URL is not `https`, is malformed, or points at a non-public host |
| `timeout` | RUCKUS One did not answer within 15 seconds — try again |
| `decryption_failed` | The stored secret could not be decrypted — re-enter it with **Edit** |
For `token_mint_failed`, in order of likelihood:
1. **Wrong region.** The credentials are valid but the tenant isn't in that
region. Check whether your tenant is US, Europe, or Asia — see
[Getting started](https://docs.neuralconfig.com/r1-mcp/setup/getting-started/#regions).
2. **Wrong tenant ID.** The token URL includes it, so a wrong value fails at
mint time.
3. **Client secret mistyped.** The field is write-only, so you can't inspect
what's stored — re-enter it rather than trying to verify it.
4. **Client disabled or deleted in RUCKUS One.** Check the API client is still
active.
## The connector won't authorize
- **Redirect loop or "too many redirects"** — a cookie problem during the
Google sign-in hop. Use a normal (non-private) window, allow cookies for
`r1-mcp.lanpulse.com`, remove the connector, and add it again.
- **Every call fails authentication** — the token was revoked, or the
connector was added before sign-in completed. Remove and re-add.
- **`state_browser_mismatch` or `invalid_or_expired_state` after Google
sign-in** — the sign-in finished in a different browser from the one that
started it, or took too long. Start again in one normal window.
- **You're sent to an accept-terms page** — the Terms of Service changed since
you last accepted them. Accept them, and the authorization continues.
- **Connector connects, but calls fail on credentials** — MCP auth is fine and
RUCKUS auth isn't. Go re-run **Test** on the connection in the dashboard.
See [Connecting to Claude](https://docs.neuralconfig.com/r1-mcp/setup/connecting-claude/).
## A tool or prompt is missing
- Check the [feature](https://docs.neuralconfig.com/r1-mcp/reference/features/) it belongs to is enabled on your
account.
- **Reconnect the connector.** Tool and prompt lists are fetched when the
connector refreshes; a newly enabled feature often needs a reconnect before
Claude sees it.
- For Early Access features (GraphQL, Probe, Data Studio, Console, VLAN
probe), confirm Early Access is unlocked on your account.
- **The AI chat panel is missing from the Console page.** AI chat can't be
turned on from your account — an administrator has to grant it. Ask
[support](https://support.neuralconfig.com/r1-mcp?from=docs).
## "Connection required" errors
You have more than one enabled RUCKUS connection and the call didn't name one.
This is intentional — R1-MCP will not guess which tenant you meant. Name the
connection:
> Using the Acme Production connection, …
See [Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/#choosing-a-connection-in-conversation).
The same applies to GraphQL (`call_r1_gql`) and Data Studio (`ds_*`) calls.
Related:
| Error | What it means |
|---|---|
| `unknown_connection` | The name didn't match anything. Labels match exactly, including capitalization |
| `connection_disabled` | It matched a connection you've disabled |
| `no_enabled_connection` | Every saved connection is disabled — enable one in the dashboard |
| `no_credentials` | No connection is saved at all |
| `no_connection` | A Data Studio tool found no connection — add one in the dashboard |
## Rate limits (429)
GET, PUT, and DELETE are retried automatically, honoring `Retry-After`, with the
wait capped at 5 seconds and at most 2 retries. POST and PATCH are **not**
replayed automatically, because re-sending a create or a partial update isn't
safe.
If you're hitting limits consistently, narrow the scope of the request — a
question about one venue makes far fewer calls than one about every venue.
## Calls time out or come back partial
Each `code_mode` run has a hard 30-second wall-clock
[limit](https://docs.neuralconfig.com/r1-mcp/concepts/how-code-mode-works/#the-run-budget). A very broad
request either returns partial results after the 20-second warning, or is
stopped with "code_mode exceeded its 30s wallclock limit". Nothing continues on
its own — ask again, with a narrower scope.
The fix is scope, not retries: ask for one venue, one time window, one device.
If the run was making changes, check what landed before retrying: writes it had
already sent may still complete after the timeout.
## The FastIron syntax is wrong
Almost always a firmware train mismatch. R1-MCP scopes documentation search to
one release, and defaults to the newest train — which may not be your switch's.
Tell it the firmware: read `switchFirmwareVersion` from R1 or run
`show version`, and say "this switch is on 10.0.10". The patch level doesn't
matter; the minor does. Never mix trains within one switch's config. See
[ICX](https://docs.neuralconfig.com/r1-mcp/features/icx/#firmware-trains-matter).
## device_cli can't reach a device
A prompt timeout — no prompt after login, or the session closing right after
login — usually means the **device is offline or unreachable**, not that the
call was wrong. Confirm the device is online with a status query before
retrying; each first-call retry opens a fresh session, so blind retries against
a dead target just accumulate.
Also check you passed the device **serial number**, not its MAC.
| Error | What it means | What to do |
|---|---|---|
| `no_prompt_after_login` / `ws_closed_after_login` (switch), `no_ap_prompt` (AP) | The device is most likely offline or unreachable | Confirm it is online before retrying |
| `jwt_mint_forbidden` | The connection's R1 API client isn't allowed to open this CLI. For an AP, the connection is read-only — AP CLI needs a read-write one | Re-run with `connection` naming a read-write connection; the reply's `hint` says the same |
| `connection_mismatch` | You named a different connection while reusing an open session | Close the session and open a new one on the other connection |
| `busy` | Another call on the same session is still running | Wait for it to return, then retry |
| `command_in_flight` | A previous command is still streaming | Poll it to completion first |
| `session_lost` | The session dropped or was reclaimed after sitting idle | Open a fresh session |
| `switch_credentials_unavailable` | R1 has no switch login credential for the venue | Check the venue's switch settings in RUCKUS One |
| `login_incorrect` | The switch rejected the login | Check the venue's switch credential in RUCKUS One |
Without a `connection`, `device_cli` uses your **default** connection. If that
connection is disabled, the call fails with `connection_disabled` — enable it,
make an enabled connection the default, or name one with `connection`. See
[Multiple connections](https://docs.neuralconfig.com/r1-mcp/setup/connections/#where-the-default-connection-is-used)
and [Live CLI](https://docs.neuralconfig.com/r1-mcp/features/live-cli/).
## A MOP replay stops on write arming
- **`write_arming_required`** — the run contains writes to a RUCKUS One tenant.
Claude should show you the `write_targets` tenants and, once you agree,
re-send with `armWrites: true`.
- **`write_not_armed`** — a step writes to a tenant that wasn't in the run's
armed set. Re-create the run with `armWrites: true`.
See [Live CLI and MOPs](https://docs.neuralconfig.com/r1-mcp/features/live-cli/).
## A call came back `confirm_required` with status 0
That is [Write Guard](https://docs.neuralconfig.com/r1-mcp/features/write-guard/), not an HTTP failure.
Nothing was sent to RUCKUS One. Claude shows you the preview, and after you
approve it, sends the same call again with the confirmation token.
## Claude paraphrased console output instead of showing it
Ask for it verbatim. R1-MCP's instruction is to surface live console output in
a fenced code block labeled with its command — if you only got a summary, "show
me the raw output" gets you the rest.
## A copy, backup, or restore refuses
Each of these is a deliberate stop, not a bug.
**Gates:**
| Error | What it means | What to do |
|---|---|---|
| `target_not_empty` | The target venue already has onboarded devices or activated config | Confirm it really is the right target, then re-plan with `acceptWarnings: true` |
| `missing_capture` | The plan needs a write-only secret the source tenant masks on read | Supply it in the `bindings` map at run start — the plan's `operatorInputRequired` lists exactly which |
| `snapshot_incomplete` | You planned from an extract that never finished | Call `venue_extract` with the same `snapshotId` until `complete: true` |
**Caps:**
| Error | What to do |
|---|---|
| `snapshot_too_large` / `backup_too_large` | Over the 5 MB config cap — restrict `domains` and capture the rest separately |
| `snapshot_limit_reached` | 20 snapshots — delete one with `venue_snapshot_delete` |
| `backup_limit_reached` | 50 backups, and nothing expires them — `backup_delete` one first |
| `plan_invalid` | The compiled MOP is over its step cap — plan each subset of `domains` into its own MOP |
**Arguments:**
| Error | What it means |
|---|---|
| `ambiguous_target` | You passed both `target.venueId` and `target.newVenue` — pass exactly one |
| `ambiguous_source` | You passed both `snapshotId` and `backupId` — they're alternative sources for the same diff |
| `template_requires_new` | Template mode always creates a new template, so it needs `target.newVenue` |
| `not_an_element_snapshot` | That snapshot is a venue extract — continue it with `venue_extract`, not `element_extract` |
| `element_selector_required` | Identify the element with an `id` (preferred) or an exact `name` |
| `snapshot_blob_missing` / `backup_blob_missing` | The stored config is gone; delete the row and capture again |
Also check `complete` on the snapshot before planning. An extract that stopped
partway leaves objects without captured definitions, and the plan skips them with
a warning rather than guessing. See [Venue config copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/).
## An element copy produced no MOP at all
A **same-tenant** element copy writes nothing unless you rename what it
creates: the copy names every object exactly as the source does, so each
collides with itself and R1 refuses the duplicate name. Pass a `rename` to
`element_copy_plan` (for example a new name for the element), name a different
`targetConnection`, or use a
[venue copy](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/) if you want the object on another venue in the
same tenant. See [Copying one object](https://docs.neuralconfig.com/r1-mcp/features/element-copy/#same-tenant-needs-a-rename).
## The copy joined an object I didn't expect
A copy into a tenant you have copied into before **adopts** an existing shared
object of the same name by default — it wires your copy to that object rather
than creating a second one. Matching is by **name only**; the contents are never
compared.
Every adopted object is named in the plan's `warnings`. If you wanted a separate
object, rename the source before extracting; if you wanted the existing one
brought in line with the source, plan with `sharedCollision: "overwrite"` — but
read [what an overwrite does to other venues](https://docs.neuralconfig.com/r1-mcp/features/venue-copy/#when-the-name-already-exists-in-the-target)
first, because an undo cannot reverse it.
Relatedly, `venue_copy_verify` reporting `complete: true` does not mean every
object was compared — read `verifyLimits` and `subCollections`.
## Undo or verify says `run_not_found`
Replay runs are kept for **7 days**. After that, `venue_copy_undo` and
`element_copy_verify` with a `runId` return `run_not_found`. Undo a copy, or
verify it by run, within a week of running it.
## Probe calls come back `not_linked`
Your account hasn't completed the one-time consent on the Probe MCP side. The
error carries a `link_url` — open it once in a browser and the calls start
working. `probe_link_status` reports the current state at any time.
`probe_offline` is different: the consent is fine and the probe itself isn't
reachable. `companion_unavailable` means the deployment has no probe integration
wired at all. `unknown_tool` means the tool named isn't one Probe MCP offers, and
`ambiguous_probe` (from `probe_reconcile`) means you have more than one probe and
didn't say which. Other codes — `probe_unreachable`, `bad_assertion`,
`companion_disabled`, `no_probes`, `no_cloud_devices`, `r1_query_failed` — are
explained in [Probe error envelopes](https://docs.neuralconfig.com/r1-mcp/features/probe/#error-envelopes).
## A probe tool I expected isn't available
R1-MCP exposes **15 read-only probe tools** — the CLI, packet-capture, traffic,
and egress tools are not among them, and `probe_call` refuses a name outside that
list. This is narrower than what the link *permits*, deliberately; see
[Two boundaries, not one](https://docs.neuralconfig.com/r1-mcp/features/probe/#two-boundaries-not-one).
## A Data Studio dashboard is empty or invisible
Two distinct causes, and they look similar:
- **You can't see it at all.** New dashboards are drafts, and a draft is visible
only to the API client that created it. It needs `published: true`.
- **It's visible but the charts aren't there.** Charts must be attached with
`dashboards: []` when created or updated. Referencing chart ids in
`positionJson` alone does not create membership.
For a chart that saves but throws "Unexpected Error" on render, `ds_diagnose_charts`
replays the real render and reports Superset's own error. See
[Data Studio dashboards](https://docs.neuralconfig.com/r1-mcp/features/data-studio/).
Two more chart errors:
- **`datasource_id_mismatch`** — the dataset id disagrees between the tool
argument, `params`, and `queryContext`, so the chart is refused. Such a chart
would save but render empty; make all three match.
- **`DATASTUDIO-20010`** — RUCKUS allows at most 6 dimensions per chart, and
the chart won't render until you reduce them. See
[RUCKUS's chart limits](https://docs.neuralconfig.com/r1-mcp/features/data-studio/#ruckuss-chart-limits).
## Live Console problems
- **`watch_limit_reached`** — you have 100 active watches. Clear one before
adding another.
- **The sparklines stopped moving.** Metric polling pauses after 15 minutes to
spare the R1 API; webhook events keep updating. Press **Resume** on the
banner.
See [Live Console](https://docs.neuralconfig.com/r1-mcp/features/live-console/).
## Test bed and webhook errors
- **`no_live_backup`** from `config_diff` — RUCKUS One has no usable config
backup for that switch, and `config_diff` won't create one (that would evict
one of the few backups RUCKUS keeps). Run `testbed_capture` for a fresh
capture. See [Test beds](https://docs.neuralconfig.com/r1-mcp/features/testbed/).
- **`nothing_to_apply`** from `testbed_apply` — every device is already where
the plan puts it.
- **Your webhook receiver answers `401` `unauthorized`** — the secret RUCKUS One
sends doesn't match the one R1-MCP issued. Re-copy it into the webhook
settings. See [Webhooks and analytics](https://docs.neuralconfig.com/r1-mcp/features/webhooks-and-analytics/).
## An endpoint behaves differently from the spec
That happens — the RUCKUS spec doesn't capture everything. Ask Claude to save
an endpoint note describing the quirk; it's private to you and resurfaces
whenever that endpoint's details are looked up again. See
[Core tools](https://docs.neuralconfig.com/r1-mcp/reference/core-tools/#discovery-primitives).
If it's a spec-wide problem worth everyone knowing,
[tell support](https://support.neuralconfig.com/r1-mcp?from=docs) — notes can be promoted to
global visibility.
## Still stuck
[Contact support](https://support.neuralconfig.com/r1-mcp?from=docs). Include the tenant region,
roughly when the request ran, and the error text Claude reported — R1-MCP
surfaces real R1 status codes and bodies, so that text is usually diagnostic.