Skip to main content
Glama
ITbuilder-Ltd

IT Glue MCP Server

IT Glue MCP Server

An MCP server over the IT Glue API for every resource and action except anything to do with passwords. It runs in a container, or as a local process over stdio, and works with MCP clients such as Claude Code and Copilot Studio.

This is an unofficial project. It is not affiliated with, endorsed by or supported by Kaseya or IT Glue.

Safety

IT Glue holds documentation and customer passwords, has no sandbox, and an API key can read and write every organisation the account has. So the code, not care, limits what the key can do:

  • No passwords, ever. The server has no tool, path, include, field or export that reads or writes a password, a password folder or a password category. Requests that mention one are refused on the way in, and anything that points at one is removed on the way out, whatever the key's Password Access setting.

  • Reads everything, writes nothing, until told otherwise. The default policy reads every organisation and writes none. Writes, deletes and account-wide writes are switched on one by one, and writes only reach the organisations on an allow-list. A tool the policy can never perform is not offered at all.

  • Restricted records are withheld. Records IT Glue marks restricted, what belongs to them, and documents and folders inside a restricted folder are left out of every reply and counted, unless the deployment turns that off.

  • Credential-like text in documents is redacted before a model reads it, by one policy wherever a document's prose appears. A write's reply names the record and never repeats its content.

  • Callers sign in with Microsoft Entra ID, and need an app role for this server: reader reads, writer writes. A caller with neither is refused before any tool runs, and a tool call whose sign-in is not admitted is refused, never served read-only. A reader is handed an IT Glue client with every write switched off, so no tool can write on a reader's behalf.

  • HTTP with no sign-in answers only the loopback names, so a web page cannot reach the server through DNS rebinding.

  • No live call without ITGLUE_LIVE=1. The key lives only in the environment, never in the image.

  • Every failure is an error, never an empty result. A change whose connection dropped says its outcome is unknown.

  • Every reply carries what a person needs to check it: the record's last-updated date and its IT Glue link, and a count of what was withheld.

Related MCP server: itglue-mcp-server

Quick start, with Docker

  1. Create an API key in IT Glue under Admin > Settings > Custom API Keys, with Password Access off. Copy .env.example to .env and put the key in it.

  2. Say who may connect. Either configure sign-in, as described under Sign in with Microsoft Entra ID, or, to try the server on this machine with nobody signing in, set ITGLUE_MCP_UNAUTHENTICATED=1 in .env.

  3. docker compose up -d mcp. The server listens at http://127.0.0.1:8000/mcp, on this machine only.

  4. Connect a client, for example:

    claude mcp add --transport http itglue http://127.0.0.1:8000/mcp

With only the key set, the server is read-only. To allow writes, name where they may go in .env:

ITGLUE_WRITES=1
ITGLUE_WRITE_ORG_IDS=<the organisation ids that may be written to, separated by commas>

Without sign-in the server refuses to listen on an address other machines can reach unless ITGLUE_MCP_UNAUTHENTICATED=1 says that is intended. compose.yaml publishes the port on 127.0.0.1 only, which is what makes that acceptable. Do not publish the port further without sign-in. The container runs as a non-root user with a read-only filesystem and no capabilities, and keeps the sign-in proxy's state on the signin-state volume. compose.yaml passes the container only the settings the server reads, listed by name, so nothing else in .env reaches it. docker inspect shows a container's environment, key and client secret included, to anyone who can use Docker on the host.

Sign in with Microsoft Entra ID

Over HTTP the server signs callers in with Microsoft Entra ID. People sign in through the server's own OAuth proxy (fastmcp's AzureProvider), which gives MCP clients the dynamic client registration that Entra lacks, so Copilot Studio's dynamic discovery, Microsoft 365 Copilot and Claude Code can connect with nothing but the server's URL. Applications, such as an Entra agent identity, present an access token they got from Entra for this server, and the server checks it directly. stdio never signs in: it answers only the program that started it, which already holds the IT Glue key. Every other transport signs in, and the server refuses to start with a transport other than http or stdio.

Who gets in, decided from the Entra access token's claims:

Caller

The token needs

Gets

A person (the token has scp)

