nexus-mcp/archive/Identity/implementation-guide.md
nathan 479df6bd8a chore: archive legacy Identity, Workday, and Intune folders
- Move Identity/, Workday/, Intune/ to archive/ (superseded by nexus-mcp shards)
- Move 'Local Setup.md' to archive/ (superseded by nexus-mcp/Local-Setup.md)
- Add archive/README.md explaining migration and preserved content
- Clean repository structure: only nexus-mcp, documentation, and .github remain active

All legacy functionality migrated to nexus-mcp sharded architecture.
Archived folders preserved for reference and historical context.

Refs: SESSION_SNAPSHOT_2026-04-13.md
2026-04-13 09:38:42 -04:00

4.7 KiB

Identity MCP implementation kickoff (Phase 1)

Purpose

This document starts implementation of an Identity MCP server with a read-only baseline.

What is implemented

  • Python MCP server scaffold using FastMCP
  • Read-only tool exposed: get_user
  • Read-only tool exposed: get_user_groups
  • Read-only tool exposed: get_group_members
  • Read-only tool exposed: find_stale_users
  • Read-only tool exposed: get_computer
  • In-memory backend for local contract testing
  • Active Directory backend using PowerShell subprocess wrappers
  • Environment-based backend selection (memory vs AD)
  • STDERR-only logging for STDIO transport safety
  • Basic audit log entries for tool calls
  • Unit tests and integration smoke tests

Files

  • identity_mcp_server.py: FastMCP server, tool definitions, logging, backend selection, and run entrypoint
  • identity_backend.py: backend interface and in-memory implementation
  • ad_adapter.py: Active Directory backend using PowerShell Get-AD* cmdlets
  • tests/test_ad_adapter.py: unit tests for AD adapter output parsing and error handling
  • tests/test_integration.py: integration smoke tests against non-production AD
  • pyproject.toml: project metadata, dependency pin for MCP SDK, and CLI entrypoint
  • .gitignore: excludes Python bytecode, test cache, and local virtual environment artifacts

How to run

Using in-memory backend (default, safe mode)

uv run identity_mcp_server.py

Using Active Directory backend

Set environment variables before running:

# Test environment with explicit credentials
export IDENTITY_BACKEND=ad
export AD_USERNAME=your_test_username
export AD_PASSWORD=your_test_password
uv run identity_mcp_server.py
# Production environment with service account context
export IDENTITY_BACKEND=ad
# Service account runs process, no explicit credentials needed
uv run identity_mcp_server.py

Running tests

# Install test dependencies
uv pip install -e ".[test]"

# Run unit tests only (no AD connection required)
pytest tests/test_ad_adapter.py -v

# Run integration smoke tests (requires AD credentials)
export AD_TEST_USERNAME=your_test_username
export AD_TEST_PASSWORD=your_test_password
export AD_TEST_USER=known_test_user
export AD_TEST_GROUP=known_test_group
export AD_TEST_COMPUTER=known_test_computer
pytest tests/test_integration.py -v

# Run all tests
pytest tests/ -v

Active Directory adapter details

Query mapping

  • get_user: Uses Get-ADUser with samAccountName filter, retrieves Enabled, DistinguishedName, Description, lastLogonTimestamp
  • get_user_groups: Uses Get-ADUser with MemberOf property, resolves group names
  • get_group_members: Uses Get-ADGroup + Get-ADGroupMember, filters user objects only
  • find_stale_users: Uses Get-ADUser with lastLogonTimestamp cutoff (FileTime comparison)
  • get_computer: Uses Get-ADComputer, returns OU and null assigned_username (Phase 1)

Authentication model

  • Test environments: explicit username/password via environment variables
  • Production: process runs as dedicated service account, no credentials in code
  • Service account requires Read Directory Data permission only (no write permissions)

Error handling

All backend failures (timeout, auth denied, permission denied) return:

  • None for get_user and get_computer (tool wrapper converts to "User not found" or "Computer not found")
  • Empty list [] for get_user_groups, get_group_members, find_stale_users

Timeouts

Default: 30 seconds per query. Override with AD_TIMEOUT environment variable.

Known gaps (deferred to later phases)

  • Ticket-ID enforcement for write actions (Phase 3)
  • PII redaction in audit logs (toggle ready, not enabled by default)
  • Entra ID/Azure AD integration (separate adapter)
  • Production service account provisioning (infrastructure task)
  • Host/client configuration details depend on your selected MCP client

Verification checklist

Before deploying to production:

  • Unit tests pass: pytest tests/test_ad_adapter.py -v
  • Integration smoke tests pass against non-production AD: pytest tests/test_integration.py -v
  • Service account provisioned with Read Directory Data only
  • MCP tool responses match expected contract shapes
  • Error messages are friendly strings (not exceptions or technical errors)
  • Stale-user logic confirmed using lastLogonTimestamp
  • Computer assigned_username returns null in Phase 1
  • Backend selection tested: memory mode and AD mode both run successfully

Next implementation slice

  1. Add structured PII redaction toggle for audit logs.
  2. Add phase gate config that blocks write tools entirely until explicitly enabled (Phase 3 prep).
  3. Implement Entra ID/Azure AD adapter (separate backend).
  4. Add canary/rollback mechanism for backend switching.