mcpAD - an MCP server for Microsoft Active Directory

2026-10-18

mcpAD

mcpAD is a FastMCP server that exposes the msad Active Directory / LDAP library as MCP tools.

It is built with Python 3.14 and uv, and reuses the typed, public msad API (search users/groups, memberships, account status). All the tools are read-only, which makes it a safe way to let an AI agent explore and audit an Active Directory domain without the risk of changing anything.

If you already know msad — the command line tool for working with AD/LDAP — mcpAD is its natural companion: the same library, now reachable from any MCP client (Claude Desktop, IDE agents, custom agents, …).

Tools

The server exposes a rich set of read-only tools, grouped by purpose.

Search and lookup

Tool Description
find_users Find users by name/surname/mail/sam/department (criteria are ANDed, * wildcards)
get_user Get a single user by sAMAccountName, UPN, mail or cn (exact match)
find_groups Find groups by cn/name/sAMAccountName/displayName (* wildcards)
get_group Get a single group by sAMAccountName or cn (exact match)
find_computers Find computers by name (cn), dNSHostName or operatingSystem
get_computer Get a single computer by sAMAccountName, cn or dNSHostName
find_ous Find organizational units by name (* wildcards)
get_ou Get a single OU by its ou name or full DN (exact match)
get_ou_contents List objects under an OU (optionally filtered by object_class)
get_by_dn Fetch any entry directly by its DN (resolve manager / managedBy)

The find_* tools accept an optional base (a DN, e.g. an OU) to restrict the search to a subtree instead of the whole domain.

Memberships and account status

Tool Description
group_members List members of a group (direct, or recursive with nested)
user_groups List the groups a user belongs to (nested/recursive by default)
is_member Check whether a user is a (nested) member of a group
is_disabled Check whether an account is disabled
is_locked Check whether an account is locked

Audit

Tool Description
find_inactive_users Users whose last logon is older than days (default 90), optionally including those who never logged on
find_stale_computers Computers whose last logon is older than days (default 90)
get_domain_info The domain object: security-relevant settings and metadata
get_password_policy The default domain password policy (maxPwdAge, minPwdLength, …)
get_password_policy_violations Enabled users whose password violates the domain policy
get_privileged_groups Well-known privileged groups (Domain Admins, …) with member counts

Diagnostics

Tool Description
test_connection Test AD connectivity and bind (returns ok / target / auth / error)
health Server health check (server name, msad version, connectivity)

Authentication and connection

The server has no connection settings of its own: it reuses the msad configuration file, ~/.msad.toml by default (create it with msad init). Each tool call opens a short-lived connection through msad.connect().

A minimal ~/.msad.toml:

[defaults]
domain = "group"

[domains.group]
host = "dc.example.com"
base = "dc=group,dc=example,dc=com"
port = 636
use_ssl = true
# user = "svc_account"   # optional
# password = "..."       # optional

You can declare several [domains.*] blocks and pick one per call with the tool’s domain argument, or globally via MSAD_DOMAIN.

The authentication mode is chosen automatically from the domain block:

  • Kerberos (SASL) when user/password are not both set (the default) — obtain a ticket first with kinit.
  • User / password when both user and password are set — a simple LDAP bind. Restrict the file permissions (chmod 600 ~/.msad.toml) since the password is stored in clear text.

Use LDAPS (port = 636, use_ssl = true) whenever possible.

Running

Using uvx:

uvx --from git+https://github.com/matteoredaelli/mcpAD mcpAD

The transport is configurable (stdio, streamable-http, sse):

make start-stdio                               # stdio (for local MCP clients)
make start-http                                # streamable-http on 127.0.0.1:8000
make start-http HOST=0.0.0.0 PORT=9000         # bind elsewhere

Registering the server with an MCP client

Local (stdio) — the client launches the server

{
  "mcpServers": {
    "mcpAD": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/mcpAD", "mcpad"],
      "env": { "MSAD_DOMAIN": "group" }
    }
  }
}

The spawned process inherits your environment, so a Kerberos ticket obtained with kinit in the same session is used automatically. For an unattended client, point it at a keytab via KRB5_CLIENT_KTNAME.

Remote (streamable-http) — the server runs as a service

Start the service on a host that has AD/Kerberos access:

make start-http HOST=0.0.0.0 PORT=9000

Then point the client at its URL:

{
  "mcpServers": {
    "mcpAD": {
      "transport": "http",
      "url": "http://mcp-host.example.com:9000/mcp"
    }
  }
}

The server itself performs no client authentication: if you expose it beyond localhost, put it behind a reverse proxy / network controls and treat the AD credentials on that host accordingly. Kerberos runs where the server runs — that host needs a valid ticket or keytab, not the client.

Why it is useful

With mcpAD an AI agent can answer questions like “which accounts have been inactive for more than 90 days?”, “who are the members of the Domain Admins group?” or “show me the password policy violations” — directly, in natural language, and safely, because every tool is read-only.

The code is available on GitHub.


Enter your instance's address


More posts like this