duo-mcp
Provides tools for interacting with Cisco Duo's Admin API, enabling management of users, groups, phones, tokens, WebAuthn credentials, policies, endpoints, and other Duo security settings for multi-factor authentication and zero-trust access.
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., "@duo-mcplist all users in the Engineering group"
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.
duo-mcp
MCP server for the Cisco Duo Admin API — Duo's multi-factor authentication and zero-trust access platform. Built to cover MFA synchronization, user pre-enrollment, and enrollment validation (the capabilities this task specifically requested), and — per an explicit follow-up scope decision — the full Admin API beyond that.
Overview
Stateless HTTP service. No credentials are ever persisted — each request supplies its own integration key/secret key/API host via headers, used only for the lifetime of that single request.
Supports concurrent requests; per-request credential isolation is done via Python
contextvars, not a global/shared client instance.Entry points:
POST /mcp(MCP protocol) andGET /health(health check).Default port:
8080(configurable viaMCP_HTTP_PORT).
Related MCP server: syncro-mcp
Scope
28 tools, trimmed down from an original 160-tool full-Admin-API build
(2026-08-04). Duo has no existing MSPbots integration to anchor scope
against — it was never previously configured in MSPbots' platform — so
unlike other trimmed vendors in this program, "actual usage" was taken from
the original ClickUp task's own stated requirement instead of a live API
config: MFA synchronization, user pre-enrollment, and enrollment
validation. Those 3 capabilities map to the users category almost
entirely, plus the resource types a user's MFA methods reference:
MFA synchronization:
duo_users_retrieve_users,duo_users_retrieve_user_by_id,duo_users_synchronize_user_from_directory, plus per-user MFA-method listing (retrieve_phones_by_user_id,retrieve_hardware_tokens_by_user_id,retrieve_web_authn_credentials_by_user_id,retrieve_groups_by_user_id)User pre-enrollment:
duo_users_create_user,duo_users_enroll_user,duo_users_associate_phone_with_user(+disassociate),duo_users_associate_hardware_token_with_user,duo_users_associate_group_with_user, plus phone provisioning (duo_phones_create_phone,duo_phones_create_activation_code_via_sms)Enrollment validation:
duo_users_send_verification_push+duo_users_retrieve_verification_push_response
Plus core CRUD/list for the referenced resource types themselves —
duo_users_modify_user, duo_users_delete_user,
duo_users_create_bypass_codes_for_user, duo_phones_retrieve_phones,
duo_phones_retrieve_phone_by_id, duo_tokens_retrieve_hardware_tokens,
duo_tokens_retrieve_hardware_token_by_id,
duo_webauthn_credentials_retrieve_web_authn_credentials (+ _by_key),
duo_groups_retrieve_groups, duo_groups_get_group_info.
Everything else from the original 160-tool build — Desktop Authenticators, Bypass Codes (standalone category; the per-user variant
under users was kept), Integrations, Policies, Endpoints,
Registered Devices, Passport, Administrators, Administrative Units,
Logs, Trust Monitor, Settings, Custom Branding, Account Info,
Bulk Operations (15 categories, ~132 tools) — was removed as unrelated to
the original task's 3 stated capabilities.
No official Duo MCP exists — searched GitHub (duo-mcp, "duosecurity" mcp) and both wyre-technology/MSPbotsAI orgs before building; the only
existing "Duo + MCP" material is Duo SSO for MCP,
which is the reverse relationship (Duo as an identity provider protecting
MCP servers), not a Duo Admin API MCP server.
Source data for the kept tools was originally extracted from Duo's own
official Postman collection
(https://github.com/duosecurity/duo_postman_collection, duo-admin-api
folder), cross-referenced against the live duo.com/docs/adminapi
documentation. If a removed category is needed later, that same source can
be re-parsed the same way.
Authentication
Duo Admin API auth is not a simple bearer token — every request is
individually signed with HMAC-SHA512 (Duo's "sig_version 5") using an
Integration Key (ikey) and Secret Key (skey). This server implements
that signing logic itself (ported line-for-line from Duo's own
reference Python client
and verified byte-for-byte identical against that reference
implementation for both GET-style query-signed requests and POST-style
JSON-body-signed requests, including special-character percent-encoding) —
callers only need to supply the raw ikey/skey/host per request; this server
computes the canonical string, HMAC, and Authorization: Basic header on
every call.
Per Duo's own signing convention: GET/DELETE requests sign and send
params as a url-encoded query string; POST/PUT/PATCH requests sign and
send params as a single JSON object request body. Tools in this server don't
need to know which — the client picks the correct transport based on the
HTTP method automatically, exactly matching the reference implementation's
behavior.
HEADER 授权参数说明
Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
| string | 是 | 无 | 无 | Duo Admin API 集成的 Integration Key(用作 HMAC 签名的 Basic Auth 用户名部分) |
|
| string | 是 | 无 | 无 | Duo Admin API 集成的 Secret Key(HMAC-SHA512 签名密钥,仅用于当次请求签名计算,不落盘) |
|
| string | 是 | 无 | 无 | 该 Duo 账号的 Admin API host(每个账号独立子域名,如 |
|
Missing any header returns 401:
{
"error": "Missing credentials",
"message": "This server requires the X-Duo-Ikey, X-Duo-Skey, and X-Duo-Api-Host headers",
"required_headers": ["X-Duo-Ikey", "X-Duo-Skey", "X-Duo-Api-Host"],
"optional_headers": []
}Environment Variables
Variable | 类型 | 是否必填 | 默认值 | 说明 |
| int | 否 |
| HTTP 监听端口 |
| string | 否 |
| HTTP 监听地址 |
MCP Endpoint
POST /mcp— MCP protocol (streamable HTTP transport)GET /health— health check, returns{"status": "ok"}(local-only probe, does not call Duo)
Tool List
Tool names are duo_<category>_<operation>, derived from each operation's
name in Duo's official Postman collection. body parameters (for endpoints
whose payload is a nested/complex JSON object rather than flat scalar
fields, e.g. bulk operations, SSO integration config, policy sections) are
accepted as a generic dict — the docstring lists the top-level keys from
Duo's own example, and the full schema is in the linked API reference.
The 3 capabilities this task specifically named map to these tools:
MFA synchronization:
duo_users_retrieve_users,duo_users_synchronize_user_from_directoryUser pre-enrollment:
duo_users_create_user,duo_users_enroll_userEnrollment validation:
duo_users_send_verification_push+duo_users_retrieve_verification_push_response
Category | Tool | Description | Method + Path | Params |
groups |
| Get Group Info. | GET /admin/v2/groups/{group_id} | group_id(required) |
groups |
| Retrieve Groups. | GET /admin/v1/groups | limit(optional), offset(optional) |
phones |
| Create Activation Code via SMS. | POST /admin/v1/phones/{phone_id}/send_sms_activation | phone_id(required), valid_secs(optional), install(optional), installation_msg(optional), activation_msg(optional) |
phones |
| Create Phone. | POST /admin/v1/phones | none |
phones |
| Retrieve Phone by ID. | GET /admin/v1/phones/{phone_id} | phone_id(required) |
phones |
| Retrieve Phones. | GET /admin/v1/phones | number(optional), extension(optional), limit(optional), offset(optional) |
tokens |
| Retrieve Hardware Token by ID. | GET /admin/v1/tokens/{token_id} | token_id(required) |
tokens |
| Retrieve Hardware Tokens. | GET /admin/v1/tokens | type(optional), serial(optional), limit(optional), offset(optional) |
users |
| Associate Group with User. | POST /admin/v1/users/{user_id}/groups | user_id(required), group_id(required) |
users |
| Associate Hardware Token with User. | POST /admin/v1/users/{user_id}/tokens | user_id(required), token_id(required) |
users |
| Associate Phone with User. | POST /admin/v1/users/{user_id}/phones | user_id(required), phone_id(required) |
users |
| Create Bypass Codes for User. | POST /admin/v1/users/{user_id}/bypass_codes | user_id(required), count(optional), codes(optional), reuse_count(optional), valid_secs(optional) |
users |
| Create User. | POST /admin/v1/users | username(required), aliases(optional), realname(optional), email(optional), status(optional), notes(optional), firstname(optional), lastname(optional) |
users |
| Delete User. | DELETE /admin/v1/users/{user_id} | user_id(required) |
users |
| Disassociate Phone from User. | DELETE /admin/v1/users/{user_id}/phones/{phone_id} | user_id(required), phone_id(required) |
users |
| Enroll User. | POST /admin/v1/users/enroll | username(required), email(required), valid_secs(optional) |
users |
| Modify User. | POST /admin/v1/users/{user_id} | user_id(required), username(optional), aliases(optional), realname(optional), email(optional), status(optional), notes(optional), firstname(optional), lastname(optional) |
users |
| Retrieve Groups by User ID. | GET /admin/v1/users/{user_id}/groups | user_id(required), limit(optional), offset(optional) |
users |
| Retrieve Hardware Tokens by User ID. | GET /admin/v1/users/{user_id}/tokens | user_id(required), limit(optional), offset(optional) |
users |
| Retrieve Phones by User ID. | GET /admin/v1/users/{user_id}/phones | user_id(required), limit(optional), offset(optional) |
users |
| Retrieve User by ID. | GET /admin/v1/users/{user_id} | user_id(required) |
users |
| Retrieve Users. | GET /admin/v1/users | username(optional), limit(optional), offset(optional) |
users |
| Retrieve Verification Push Response. | GET /admin/v1/users/{user_id}/verification_push_response | user_id(required), push_id(required) |
users |
| Retrieve WebAuthn Credentials by User ID. | GET /admin/v1/users/{user_id}/webauthncredentials | user_id(required) |
users |
| Send Verification Push. | POST /admin/v1/users/{user_id}/send_verification_push | user_id(required), phone_id(required) |
users |
| Synchronize User from Directory. | POST /admin/v1/users/directorysync/{directory_key}/syncuser | directory_key(required), username(required) |
webauthn_credentials |
| Retrieve WebAuthn Credentials. | GET /admin/v1/webauthncredentials | limit(optional), offset(optional) |
webauthn_credentials |
| Retrieve WebAuthn Credentials by Key. | GET /admin/v1/webauthncredentials/[webauthnkey] | webauthnkey(required) |
测试示例
# Health check
curl -s http://localhost:8080/health
# Call a tool via the MCP protocol (streamable HTTP) — requires an
# initialize handshake first per the MCP spec; abbreviated example below
# shows the tool-call request body only:
curl -s -X POST http://localhost:8080/mcp \
-H "X-Duo-Ikey: <your-integration-key>" \
-H "X-Duo-Skey: <your-secret-key>" \
-H "X-Duo-Api-Host: api-xxxxxxxx.duosecurity.com" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: <session-id-from-initialize>" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "duo_users_retrieve_users",
"arguments": {"limit": "5"}
}
}'Signing correctness verified independently of any live account: this
server's HMAC-SHA512 request-signing implementation was directly compared,
side-by-side in the same Python process, against Duo's own official
reference client (duo_client_python) — the canonical string, the full
Authorization: Basic header, and percent-encoding of special characters
were all confirmed byte-for-byte identical for both a GET (query-signed) and
a POST (JSON-body-signed) scenario. Structural checks were also completed:
MCP handshake, tools/list returning all 160 registered tools, and 401
credential-gating with placeholder header values.
Live self-test against a real Duo account: passed. Using a real Admin API
integration created in a live Duo account, three calls were made through the
running MCP server end-to-end (real HTTP requests to
api-4d02a5dd.duosecurity.com, real HMAC-SHA512 signing, real response
parsing):
duo_administrators_retrieve_administrators→ returned the real account owner (ryan.li@mspbots.ai, roleOwner, an enrolled iPhone with push capability).duo_integrations_retrieve_integrations→ returned the Admin API integration itself, withintegration_keymatching the ikey used to authenticate — direct proof the signature was accepted by Duo.duo_users_retrieve_users→ returned[]. Cross-checked against the two calls above (not assumed): since both other calls returned real, non-empty data through the identical auth/parsing path, the empty array reflects a genuinely fresh account with zero enrolled end users yet, not a masked auth failure.
API Reference
Admin API docs: https://duo.com/docs/adminapi
Official Postman collection: https://github.com/duosecurity/duo_postman_collection
Reference Python client (signing algorithm source): https://github.com/duosecurity/duo_client_python
Known Gaps
Trimmed from 160 to 28 tools on 2026-08-04. The original build covered the full public Admin API per an earlier follow-up scope decision (justified at the time by there being no MSPbots-existing integration to anchor a narrower scope against). A later scope decision cut this back to the original ClickUp task's actual 3 stated capabilities (MFA sync / pre-enrollment / enrollment validation) plus minimal supporting CRUD — see the Scope section above for the exact mapping and the full list of the 15 removed categories (~132 tools). If a removed category is needed later, Duo's own Postman collection (linked below) still documents its exact operations and they can be re-added the same way the kept tools were generated.
Several kept tools still mutate real Duo account data (
duo_users_create_user,duo_users_delete_user,duo_users_enroll_user,duo_phones_create_phone, etc.) — treat these as state-changing and confirm with a human before invoking.bodyparameters are untyped (dict) where a tool has a nested/ complex JSON payload — each such tool's docstring lists the top-level keys from Duo's own example payload; the full schema is in the linked API reference.Live functional self-test passed (pre-trim) against a real Duo account — administrators and integrations endpoints returned real data; the users endpoint correctly returned an empty list for this account's current (zero end-user) state. Not independently re-verified against the live API after the trim, though the trim only removed tools/files and changed no request-building logic for the ones kept.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityCmaintenanceA community MCP server for Cisco Secure Access that exposes the Secure Access REST API to AI clients as a curated catalog of tools for Admin, Deployments, Investigate, Policies, and Reports.421Apache 2.0
- AlicenseNot gradedqualityAmaintenanceAn MCP server for Syncro MSP platform, enabling management of tickets, assets, customers, and billing through Syncro's API.3Apache 2.0
- AlicenseNot gradedqualityDmaintenanceMCP server for interacting with Sophos Central APIs, providing 255 tools for managing endpoints, alerts, policies, and more across partners, organizations, and single tenants.166MIT
- FlicenseNot gradedqualityFmaintenanceMCP server that provides access to Auth0 Management API v2, offering read-only tools grouped by categories for querying Auth0 resources.
Related MCP Connectors
34 production API tools over one hosted MCP endpoint.
XFA's remote MCP server — query device posture, compliance, policies & CVEs. Read-only.
MCP Server for agents to onboard, pay, and provision services autonomously with InFlow
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/MSPbotsAI/duo-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server