mcp.access in scp, and the writer or reader app role

writer: the deployment's policy, writes included. reader: reads only

An application (no scp)

idtyp of app, and the writer or reader app role

The same

Anything else

Refused with HTTP 401 before any tool runs

The token must also be a v2.0 access token from your tenant (its issuer), for this app (its audience, the client id or api://<client id>), signed by one of the tenant's keys, unexpired, and already valid. The same rule runs for both kinds of caller, at one place, on every request. A person with no role who signs in through the proxy is refused at the token endpoint with an OAuth error that says the role is missing, and nothing is kept for them. A role removed later does not take effect at the next call: every call is checked against the roles in the Entra token the proxy holds for that person, and that token is only replaced when it expires or the proxy refreshes it, so the person keeps their access until then, and is refused at that refresh. Entra decides how long the token lasts. An application's token is checked the same way, until its own expiry. The server does not check azp, the client application a person signed in through: any client your tenant lets request mcp.access can be used, so control that with consent (step 1).

Each refusal is logged at WARNING with its reason, and with the caller's azp, oid and roles once the token's signature is verified; a token that fails verification is logged with the kind of failure only. An admitted call is logged at DEBUG. No token, authorization code or query string is ever logged: uvicorn's access log, which would write the sign-in callback's code, is off, and each sign-in request is logged with its method, path and status.

To set it up:

  1. Register an app in Entra ID, single tenant. Under Expose an API, set the Application ID URI to api://<client id> and add the delegated scope mcp.access, with Who can consent: Admins only, so that no user can consent to it for a client application of their own choosing; grant admin consent for the clients you use. In the manifest set requestedAccessTokenVersion to 2. Add two app roles, writer and reader, each allowed for users and groups and for applications. Add the Web redirect URI <public URL>/auth/callback, and create a client secret.

  2. Under Token configuration, add the optional claim idtyp to the access token. Entra leaves it out by default, and without it the server cannot tell an application's token from a person's ID token, so it refuses every application.

  3. Assign the roles. People and groups get reader or writer under the enterprise application's Users and groups. An application or agent identity gets one through Microsoft Graph (appRoleAssignedTo on the server's service principal). Entra issues no token for this app to an application with no role.

  4. Set the variables below in .env and start the server. ITGLUE_MCP_PUBLIC_URL is where clients reach it, with no path: https:// for another machine, or http://localhost:8000 on this one.

  5. Connect. In Copilot Studio, add an MCP tool with the URL <public URL>/mcp and OAuth 2.0 dynamic discovery. The proxy sends a sign-in back only to an address ITGLUE_MCP_ALLOWED_REDIRECT_URIS allows. By default that is any port on localhost and 127.0.0.1, for clients on this machine such as Claude Code, and https://global.consent.azure-apim.net/redirect*, where Copilot Studio's connectors are believed to receive theirs. That address is not yet verified against Copilot Studio, and it is shared by every tenant's connectors: once your connector's own redirect URL is known, set the variable to it and the loopback patterns alone. A client may not name itself by a URL for the server to fetch (CIMD). In Claude Code, claude mcp add --transport http itglue <public URL>/mcp, which signs in through the browser. The first sign-in from each client shows the proxy's consent page. Use the public URL exactly as configured, so http://localhost:8000 and not http://127.0.0.1:8000: the server's sign-in metadata names it, and a client may refuse metadata for another address.

The proxy keeps client registrations, sign-ins in progress and the Entra tokens it holds, encrypted, under FASTMCP_HOME (/data in the image), which the server makes readable by its own user only. On a read-only filesystem that must be a writable volume, as compose.yaml mounts, or the server refuses to start and says why. Without a volume, every restart forgets every registered client. Run one replica: a second would not see the first one's state. The proxy's signing key derives from the client secret unless ITGLUE_MCP_SIGNING_KEY is set, so set it to let the secret rotate without signing everyone out.

Registration (/register) needs no sign-in, as dynamic client registration requires, and each one is kept for good. The server refuses a sign-in request body over 64 KB and sweeps what has expired from the store at most every ten minutes, but it does not limit how many requests arrive: the ingress in front of it should rate-limit /register, /authorize and /token.

