Skip to main content
Glama

About

Active Directory MCP is an open-source Model Context Protocol server that lets AI assistants (Claude, Gemini CLI, ChatGPT via API, etc.) safely manage Active Directory environments.

Key features

  • 10 tools covering users, groups, computers, OUs, security and the directory catalogue, plus 15 MSP prompt playbooks served through the MCP prompts protocol. One read-only search_* and one write manage_* per kind of object; the write tool takes an action. Common requests are one call each: an account's details already carry its groups, primary group and OU; onboarding copies groups and OU from a model account (copy_from_user); offboarding disables, moves (move_to_ou) and optionally strips groups in one call; membership calls accept lists.

  • Two transports, one catalogue: stdio (server.py) is a thin adapter over the same registry, sanitizer, name resolution and deadlines that serve Streamable HTTP via FastAPI (server_fastapi.py). Neither transport can drift from the other. An earlier FastMCP-based HTTP transport (server_http.py) has been removed.

  • Two deployment modes: single (default) binds one process to one AD via AD_MCP_CONFIG — run one process per tenant to serve several; multi binds one process to N ADs via AD_MCP_SERVERS, adding a required/optional ad_server parameter to every directory-bound tool. See Multi-tenant architecture.

  • Write-operation guard rails: every mutating tool requires either a per-tenant client confirmation string or an automation Bearer token before touching AD.

  • Audit log on every operation: each call records operation name, target, mode (CONFIRMED / AUTOMATION / NO_CONFIRMATION_REQUIRED), and outcome.

Naming convention

All MCP tool names use the ad_* prefix with a descriptive suffix — e.g. ad_search_directory_users, ad_manage_directory_users, ad_search_security_reports. This avoids collisions when this MCP runs alongside other servers (GLPI, Hudu, etc.) connected to the same AI client.


Related MCP server: Shell MCP

Multi-tenant architecture

There are two ways to serve more than one AD with this codebase. Both read the same active_directory / organizational_units / security / client schema (see Configuration); pick one per deployment, not both.

Mode 1 — one process per tenant (AD_MCP_MODE=single, the default)

.base-code/                    <- this repository (shared source of truth)
  src/active_directory_mcp/
  ad-config/
    ad-config.example.json     <- template only (real configs are .gitignored)

<deployment>/                  <- one directory per tenant, OUTSIDE this repo
  tenant-a/
    ad-config/ad-config.json   <- real credentials (NEVER committed)
    start.sh                   <- exports AD_MCP_CONFIG and launches the server
  tenant-b/
    ad-config/ad-config.json
    start.sh

Each start.sh exports AD_MCP_CONFIG pointing at that tenant's config and runs python -m active_directory_mcp.server_fastapi on a dedicated port. Update the shared .base-code/ once, restart every tenant process &mdash; same code, isolated state. Tools take no ad_server parameter in this mode; this is the original, unchanged behavior.

Mode 2 &mdash; one process serving several ADs (AD_MCP_MODE=multi)

