cxone-wfm-intraday-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cxone-wfm-intraday-mcpWhich queues are at risk right now?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
CXone WFM Intraday MCP (Sparkathon Prototype)
An MCP server that exposes governed CXone WFM Intraday tools to an AI assistant. It proves one Real-Time Analyst workflow — "Why is Billing Support at risk today, and what can we do to recover SLA?" — grounded entirely in structured tool calls over deterministic synthetic data. Simulation only; no live systems, no write-back.
Design spec: docs/superpowers/specs/2026-07-15-cxone-wfm-intraday-mcp-design.md.
Tools
Tool | Purpose |
| Catalog of queryable Intraday metrics |
| Fuzzy name → canonical queue |
| Current state of all/selected queues + highest-risk queue |
| Per-interval forecast vs actual variance |
| Ranked reasons a queue is at risk |
| Donor queues with spare capacity + trade-offs |
| Before/after impact of moving N agents for Y minutes |
| Plain-English what / why / action / impact / trade-offs |
| Replace the dataset with your own queues (bring-your-own-data) |
| Restore the built-in demo dataset |
Related MCP server: Sablier MCP Server
Ways to run it
Pick the path that fits — all three end with the same 10 tools available to your assistant:
Fastest, no install → Quick start (uv): one
uvxcommand, nothing to clone.Local dev / offline / to change the data → Setup: clone + venv +
pip install.Share via a URL (teammates install nothing) → Run as a remote HTTP MCP: deploy to Cloud Run.
Then, in your assistant, ask "Which queues are at risk right now?" and follow the Demo script.
Quick start (no clone, via uv)
If you have uv installed and access to this repo, register
the server with a single command — no git clone, no venv, no pip install. uv fetches,
installs, and runs it in an ephemeral environment straight from the repo.
Claude Code:
claude mcp add cxone-wfm-intraday -- uvx --from git+https://github.com/ssolanky/cxone-wfm-intraday-mcp cxone-wfm-intradayClaude Desktop — add to claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"cxone-wfm-intraday": {
"command": "uvx",
"args": ["--from", "git+https://github.com/ssolanky/cxone-wfm-intraday-mcp", "cxone-wfm-intraday"]
}
}
}Notes: this is a local server — uv runs it on your machine, it just removes the manual
clone/install steps. Because the repo is private, uv needs Git access to it (a credential
helper via gh auth setup-git, or a token). No uv? Use the full Setup below instead.
Setup
git clone https://github.com/ssolanky/cxone-wfm-intraday-mcp.git
cd cxone-wfm-intraday-mcp
python -m venv .venv
# Windows: .venv\Scripts\activate macOS/Linux: source .venv/bin/activate
python -m pip install -e ".[dev]"
python -m pytest -q # all tests should pass (64 tests)NICE machines:
piphere defaults to a private CodeArtifact index that 401s and lacksmcp. Install from public PyPI instead:python -m pip install --index-url https://pypi.org/simple/ -e ".[dev]"(or addindex-url = https://pypi.org/simple/under[global]in.venv/pip.ini).
Run against Claude
Claude Code:
claude mcp add cxone-wfm-intraday -- python -m cxone_wfm_intraday_mcp.server(run from this project directory, using the interpreter where the package is installed).
Claude Desktop: copy the block from claude_desktop_config.example.json into your
claude_desktop_config.json (Settings → Developer → Edit Config), fixing command
to your Python interpreter, then restart Claude Desktop.
Run as a remote HTTP MCP (optional)
The same server can serve the Streamable HTTP transport instead of stdio, so teammates
add just a URL — nothing installed locally. It's zero config: the server serves HTTP
automatically when a PORT env var is present (as on Google Cloud Run) or MCP_TRANSPORT=http
is set, and otherwise stays stdio for local use. HTTP endpoint path is /mcp.
Test it locally:
# macOS/Linux
MCP_TRANSPORT=http PORT=8080 python -m cxone_wfm_intraday_mcp.server
# Windows PowerShell
$env:MCP_TRANSPORT="http"; $env:PORT="8080"; python -m cxone_wfm_intraday_mcp.server
# now serving at http://127.0.0.1:8080/mcpDeploy to Google Cloud Run (free tier, scales to zero) — from the repo root, using the
included Dockerfile:
gcloud run deploy cxone-wfm-intraday --source . --region <region>Cloud Run builds the image, injects PORT, and the server serves HTTP automatically. It
prints a service URL; register it with any assistant:
claude mcp add --transport http cxone-wfm-intraday https://<service-url>/mcpAuth: a public URL serving even mock data should be protected. Cloud Run requires IAM auth by default (omit
--allow-unauthenticated); for other hosts put a token/proxy in front. Authentication was deliberately deferred by the Sparkathon spec — add it before any non-demo use.
Demo script
"Which queues are at risk right now?" → snapshot flags Billing Support.
"Why is Billing Support at risk?" → volume +18%, AHT +11%, staffing −3.
"What can we do to recover?" → move 2 agents from General Enquiries.
"What would the impact be?" → SLA 72% → ~81%, General Enquiries stays above target.
What you can ask (and what you'll get back)
You never call tools by name — just ask in plain language and the assistant picks the right tool(s). The tables below list example prompts, the tool(s) that fire, and the answer you can expect on the built-in demo data (swap in your own data and the same questions work — see Bring your own data).
Reading current state
Ask something like… | Tool(s) | Expected answer (demo data) |
"What metrics can I query?" / "What data do you have?" |
| The 11 Intraday metrics with definitions/units: SLA, SLA target, forecast/actual volume, forecast/actual AHT, planned/actual staffing, occupancy, backlog, risk status. |
"Which queues are at risk right now?" / "Give me the intraday snapshot" |
| All 5 queues with SLA/target, volume, AHT, staffing, occupancy, backlog, risk — and highest risk: Billing Support (72% vs 80% target). |
"How is Sales doing?" / "Show me just Billing and General Enquiries" |
| The selected queue(s) only. Sales → 83% vs 80% target, watch. |
"Does 'GE' / 'the billing queue' / 'tech support' map to a real queue?" |
| Resolves fuzzy names/aliases → General Enquiries / Billing Support / Technical Support (with a confidence level). |
Explaining risk
Ask something like… | Tool(s) | Expected answer (demo data) |
"Why is Billing Support at risk?" |
| Primary: volume +18% above forecast. Also AHT +11%, staffing 3 below plan, occupancy 92%, backlog 47. Severity: high. |
"How are actuals tracking vs forecast for Billing this morning?" |
| Six 30-min intervals (08:00–10:30); variance widens from ~0% to +18% volume / +11% AHT, staffing drifts 15 → 12. |
"Which queue is under the most pressure and why?" |
| Billing Support, driven by the volume spike + AHT + staffing gap (as above). |
Finding capacity & recovering
Ask something like… | Tool(s) | Expected answer (demo data) |
"Is there spare capacity to help Billing?" / "Who can lend agents?" |
| General Enquiries can spare 2 (SLA 94% → ~92%, still above target); Complaints can spare 1. Sales & Technical Support: none (staffed to plan). |
"What's the best recovery action?" / "How do we recover Billing's SLA?" |
| Move 2 agents from General Enquiries to Billing Support for 60 min → Billing SLA 72% → ~81.2%, GE stays above target. Trade-off + "monitor AHT and backlog" included. |
"What happens if I move 2 agents from General Enquiries to Billing for 60 minutes?" |
| Billing 72% → 81.2% (occupancy 92 → 79); GE 94% → 91.9% (occupancy 71 → 81), stays above its 80% target; no new risk. |
"What if I move 3 instead?" |
| Billing → 84.6%, GE → 90.6% — but flagged: 3 exceeds GE's spare capacity of 2, so GE drops below its own plan. |
"Can I pull 2 from Sales instead?" |
| Billing → 81.2%, but Sales falls 83% → ~71%, below its 80% target — not a safe donor (risk created). |
Bring-your-own-data & housekeeping
Ask something like… | Tool(s) | Expected answer |
"Load this intraday data, then tell me which queue is at risk: |
| "Loaded N queues; highest risk: |
"Reset to the demo data" |
| Restores the built-in 5-queue demo for your session. |
A full worked conversation (demo data)
You: Which queues are at risk right now? Assistant: Five queues are live. Billing Support is the highest risk — SLA 72% against an 80% target. General Enquiries (94%), Technical Support (88%) and Complaints (91%) are healthy; Sales (83%) is on watch.
You: Why is Billing Support at risk? Assistant: Three things are compounding: volume is 18% above forecast, AHT is 11% higher than expected, and staffing is 3 agents below plan — pushing occupancy to 92% with a backlog of 47. The variance has widened steadily since 08:00.
You: What can we do to recover? Assistant: General Enquiries has 2 agents of spare capacity (it's 2 over plan at 94% SLA). Complaints could lend 1; Sales and Technical Support have none.
You: What would moving 2 from General Enquiries do? Assistant: Billing Support SLA improves from 72% to ~81.2% and its occupancy eases from 92% to ~79%. General Enquiries dips to ~91.9% — still comfortably above its 80% target. No new risk is created. Recommend the move for 60 minutes and keep watching AHT and backlog.
When something's off (error responses)
Ask something like… | What you'll get |
"Analyze the Refunds queue" | An error naming the valid queues: "Could not resolve 'Refunds'… Valid queues: Billing Support, Complaints, General Enquiries, Sales, Technical Support." |
"Move 50 agents from General Enquiries to Billing" | "Cannot move 50 agents from General Enquiries; only 16 are staffed." |
Loading data with a missing/invalid field | A clear message (e.g. "queue 'x': missing required field 'sla_current'" or "risk_status must be one of ('at_risk','watch','healthy')"), and the current dataset is left untouched. |
Where the data comes from
All data is synthetic and hardcoded in cxone_wfm_intraday_mcp/data.py — a fixed
in-memory list of 5 queues loaded once at startup. There is no database, API, CXone
tenant, network call, or randomness, so every run returns identical numbers (a
repeatable demo by design). This matches the spec: for the prototype, mocked data is
acceptable; the point is proving the pattern of grounded, tool-driven answers.
What's stored by hand vs. computed at call time:
Stored (the demo "facts"), per queue in
data.py:sla_current,sla_target,volume_actual/forecast,aht_actual/forecast,staffing_planned/actual,occupancy,backlog, arisk_statuslabel (at_risk/watch/healthy), and a 6-interval forecast-vs-actual history.Computed from those stored fields at call time — this is the real "analysis":
get_intraday_snapshotranks queues by storedrisk_status(analysis.py).get_forecast_vs_actual/get_intraday_risk_driverscompute volume/AHT/staffing variance from the stored actual-vs-forecast values and flag drivers over thresholds (analysis.py).get_available_capacityderives spare agents (surplus over plan, validated against the SLA curve).simulate_recovery_actionrecomputes SLA for both queues via the formula below (simulation.py).
So "Billing Support is at risk" is a hand-authored label, but "…because volume is +18%, AHT +11%, staffing −3, and moving 2 agents lifts SLA 72→81.2%" is genuinely calculated from the stored fields — never invented by the assistant.
Change the scenario (make a different queue at risk, tweak SLA/volume/staffing,
add a queue) by editing the literals in data.py — nothing else needs to change. In a
real product, data.py would be replaced by live CXone WFM as the source of truth; the
tool contracts stay identical.
Bring your own data
Consumers can analyze their own Intraday data without editing any code, via two tools:
load_intraday_data— replace the dataset with your own queues; every other tool then analyzes your data.reset_intraday_data— restore the built-in demo.
Just ask the assistant (e.g. "Load this Intraday data and tell me which queue is at risk") and provide queues shaped like:
{
"queues": [
{"id": "payments", "name": "Payments", "sla_current": 64, "sla_target": 85,
"volume_forecast": 200, "volume_actual": 260, "aht_forecast": 280, "aht_actual": 320,
"staffing_planned": 18, "staffing_actual": 14, "occupancy": 94, "backlog": 40,
"risk_status": "at_risk", "aliases": ["pay"]},
{"id": "onboarding", "name": "Onboarding", "sla_current": 97, "sla_target": 80,
"volume_forecast": 90, "volume_actual": 80, "aht_forecast": 300, "aht_actual": 290,
"staffing_planned": 7, "staffing_actual": 10, "occupancy": 55, "backlog": 0,
"risk_status": "healthy"}
]
}Per-queue fields: id, name, sla_current, sla_target, volume_forecast,
volume_actual, aht_forecast, aht_actual, staffing_planned, staffing_actual
(≥ 1 — the SLA curve divides by it), occupancy, backlog, risk_status
(at_risk | watch | healthy). Optional: aliases (list) and intervals (list of
{interval, volume_forecast, volume_actual, aht_forecast, aht_actual, staffing_planned, staffing_actual}). Percentages are 0–100, times are seconds, staffing is agent counts.
Invalid input is rejected with a clear message and leaves the current dataset untouched.
Isolation: loaded data is scoped to your MCP session — on a shared HTTP server each conversation gets its own dataset (one client's load never affects another).
reset_intraday_data, or the session ending, restores the demo for that session only. stdio has a single session (just you). Nothing is persisted to disk; the dataset lives in memory for the life of the session.
The simulation model
Rule-based and deterministic. Each queue has a staffing→SLA response curve
sla(n) = 100 − (100 − sla_current)·decay^(n − staff_actual), with
decay = exp(−2.4 / staff_actual), anchored so sla(actual) = current SLA. Every
number the assistant reports comes from this formula given tool inputs — not from
the model's own reasoning. See §6 of the design spec.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ssolanky/cxone-wfm-intraday-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server