With sign-in, the server answers requests addressed to the public URL's host and to the loopback names, and accepts a browser's Origin only from the public URL. A reverse proxy in front must keep the Host header.

Configuration

Everything is an environment variable. compose.yaml passes the container each variable below that .env sets, by name, and nothing else from .env. Outside a container, the IT Glue client also reads the ITGLUE_ settings it uses, other than ITGLUE_LIVE, from a .env file at the repository root, and the environment wins. The server's own ITGLUE_MCP_ settings, sign-in included, come from the environment only.

Variable

Meaning

ITGLUE_LIVE

Must be 1, or nothing is sent. compose.yaml sets it

ITGLUE_API_KEY

The IT Glue API key

ITGLUE_BASE_URL

IT Glue's region: https://api.itglue.com, https://api.eu.itglue.com (default) or https://api.au.itglue.com

ITGLUE_READ_ORG_IDS

Organisation ids that may be read, separated by commas. Empty reads every organisation

ITGLUE_WRITE_ORG_IDS

Organisation ids that may be written to. Empty writes none

ITGLUE_WRITES

1 allows creating, updating and publishing, within the write list

ITGLUE_DELETES

1 also allows deleting. Needs ITGLUE_WRITES=1

ITGLUE_ACCOUNT_WRITES

1 also allows writing records that belong to no organisation, such as types and statuses. Needs ITGLUE_WRITES=1

ITGLUE_MCP_HOST, _PORT, _PATH

Where to listen: 127.0.0.1, 8000 and /mcp by default

ITGLUE_MCP_UNAUTHENTICATED

1 accepts that nobody signs in, so that the server may listen on an address other machines can reach. Refused beside sign-in

ITGLUE_MCP_SERVE_RESTRICTED

1 serves records IT Glue marks restricted. Withheld by default

ITGLUE_MCP_ENTRA_TENANT_ID, _CLIENT_ID, _CLIENT_SECRET

The Entra tenant, the app registration and its client secret. Any of them turns sign-in on, and then all three and ITGLUE_MCP_PUBLIC_URL are needed. The ids are GUIDs, in either case

ITGLUE_MCP_PUBLIC_URL

Where clients reach the server, with no path, user or password. The Entra redirect URI is this plus /auth/callback

ITGLUE_MCP_ALLOWED_REDIRECT_URIS

Where the sign-in proxy may send a client back to, separated by commas, * for any port or the rest of a path: https:// addresses, or http:// on localhost or 127.0.0.1. A wildcard host must be a single leading *. before a domain you own, as in https://*.example.com/* (the only form the sign-in proxy matches), with no empty labels or trailing dot: https://*.com/* and https://*.*.example.com/* are refused. The check has no public suffix list, only a short built-in one of common cases, so never wildcard a shared hosting domain such as github.io or azurewebsites.net. Empty: any loopback port, and Copilot Studio's connector redirect

ITGLUE_MCP_ENTRA_SCOPE

The delegated scope a person's token needs: mcp.access by default

ITGLUE_MCP_READER_ROLE, ITGLUE_MCP_WRITER_ROLE

The app role values: reader and writer by default

ITGLUE_MCP_SIGNING_KEY

Optional, 32 characters or more. Signs the proxy's tokens and encrypts its state, instead of a key derived from the client secret

FASTMCP_HOME

Where the sign-in proxy keeps its state: /data in the image

Tools

Ten tools reach every operation the server supports. Every input has one JSON type and an empty default ("", 0 or "{}"), because Copilot Studio drops a tool whose schema has a union or a reference. Objects travel as JSON text and lists of ids as comma-separated text.

Tool

What it does

Hints

describe_resources(resource="")

Every resource and what it supports, or how one is addressed and which filters, sorts and includes it allows

read-only

list_records(resource, organization_id, parent, parent_id, filters, sort, include, fields, page_number, page_size)

One page of a resource's records, with page.total and page.next

read-only

get_record(resource, record_id, organization_id, parent, parent_id, include, fields)

One record, whole

read-only

find_documents(organization_id, title_contains, folder_id, limit)

An organisation's documents whose title holds every word

read-only

get_document(organization_id, document_id, max_chars)

One document as text