A single server_fastapi.py process can instead serve N directories, selected via AD_MCP_SERVERS pointing at an ad-servers.json (schema: ad-config/ad-servers.example.json &mdash; each entry is an ad-config.json block plus label/aliases/enabled). Every directory-bound tool then gains an ad_server parameter:

  • Write tools: ad_server is required and must name exactly one directory &mdash; there is no "all".

  • Read tools: ad_server is optional; omitted (or all/todos/*) runs the query against every configured directory and the response reports where each result was found.

  • Catalog tool: ad_list_ad_servers, ad_check_ad_server_configured, ad_list_configured_clients, ad_check_client_configuration and ad_get_client_tenant_info are replaced by a single ad_search_directory_servers (same tool in both modes), whose optional server_name resolves a name, alias, domain or client name to the exact ad_server. Calling it first is not required: ad_server itself accepts the client's name.

ad_server matching ignores case, accents and surrounding whitespace; a name that matches more than one directory is refused with the list of candidates rather than guessed. Write confirmation (client_confirmation, below) is validated against the same directory named by ad_server.

export AD_MCP_MODE=multi
export AD_MCP_SERVERS=/etc/ad-mcp/ad-servers.json
python -m active_directory_mcp.server_fastapi --host 0.0.0.0 --port 8820

The stdio transport (server.py) only supports single mode.


Quick Start

Prerequisites

  • Python 3.11+

  • LDAP/LDAPS reachable from the host

  • An AD service account with the permissions required by the operations you plan to expose

1. Install

git clone https://github.com/DevSkillsIT/Skills-MCP-Active-Directory.git
cd Skills-MCP-Active-Directory

python -m venv .venv
source .venv/bin/activate          # Linux/macOS
# .venv\Scripts\activate           # Windows

pip install -e .                   # installs from pyproject.toml

2. Configure

mkdir -p /etc/ad-mcp
cp ad-config/ad-config.example.json /etc/ad-mcp/ad-config.json
$EDITOR /etc/ad-mcp/ad-config.json   # set server, bind_dn, password, base_dn, OUs
chmod 600 /etc/ad-mcp/ad-config.json

The example file is the only template kept in git. Any real ad-config.json is blocked by .gitignore (ad-config/*.json + !ad-config/*.example.json).

3. Run

export AD_MCP_CONFIG=/etc/ad-mcp/ad-config.json

# stdio transport (for direct Claude Desktop / mcp-cli use):
python -m active_directory_mcp.server

# HTTP transport (for Claude Code, Gemini CLI, n8n, etc.):
python -m active_directory_mcp.server_fastapi --host 0.0.0.0 --port 8820
# MCP endpoint: http://localhost:8820/mcp   Health (no auth): http://localhost:8820/health

Set AD_MCP_API_TOKEN in the environment to require a Bearer token on the HTTP transport; without it the server accepts unauthenticated requests (development only &mdash; always set it in production). See HTTP_MCP_GUIDE.md for the full transport reference, including the multi mode.

4. Connect from Claude Code

claude mcp add --transport http ad http://localhost:8820/mcp \
  --headers "Authorization: Bearer YOUR_AUTOMATION_TOKEN"

5. Connect from Gemini CLI

~/.gemini/settings.json:

{
  "mcpServers": {
    "ad": {
      "httpUrl": "http://localhost:8820/mcp",
      "headers": { "Authorization": "Bearer YOUR_AUTOMATION_TOKEN" },
      "timeout": 30000
    }
  }
}

Tools

Ten tools: one read-only ad_search_* and one write ad_manage_* per kind of object, plus the catalogue. This is the house pattern (search = discovery, manage = action through an action parameter) and it replaced the 45 verb-per- tool names each mode listed before: the catalogue a client has to carry on every call went from ~60k to ~23k characters, and a model no longer has to pick between seven near-identical user tools.

Every tool declares MCP annotations: ad_search_* is readOnlyHint: true, ad_manage_* is destructiveHint: true (every one of them includes delete). In multi mode each tool bound to a directory also takes ad_server (required on writes, optional on reads — omitted means every directory).

Tool

Type

What it does

ad_search_directory_servers

read

Configured ADs; server_name resolves a client name; test_connection runs a live LDAP test (one or all)

ad_search_directory_users

read

username returns the full account sheet (groups, primary group, OU, flags, manager); otherwise lists by free text, LDAP filter or OU; inactive_days lists accounts without logon

ad_manage_directory_users

write

action: create (onboarding; copy_from_user copies groups and OU), update, move, enable, disable (offboarding with move_to_ou and remove_from_groups), reset_password, delete

ad_search_directory_groups

read

group_name returns the group with its members (recursive expands nested groups); otherwise lists

ad_manage_directory_groups

write

action: create, update, move, add_members, remove_members (several groups and members per call), delete

ad_search_directory_computers

read

computer_name returns the machine; otherwise lists; inactive_days lists stale machines

ad_manage_directory_computers

write

action: create, update, move, enable, disable, reset_trust, delete (a domain controller is refused)

ad_search_organizational_units

read

ou_dn returns the OU with its GPOs and its contents (object_types filters); otherwise lists the hierarchy

ad_manage_organizational_units

write

action: create, update, move, delete (force deletes the contents too)

ad_search_security_reports

read

report: domain_policy, privileged_groups, admin_accounts, password_violations, user_permissions

Every write answer is read back from the directory (DN, account state, groups actually joined), so a follow-up query to confirm it is unnecessary.

Old tool names

The 45 names this server listed before in each mode (47 distinct names across single and multi mode) are not gone: a client connected directly (or a saved prompt) can still call them. 45 of them are routed to the new tool with the right action plus a tool_unificada note; ad_test_ldap_connection_status and ad_move_organizational_unit_parent are still registered under their own names, just no longer listed. A gateway that only routes listed tools (mcphub) answers "tool not available" instead, and its search then finds the new tool. The mapping lives in ALIASES_DE_TOOLS (server_fastapi.py).

MSP prompts (15)

The 15 professional MSP playbooks (7 manager + 8 analyst) are not tools &mdash; they are served through the standard MCP prompts protocol, prompts/list and prompts/get, over both transports. See PROMPTS.md for the full catalog and usage.


Configuration

The runtime configuration file path is provided via the AD_MCP_CONFIG environment variable. Schema in ad-config/ad-config.example.json.

Key fields

Field

Required

Description

active_directory.server

yes

Primary LDAP URL, e.g. ldaps://dc.example.com:636

active_directory.server_pool

no

Additional LDAP URLs for failover

active_directory.bind_dn

yes

Full DN of the service account

active_directory.password

yes

Service account password (keep file at chmod 600)

active_directory.base_dn

yes

Base DN, e.g. DC=example,DC=com

organizational_units.*

yes

Default OUs for users/groups/computers/service accounts

security.enable_tls

no

Force StartTLS / LDAPS

security.validate_certificate

no

Verify server certificate against ca_cert_file

security.require_secure_connection

no

Refuse to bind over plaintext

automation.token

no

Bearer token for unattended write operations

client.slug

no

Tenant identifier reported by ad_search_directory_servers

Service account permissions

Grant the bind account the minimum delegated rights required by the operations you intend to expose:

  • Read-only deployments: "Read all properties" + "List contents" on the domain root is enough.

  • User/group write: delegate "Create/Delete objects" + "Write all properties" on the target OUs.

  • Password reset: delegate the "Reset password" extended right on the target OUs.

  • Computer join/leave: delegate "Create/Delete computer objects" on the computers OU.

Always use a dedicated service account, LDAPS in production, and rotate the password regularly.


Security

Write protection model

Every write &mdash; each action of the ad_manage_* tools, and the old write names routed to them &mdash; calls check_write_permission() before reaching LDAP. It accepts the write if one of:

  1. automation_token matches automation.token in the config &mdash; intended for CI / scheduled jobs.

  2. client_confirmation matches the tenant slug &mdash; the AI assistant must identify the tenant first (ad_search_directory_servers, in either mode), read the slug back to the user, and pass that exact string.

  3. The tenant has require_confirmation_for_writes: false (explicit opt-out, not recommended).

If none of the above is satisfied, the call short-circuits with a permitted: false message and the LDAP write is never attempted.

Audit logging

All operations write a structured log line including: timestamp, tool name, target, confirmation mode (AUTOMATION / CONFIRMED / WRONG_CONFIRMATION / NO_CONFIRMATION_REQUIRED), and success/failure. Logs go wherever logging.file points.

Secrets hygiene

  • Real ad-config.json files are git-ignored. Only *.example.json is tracked.

  • Never paste a config containing a real password or automation.token into a chat that's logged or transcribed by a third party.

  • Rotate automation.token whenever you regenerate it; treat it as a privileged credential.


Testing

# Unit + integration tests
pytest tests/ -v

# Coverage
pytest --cov=src/active_directory_mcp --cov-report=term-missing

# Lint
ruff check .

A bundled docker-compose-ad.yml spins up a Samba AD container at 192.168.1.100 plus an MCP container so the integration tests can run against a real LDAP backend without touching production.


Troubleshooting

Symptom

Likely cause

Fix

LDAP bind failed

bad bind_dn / password

Verify against ldapsearch -H <server> -D '<bind_dn>' -W

Insufficient permissions

service account lacks delegated rights

Re-delegate on the target OU

Certificate verification failed

self-signed cert without trust

Set ca_cert_file or validate_certificate: false (test only)

permitted: false on every write

Missing confirmation/token

Identify the tenant first (ad_search_directory_servers), or pass automation_token

Health degraded

socket open but LDAP search failed

Check service-account lockout / replication / network ACLs


Contributing

  1. Fork the repo.

  2. Create a feature branch: git checkout -b feat/your-feature.

  3. Run tests: pytest.

  4. Open a PR with a clear description and a link to the relevant issue.

Commits follow Conventional Commits.


License

MIT &mdash; see LICENSE.

Acknowledgments

Support

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A comprehensive MCP server for managing Active Directory environments through LDAP, enabling user, group, computer, and OU management, as well as security auditing and policy compliance checks.
    51
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A production-ready MCP server that enables AI assistants to execute shell commands, manage files, monitor system resources, and automate complex workflows with advanced features like stock tracking and web automation.
    7
    7 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server that enables AI-powered assessment of Active Directory on-premises environments by exposing AD data as queryable tools for LLMs like Claude.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that enables AI assistants to manage, monitor, and diagnose Windows systems through 42 tools across 8 modules, including services, event viewer, task scheduler, processes, network, diagnostics, observability, and safety features.
    8 npm
    9
    MIT