Skip to main content
Glama
MSPbotsAIFramework

datto-rmm-mcp

datto-rmm-mcp

MCP server for Datto RMM — device inventory, the component (script) library, Quick Job execution (run a component on a device right now), and alert visibility/resolution, over the Model Context Protocol (Streamable HTTP/SSE transport).

Built for PRD-16562 (on-prem operations via Datto RMM, alongside self-host/NinjaOne) after a feasibility investigation confirmed the API surface — see Known Gaps for exactly what was and wasn't verified before this was written.

MSPbots Connector

The MCP Gateway built for MSPs: visible, controlled, and your data stays where it belongs.

Get started at connect.mspbots.ai →


MSPbots Connector gives your AI clients one MCP URL to reach your entire MSP stack (RMM, PSA, documentation, security, finance), and gives you control over who can call which tool and a record of everything that was called.

Hosted service: connect.mspbots.ai · Free to use.

Why Connector

MSPbots Connector

Visible

Every tool call is logged: who, which vendor, when. Usage dashboard, CSV export, SIEM streaming.

Controlled

Role-based, per-tool allowlist. Deny by default.

Protected

Credentials encrypted per record. AI clients never see your vendor passwords or tokens.

MSP-native

Built for the MSP stack only: RMM, PSA, documentation, security, finance.

Quick start

  1. Sign up at connect.mspbots.ai.

  2. Connect your vendors. Pick from 150+ connectors and authorize each one on the vendor's own page, or bring your own API keys. No extra vendor accounts needed.

  3. Set access. Create roles and decide which tools each role may call. Nothing is allowed until you allow it.

  4. Add your MCP URL to your AI client. Copy the URL from your Connector dashboard into Claude, ChatGPT, Cursor, VS Code, Gemini, Codex, or any MCP-capable client.

  5. Ask your AI to do real work, and watch every call appear in the audit log.

Features

Unified gateway

  • One MCP URL for all your AI clients

  • 150+ connectors across the MSP stack

  • Custom MCP servers supported, free

  • Authorization happens on each vendor's own page; the AI never sees passwords or tokens

  • Bring your own credentials: use the vendor API keys you already have

  • Multiple accounts per app; connect once, reuse across AI clients

  • Tool search: finds the right action for the task

  • One sign-in; vendor credentials are injected behind the scenes and OAuth tokens refresh automatically

Visibility

  • Audit log for every tool call (who, which vendor, when)

  • Usage dashboard: call volume, top vendors, error rate, per-user activity

  • Export audit logs to CSV, or stream to Loki, Graylog, or LogScale (SIEM)

  • Optional recording of tool arguments and result summaries (off by default, enabled per organization)

Control

  • Per-role, per-tool allowlist, deny by default

  • owner / admin / member roles

  • SCIM provisioning with Entra ID, Okta, JumpCloud, and Google Workspace

Security

  • Credentials encrypted one record at a time (AES-256-GCM, per-record key)

  • AI clients authenticate with OAuth 2.1 + PKCE

  • Vendor responses are scanned for prompt-injection patterns and returned as structured data. This is one layer of defense, not a guarantee against every attack.

  • Static egress IP for customer firewall and API allowlisting

Pricing

Free.

Links: connect.mspbots.ai · mspbots.ai


Related MCP server: OpenCTI MCP Server

