The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the NinjaOne listing page.
A Model Context Protocol (MCP) server for interacting with NinjaOne, featuring a decision tree architecture for efficient tool loading.
[!IMPORTANT] Before you click: this server depends on
@wyre-ai/node-ninjaone, which is hosted on the GitHub Packages npm registry. GitHub Packages has no anonymous access — even though the package is public, everynpm installneeds a token. The cloud builder runsnpm installfor you, so you must give it one, or the build fails withnpm error 401 Unauthorized ... npm.pkg.github.com.
- Create a GitHub Personal Access Token with the
read:packagesscope (classic token). Any GitHub account works — you do not need to be a member of thewyre-aiorg to read its public packages.- Add it as a build variable when prompted by the deploy flow:
- Cloudflare Workers → set a build variable named
NODE_AUTH_TOKENto your PAT (Workers → Settings → Build → Variables and Secrets).- DigitalOcean App Platform → set an encrypted env var named
GITHUB_TOKENwith scope Build Time to your PAT (the.do/app.yamlalready declares it).
[!NOTE] Both targets run the full MCP server. DigitalOcean builds the Docker image and serves it over HTTP; Cloudflare Workers serves the same server via the SDK's Web Standard Streamable HTTP transport (
src/worker.ts). After deploying, set your NinjaOne credentials as secrets —NINJAONE_CLIENT_ID,NINJAONE_CLIENT_SECRET, and optionallyNINJAONE_REGION— or setAUTH_MODE=gatewayto take credentials per-request fromX-Ninja-*headers. The MCP endpoint is/mcp;/healthis an unauthenticated liveness probe.
This MCP server uses a hierarchical tool loading approach instead of exposing all tools upfront:
ninjaone_navigate)This architecture provides:
This package is published to the GitHub Packages npm registry, which requires a token even for public packages. Authenticate once, then install:
The repo's .npmrc already points the @wyre-ai scope at GitHub Packages and
reads the token from NODE_AUTH_TOKEN, so no further config is needed. The same applies
to npx @wyre-ai/ninjaone-mcp below. Prefer a zero-setup option? Use the prebuilt
container image (ghcr.io/wyre-ai/ninjaone-mcp) or the .mcpb bundle attached to
each release.
Set the following environment variables:
| Variable | Required | Description |
|---|---|---|
NINJAONE_CLIENT_ID | Yes | OAuth 2.0 Client ID |
NINJAONE_CLIENT_SECRET | Yes | OAuth 2.0 Client Secret |
NINJAONE_REGION | No | Region: us (default), eu, oc, ca, us2, or fed |
NINJAONE_SCOPES | No | OAuth scopes to request. Defaults to monitoring,management. Set this if your API app is granted a narrower set — see OAuth scopes |
| Region | Base URL |
|---|---|
us | https://app.ninjarmm.com |
eu | https://eu.ninjarmm.com |
oc | https://oc.ninjarmm.com |
ca | https://ca.ninjarmm.com |
us2 | https://us2.ninjarmm.com |
fed | https://fed.ninjarmm.com |
Add to your Claude Desktop claude_desktop_config.json:
Manage endpoints, reboot devices, view services and alerts.
Tools:
ninjaone_devices_list - List devices, filterable by organization, device class, and online status. Paginated: a full page returns hasMore: true and a cursor to pass back for the next page.ninjaone_devices_get - Get device detailsninjaone_devices_reboot - Schedule a device rebootninjaone_devices_services - List Windows services on a deviceninjaone_devices_alerts - Get device-specific alertsninjaone_devices_activities - View device activity logninjaone_devices_get_custom_fields - Get device custom fieldsninjaone_devices_update_custom_fields - Update device custom fieldsManage customer organizations and their resources.
Tools:
ninjaone_organizations_list - List organizationsninjaone_organizations_get - Get organization detailsninjaone_organizations_create - Create a new organizationninjaone_organizations_locations - List organization locationsninjaone_organizations_devices - List devices for an organizationninjaone_organizations_get_custom_fields - Get organization custom fieldsninjaone_organizations_update_custom_fields - Update organization custom fieldsView and manage alerts across all devices.
Tools:
ninjaone_alerts_list - List alerts with filtersninjaone_alerts_get - Get a single alert by UID (renders as an interactive card in MCP Apps hosts)ninjaone_alerts_reset - Reset/dismiss a single alertninjaone_alerts_reset_all - Reset all alerts for a device or organizationninjaone_alerts_summary - Get alert count summaryFeatures:
ninjaone_alerts_get renders as an interactive card in MCP Apps hosts (Claude Desktop/web) with an in-card "Reset alert" round-trip via ninjaone_alerts_reset; neutral by default, brandable via window.__BRAND__ injection or MCP_BRAND_* env vars; plain-JSON behavior is unchanged in other hostsManage service tickets.
Tools:
ninjaone_tickets_list - List tickets from a board (requires board_id; status/organization_id/device_id filters are applied client-side, see notes below)ninjaone_tickets_get - Get ticket detailsninjaone_tickets_create - Create a new ticketninjaone_tickets_update - Update an existing ticketninjaone_tickets_add_comment - Add a comment to a ticketninjaone_tickets_comments - Get ticket commentsninjaone_tickets_boards_list - List ticket boards (to discover board_id values)Note: NinjaOne queries tickets per board, and board IDs vary by tenant — board 1 is not always the "All Tickets" board, so
ninjaone_tickets_listrequires an explicitboard_idrather than silently guessing one. Discover IDs withninjaone_tickets_boards_list; on tenants where that endpoint returns 404, read the numeric ID from the board link's URL in the NinjaOne web UI (e.g. the "All tickets" sidebar link).Note: NinjaOne's board-run API cannot filter tickets by status, organization, or device server-side (attempting to throws a generic
Bad request).ninjaone_tickets_listtherefore applies those filters client-side within one board page. The response separatescount(matches in this page) fromscanned(tickets examined) and includeshasMore/cursor— page through untilhasMoreisfalseto get every match, and never treat a single page'scountas a board-wide total. Status is matched against each ticket's status display name, so custom board statuses may not map to theOPEN/IN_PROGRESS/WAITING/CLOSEDvalues.Similarly,
ninjaone_devices_listfilters byorganization_idthrough NinjaOne's dedicated per-organization endpoint (the generaldf=orgdevice filter is unreliable and can silently return the full fleet).
Always available:
ninjaone_navigate - Select a domain to work withninjaone_status - Show current state and credential statusninjaone_back - Return to main menu (when in a domain)NinjaOne uses OAuth 2.0 for authentication. You need to:
The client library handles token refresh automatically.
By default the server requests monitoring management. Which scopes you actually
need depends on what you use:
| Scope | Needed for |
|---|---|
monitoring | All read operations — listing devices, organizations, alerts, and tickets |
management | Write operations — rebooting devices, resetting alerts, creating/updating tickets and organizations |
control | Not used by this server |
If your API app is granted fewer scopes than the default, set NINJAONE_SCOPES
to match. NinjaOne rejects a token request that asks for a scope the app was
never granted — it returns 400 invalid_scope rather than narrowing the grant —
so the failure happens at the token exchange and every tool call fails, including
reads. For a monitoring-only app:
Values may be comma- or space-separated and are case-insensitive. In gateway
deployments the same value can be supplied per request via the X-Ninja-Scopes
header.
Apache-2.0