read-only

list_document_folders(organization_id, name_contains, limit)

The folders, by path, with their document counts

read-only

create_record(resource, attributes, organization_id, parent, parent_id)

Create one record

writes

update_records(resource, records, organization_id, parent, parent_id)

Change one record, or several in one bulk update

writes, destructive

publish_document(document_id)

Publish a draft document

writes

delete_records(resource, record_ids, organization_id, parent, parent_id)

Delete records by id, never by filter

writes, destructive

resource is an enum built from the resource registry, narrowed to the resources the tool can reach, so a resource added to the registry reaches the right tool with no edit to the tools. Documents and their folders are reached only through the document tools.

Finding a document

IT Glue has no document search, and it lists documents one folder at a time. find_documents therefore reads the folders and lists them in a fixed order (the root's first page, folders named for the topic, then the rest by size, then the rest of the root), matching titles in memory, ignoring case. One call stops after twelve requests or twenty seconds, though it always reads at least one page, or at limit matches. Its reply then says complete: false, names the folders left, and gives continue_from, which the next call passes back with the same query to read on from the first document it did not give; or a model picks folders with list_document_folders and asks again with folder_id, which searches that folder first and then the folders inside it. Nothing is cached between calls.

IT Glue also lists a document with its whole content, so a listing is heavy. The server reads documents a page of 100 at a time, and checks that every row names the folder asked for, because IT Glue silently ignores a filter it does not know.

Without Docker

python -m venv .venv
.venv/Scripts/pip install -e ".[server]"        # .venv/bin/pip on Linux and macOS
export ITGLUE_LIVE=1                            # and ITGLUE_API_KEY, or a .env file
.venv/Scripts/python -m itglue_mcp serve                     # HTTP on 127.0.0.1:8000
.venv/Scripts/python -m itglue_mcp serve --transport stdio   # or stdio, for a client that launches it

Development

.venv/Scripts/python -B -m unittest discover -s tests -t .

scripts/agent_identity.py check calls a signed-in server as an Entra agent identity, and bridge serves it to a coding agent over stdio. It reads the agent identity's credentials from .env.agent at the repository root, or the file --credentials names, and never from the environment or .env. Git and the image's build context ignore .env.agent and any other .env.* file; a file named otherwise is not ignored, so keep the credentials in one named .env.something. Keep them there: the blueprint's client secret mints a token for every agent identity under the blueprint, so it must not reach the server's container.

A few key unit tests, and integration tests that drive the server through FastMCP's in-memory client over a local fake IT Glue (tests/support.py). Sign-in is tested over HTTP with tokens signed by a local key (tests/entra_fake.py). A safety net in the tests blocks the real .env and any network beyond 127.0.0.1.

Path

Job

itglue_mcp/api/

The IT Glue client: the resource registry, transport, retries, pagination, the password guard, the access policy

itglue_mcp/server/

The FastMCP server over the client: the tools, sign-in, who gets which client, replies, errors and the front door

itglue_mcp/server/reading/

A document's content blocks as text, with credential-like text redacted

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    Not graded
    maintenance
    An MCP server that enables LLMs to interact with IT Glue documentation, including organizations, configurations, passwords, and flexible assets. It provides tools for listing, creating, and updating managed service provider (MSP) data through the IT Glue API.
    31
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    An unofficial Model Context Protocol server that enables AI assistants to manage ITGlue documents, sections, and organizations via the ITGlue API. It supports full CRUD operations, organization lookups, and regional API endpoints for US, EU, and Australia.
    19 npm
    6
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A Model Context Protocol server that gives Claude Code (or any MCP client) controlled access to Microsoft 365 through the Microsoft Graph API: mail, calendar, contacts, files, notes, tasks, Teams, SharePoint, and the full tenant-admin surface.
    18 npm
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Connects AI assistants to IT Glue, the MSP documentation platform. Browse organizations, read and write documents and flexible assets, and answer natural-language questions via semantic vector search (OpenAI/Azure embeddings). Viewer/editor/admin roles gate tool access; bring-your-own-key applies IT Glue's native permissions. Runs over stdio or HTTP; Docker image available.
    27
    84 npm
    5
    MIT