When would you use this

  • "What devices do we have in Datto?" / find a device before running something on it → dattormm_get_devices

  • "What scripts/components can we run?" → dattormm_get_components

  • "Run [component] on [device] now" → dattormm_run_component (⚠️ destructive, irreversible — see Known Gaps for what you can and can't confirm afterward)

  • "Did that job finish?" → dattormm_get_job_status

  • "What's alerting right now?" / narrow to one device or site → dattormm_get_alerts

  • "Resolve alert [id], I've fixed it" → dattormm_resolve_alert (⚠️ destructive, irreversible — Datto has no unresolve/reopen action)

Tools

Authorization requires the X-Datto-Api-Key and X-Datto-Api-Secret request headers; the region comes from X-Datto-Platform or X-Datto-Api-Url (see the authentication notes below).

Tool

Description

Parameters

dattormm_get_devices

List the devices under the tenant's Datto RMM account, compact by default

offset, max_results (default 50, max 250), page, hostname, site_name, device_type, operating_system, full_response (all optional)

dattormm_get_components

List the runnable components/script library, with their variables

name, offset, max_results, page (all optional)

dattormm_run_component

Run the specified component on the specified device immediately (Datto's "Quick Job"), destructive and irreversible

device_uid (required), component_uid (required), variables (optional), confirm (required, must be true)

dattormm_get_job_status

Check whether a job has reached a terminal state

job_uid (required)

dattormm_get_alerts

List alerts — account-wide, or narrowed to one device or site

status (open default or resolved), device_uid, site_uid (mutually exclusive), muted, offset, max_results, page (all optional)

dattormm_resolve_alert

Resolve the specified alert, destructive and irreversible (no unresolve/reopen exists in Datto's API)

alert_uid (required), confirm (required, must be true)

dattormm_get_job_status can only confirm whether the job is "completed", not whether it succeeded; see Known Gaps.

List results are {"items", "count", "limit", "offset", "has_more"} (plus total_count). When has_more is true, next_offset is where to continue: it starts right after the last record returned, also when a page was cut to fit the 20,000-character limit, so following it never skips a record. A call can return fewer than limit records while more remain. A full Datto device record is about 5,000 characters, so devices come back with the main fields (uid, hostname, site, OS, online state, last seen, IPs, antivirus, patch status) unless full_response is true. hostname, site_name, device_type and operating_system are partial matches done by Datto; the component name filter is applied here, scanning up to 1,000 components per call. Invalid arguments (negative page / offset, max_results outside 1-250, a missing required argument) return the invalid_argument envelope without calling Datto.

Quick Start

docker compose up --build

The server starts on http://localhost:8080.

Local (uv)

uv sync
python -m datto_rmm_mcp

Health Check

curl http://localhost:8080/health
# {"status": "ok"}

No credentials are required for the health endpoint.

Authentication

Every request to /mcp must include the following HTTP headers (provided by the MCP caller/gateway):

Header

Type

Required

Description

X-Datto-Api-Key

string

Required

API Key generated by the tenant in Datto RMM. Used as the username of the OAuth2 password grant.

X-Datto-Api-Secret

string

Required

The corresponding API Secret Key. Used as the password.

X-Datto-Platform

string

Optional

Datto RMM platform hosting the account: concord (default, US East), zinfandel (US West), merlot (Europe), vidal (Canada), syrah (Australia), pinotage (South Africa). Used when X-Datto-Api-Url is not sent. An unknown value is reported by the tools.

X-Datto-Api-Url

string

Optional

Overrides the platform: the Datto RMM regional API host where the tenant's account lives (Datto has a multi-region architecture and each tenant account is bound to one region, e.g. zinfandel-api.centrastage.net). A bare host or one with the https:// prefix both work; the server normalizes it automatically.

Missing the key or secret returns 401 Unauthorized.

Authentication mechanism: after receiving these three credentials, this service itself calls Datto's OAuth2 password grant (POST /auth/oauth/token; client_id/secret are the fixed values Datto publishes officially, public-client/public, and the tenant's API Key/Secret are used as username/password) to exchange them for the real bearer token before calling the actual endpoints. The token is not issued by the gateway on its behalf; this service does it itself (because the client credentials of Datto's OAuth are themselves public constants, there is no secret that the gateway would need to manage). The token is held only for the lifetime of a single request and is never cached.

Environment Variables

Variable

Default

Description

MCP_HTTP_PORT

8080

Listening port

MCP_HTTP_HOST

0.0.0.0

Listening host

MCP Endpoint

POST http://localhost:8080/mcp

Connect your MCP client with:

  • Transport: http (Streamable HTTP / SSE)

  • Headers: X-Datto-Api-Key, X-Datto-Api-Secret (required); X-Datto-Platform or X-Datto-Api-Url (optional, default platform concord)

Test Example

curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-Datto-Api-Key: <api-key>" \
  -H "X-Datto-Api-Secret: <api-secret>" \
  -H "X-Datto-Api-Url: zinfandel-api.centrastage.net" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": { "name": "dattormm_get_devices", "arguments": { "max_results": 10 } }
  }'

⚠️ This repository is public. Do not write real API Keys/Secrets into any committed file; the placeholders above are for illustration only.

Known Gaps

  • What was actually verified live, and how. This server was written after a feasibility investigation on real customer Datto RMM accounts (read-only credentials, OAuth2 password grant against real tenant_integration records), not from documentation alone:

    • GET /api/v2/account/devices — called for real, returned real device records (1711 devices in one tested account).

    • GET /api/v2/account/components — called for real, returned 250 real components.

    • GET /api/v2/job/{jobUid} — called for real, twice, against two different real job UIDs on two different tenant accounts. Both returned only {id, dateCreated, name, uid, status} — no exitCode, stdout, stderr, or success/failure field of any kind.

    • PUT /api/v2/device/{deviceUid}/quickjob (the tool that actually runs a script) has never been executed — by design, the investigation was read-only to stay invisible to customers. Its request/response contract in api_client.py/tools/jobs.py is taken from Datto's own current official documentation (rmm.datto.com/help/en/Content/2SETUP/APIv2.htm), not from a real call. Test this for real (a Datto trial/sandbox account, or an explicit customer-consented dry run) before treating this tool as production-ready.

  • No success/failure or stdout/stderr reporting, on purpose — and this is not a version artifact. Datto's own current API documentation states outright: "It is not possible from within the API to examine the success or failure result of a completed job schedule and access the StdOut/StdErr." Datto's v14.0.0 release notes separately claim "New API endpoints under v2/job now allow retrieval of job results, including StdOut and StdErr" — these two official Datto documents contradict each other, and this investigation could not resolve it: the "new endpoint" the release notes describe was never found (WebSearch results describing it could not be traced to a real, citable page), and there's no way to read a tested account's platform version from the API to know whether it should even have this capability. What's certain: the two real accounts tested, right now, do not return this data via GET /v2/job/{jobUid}. Given this, dattormm_get_job_status's docstring is deliberately conservative — it reports only "reached a terminal state," never success. Do not add a success/failure field to this tool without a fresh, real test proving the new endpoint (whatever it turns out to be) actually exists and works.

  • dattormm_run_component's request shape is desk-verified, not field-verified. {"componentUid": ..., "<variableName>": "<value>", ...} is what Datto's docs say to send; the docs also say a successful response contains a uid usable as dattormm_get_job_status's job_uid — this server is built to that contract, but no real call has confirmed it works as documented, whether variable names are validated, or what a validation error actually looks like from this specific endpoint (blind probing during this investigation got a generic {"detail":"Failed to read request"} for every guessed body shape, including ones matching the eventual documented shape — that response never got more specific no matter what was sent, so it's untested whether the documented shape actually parses).

  • componentUid discovery: dattormm_get_components is the intended way to find one (confirmed working), even though Datto's own docs say to copy it from the UI manually — the API path works in practice, use it.

  • No write/admin endpoints beyond quickjob and alert resolution are wrapped: device claim/unclaim, site management, and anything else in Datto's API are out of scope for this MCP.

  • Alert endpoints (dattormm_get_alerts, dattormm_resolve_alert, PRD-21198) are desk-verified from Datto's published API documentation, not field-verified — no Datto trial/sandbox account was available in this environment, the same constraint dattormm_run_component already documents above:

    • The account/device/site-scoped list endpoints are assumed to share the same pageDetails/paging contract as devices/components; this has not been confirmed against a real tenant's response. fetch_page's generic handling tolerates a differently-shaped pageDetails without crashing, but has_more/next_offset could be wrong if the real shape differs.

    • dattormm_resolve_alert's actual response shape, and what resolving an already-resolved alert does, are both undocumented by Datto and unverified. The tool passes Datto's response straight through either way. Test both for real before fully trusting them.

    • Mute/unmute are not wrapped: Datto removed that capability from its own API in release 8.9.0, so there is no "unresolve" or "reopen" path through this API at all.

  • Pagination: Datto's page is 0-based and page N starts at N * max (confirmed by QA on INT, PRD-21480). Tools expose offset / next_offset on top of it; max_results is capped at 250. Query parameters and record fields follow Datto's published OpenAPI document (https://concord-api.centrastage.net/api/v3/api-docs).

License

Copyright 2026 MSPbots.ai. Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with OpenCTI threat intelligence platform through the Model Context Protocol, providing tools for indicators, observables, reports, cases, investigations, and more.
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables Claude to interact with Datto RMM accounts for device, alert, site, and quick job management through natural language.
    Apache 2.0