mcpAD
A FastMCP server that exposes the
msad Active Directory / LDAP library as MCP tools.
Built with Python 3.14 and uv. It reuses the typed, public msad API
(search users/groups, memberships, account status). All tools are read-only.
Tools
| Tool | Description |
|---|---|
find_users |
Find users by name/surname/mail/sam/department (ANDed, * wildcards) |
get_user |
Get a single user (exact match) |
find_groups |
Find groups (* wildcards) |
get_group |
Get a single group (exact match) |
find_computers |
Find computers by name/dns/os (* wildcards) |
get_computer |
Get a single computer (sAMAccountName/cn/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) |
find_inactive_users |
Find users whose last logon is older than days (default 90) |
find_stale_computers |
Find computers whose last logon is older than days (default 90) |
get_domain_info |
Domain object: security-relevant settings and metadata (audit) |
get_password_policy |
Default domain password policy (audit) |
get_password_policy_violations |
Users whose password violates the policy (audit) |
get_privileged_groups |
Well-known privileged groups with member counts (audit) |
get_by_dn |
Fetch any entry directly by its DN (resolve manager / managedBy) |
group_members |
List group members (direct or nested) |
user_groups |
List a user's groups (nested by default) |
is_member |
Is a user a (nested) member of a group? |
is_disabled |
Is an account disabled? |
is_locked |
Is an account locked? |
test_connection |
Test AD connectivity and bind (returns ok/target/auth/error) |
health |
Server health check (server name, msad version, connectivity) |
The find_users, find_groups, find_computers and find_ous tools accept an
optional base (a DN, e.g. an OU) to restrict the search to that subtree
instead of the whole domain.
Returned attributes
By default get_user / find_users return a useful attribute set: identity
fields plus manager — the distinguished name (DN) of the user's manager,
e.g. CN=Anna Bianchi,OU=Staff,DC=group,DC=example,DC=com — as well as
memberOf (direct group DNs), userAccountControl, accountExpires,
lastLogonTimestamp and whenCreated. Group lookups include managedBy (the
DN of the group's owner), member, groupType and whenCreated.
To expand a manager (or any DN-valued field) into a full record, call
get_by_dn with that DN. This is a direct, efficient lookup (the DN is used as
the search base), so an agent can do: get_user("mrossi") → read manager →
get_by_dn("<that DN>").
Authentication & 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().
Domain parameters (~/.msad.toml)
[defaults]
domain = "group" # used when a tool call omits `domain`
[domains.group]
host = "dc.example.com" # hostname only (no scheme, no :port)
base = "dc=group,dc=example,dc=com"
port = 636 # default: 389
use_ssl = true # default: false (true = LDAPS)
# user = "svc_account" # optional (see auth below)
# password = "..." # optional
# A second domain (here using user/password auth):
[domains.lab]
host = "dc.lab.example.com"
base = "dc=lab,dc=example,dc=com"
port = 636
use_ssl = true
user = "svc_reader"
password = "s3cr3t"
You can declare several [domains.<name>] blocks and pick one per call with the
tool's domain argument, or globally via MSAD_DOMAIN. For example, an agent
can call find_users(surname="Rossi", domain="lab") to target the lab domain
while [defaults].domain stays group.
Overrides via environment
MSAD_DOMAIN— default domain when a tool call omitsdomainMSAD_CONFIG_FILE— path to an alternative TOML config
Authentication modes
The mode is chosen automatically from the domain block:
-
Kerberos (SASL) — when
user/passwordare not both set (the default). Obtain a ticket first:kinit # or: kinit <user>@REALM
The server relies on the system Kerberos ticket cache (or a keytab via
KRB5_CLIENT_KTNAME). If the ticket is missing or expired, tools fail with a cleanMsadConnectionErrormessage. When running as a background/remote service, make sure that process can see a valid ticket or keytab. -
User / password — when both
userandpasswordare set. Simple LDAP bind. The password is stored in clear text in the TOML, so restrict the file permissions (chmod 600 ~/.msad.toml).Note: setting only one of
user/passwordsilently falls back to Kerberos. Set both, or neither.
Use LDAPS (port = 636, use_ssl = true) whenever possible.
Running
Using uvx:
uvx --from git+https://github.com/matteoredaelli/mcpAD mcpAD
The Makefile wraps the common cases. Transport, host and port are
configurable:
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
make start-sse # sse transport
make start TRANSPORT=streamable-http PORT=9000 # generic form
Equivalent raw commands (the server reads MCP_TRANSPORT / MCP_HOST /
MCP_PORT from the environment):
uv run mcpad # stdio (default)
MCP_TRANSPORT=streamable-http MCP_PORT=9000 uv run mcpad
Registering the server with an MCP client / agent
MCP clients (Claude Desktop, IDE agents, custom agents, ...) usually accept a
JSON config with a mcpServers map. Two deployment styles:
Local (stdio) — the client launches the server
The client spawns the process and talks to it over stdio. This is the simplest setup and keeps everything on your machine (including your Kerberos ticket).
{
"mcpServers": {
"mcpAD": {
"command": "uv",
"args": [
"run",
"--directory", "/path/to/mcpAD",
"mcpad"
],
"env": {
"MSAD_DOMAIN": "group"
}
}
}
}
Notes:
--directorymakesuvuse this project's environment regardless of the client's working directory.- Kerberos: the spawned process inherits your environment, so a ticket obtained
with
kinitin the same user session is used automatically. For an unattended client, point it at a keytab (e.g. add"KRB5_CLIENT_KTNAME": "/path/to.keytab"toenv).
Remote (streamable-http) — the server runs as a service
Start the server as a long-running HTTP service, then point the client at its URL. Useful when the server runs on a host that has AD/Kerberos access while the client runs elsewhere.
Start the service:
make start-http HOST=0.0.0.0 PORT=9000
# serves the MCP endpoint at http://<host>:9000/mcp
Client config referencing the URL:
{
"mcpServers": {
"mcpAD": {
"transport": "http",
"url": "http://mcp-host.example.com:9000/mcp"
}
}
}
Notes:
- The default streamable-http path is
/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 a keytab, not the client.
Development
uv sync
uv run python -c "import asyncio; from mcpad import mcp; print(asyncio.run(mcp.list_tools()))"
The msad dependency can be installed
from its Git repository, or as an editable local path during development so that
library changes are picked up immediately.
Metadata
Release files for mcpad 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcpad-0.1.0.tar.gz | 9.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcpad-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.8 kB
Release files / mcpad-0.1.0.tar.gz
| Download URL | mcpad-0.1.0.tar.gz |
|---|---|
| Size | 9.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74da492a5ad57b3003482221220bdb8e04d071cb58151126d9a5c30ff7642e4a
|
|
BLAKE2b-256 checksum How to use checksums |
0f728d037ef4be50a872f84297e9cfb223969d637c85f523740f6c3b2576a0e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mcpad-0.1.0-py3-none-any.whl
| Download URL | mcpad-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6d198401b62b0d5fcbb5270adbd75c35bf07a3310e8520b4246a4c29632c3686
|
|
BLAKE2b-256 checksum How to use checksums |
7941a871e84ce78d15eb4845afd5010896d02201063ea9b62f4a89072f16bd2b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|