{
  "markdown": "# Inforcer MCP Server\n\n[![Build Status](https://github.com/WYRE-AI/inforcer-mcp/actions/workflows/release.yml/badge.svg)](https://github.com/WYRE-AI/inforcer-mcp/actions/workflows/release.yml)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)\n\nA [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that gives AI assistants structured, **mostly read-only** access to [Inforcer](https://www.inforcer.com) Microsoft 365 baseline-governance data — tenants, baselines, alignment/drift, policies, secure scores, identity, audit logs, and report generation — plus two write actions to trigger an assessment run or queue a report.\n\n> **Note:** This project is maintained by [Wyre Technology](https://github.com/WYRE-AI).\n\n## ⚠ Community-sourced API\n\nInforcer does not (at time of writing) publish an official REST API specification. This server wraps the [`@wyre-technology/node-inforcer`](https://github.com/WYRE-AI/node-inforcer) SDK, whose API surface is **community-sourced** from [royklo/InforcerCommunity](https://github.com/royklo/InforcerCommunity). Endpoints, field shapes, and behavior may change without notice. Treat results accordingly and verify anything load-bearing against the Inforcer portal.\n\n## Read-only scope\n\nEvery tool in this server is **read-only** EXCEPT two:\n\n- `inforcer_assessments_run` — triggers an assessment run for a tenant.\n- `inforcer_reports_run` — queues one or more report runs across one or more tenants.\n\nBoth are **HIGH-IMPACT** (not destructive): they kick off real work in Inforcer and are visible to operators. Both are annotated accordingly and ask for confirmation before running. **Confirm with the user before invoking.**\n\nThere are **no** create/update/delete tools for policies, tenants, or baselines — those operations are not exposed by the community API and are intentionally absent here.\n\n## Quick Start\n\n**Claude Code (CLI):**\n\n```bash\nclaude mcp add inforcer-mcp \\\n  -e INFORCER_REGION=us \\\n  -e INFORCER_API_KEY=your-api-key \\\n  -- npx -y github:WYRE-AI/inforcer-mcp\n```\n\nSee [Installation](#installation) for Docker and from-source methods.\n\n## Features\n\n- **🔌 MCP Protocol Compliance**: Full support for MCP tools and prompts\n- **🛡️ Governance Coverage (read-only)**: Tenants, baselines, alignment/drift, policies, Microsoft Secure Score, Entra ID identity, and the audit log\n- **🔍 Decision-Tree Navigation**: Start with `inforcer_navigate` to explore domains, then call domain-specific tools\n- **🧭 Flexible Tenant Resolution**: Most tools accept a `tenant` as a numeric Client Tenant ID, a tenant DNS name, an Azure AD GUID, or a friendly name — resolved automatically\n- **🔒 Secure Authentication**: `Inf-Api-Key` header auth, region-scoped\n- **🌐 Dual Transport**: stdio (local) and HTTP Streamable (gateway/Docker)\n- **🐳 Docker Ready**: Containerized deployment with HTTP transport and health checks\n- **📊 Structured Logging**: Configurable levels, credentials never logged\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Configuration](#configuration)\n- [Tenant identifiers](#tenant-identifiers)\n- [Domains and tools](#domains-and-tools)\n- [Gateway connection](#gateway-connection)\n- [Docker Deployment](#docker-deployment)\n- [Development](#development)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\n### Option 1: Claude Code (CLI)\n\n```bash\nclaude mcp add inforcer-mcp \\\n  -e INFORCER_REGION=us \\\n  -e INFORCER_API_KEY=your-api-key \\\n  -- npx -y github:WYRE-AI/inforcer-mcp\n```\n\n### Option 2: Docker\n\n```bash\ndocker compose up\n```\n\nOr pull the pre-built image:\n\n```bash\ndocker run -d \\\n  -e INFORCER_REGION=us \\\n  -e INFORCER_API_KEY=your-key \\\n  -p 8080:8080 \\\n  ghcr.io/wyre-ai/inforcer-mcp:latest\n```\n\n### Option 3: From Source\n\n```bash\ngit clone https://github.com/WYRE-AI/inforcer-mcp.git\ncd inforcer-mcp\nexport NODE_AUTH_TOKEN=$(gh auth token)   # to install @wyre-ai/* from GitHub Packages\nnpm ci\nnpm run build\n```\n\n## Configuration\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `INFORCER_REGION` | **Required.** Inforcer API region — one of `anz`, `eu`, `uk`, `us`. There is no default; the server errors clearly if it is missing. | — |\n| `INFORCER_API_KEY` | **Required.** Inforcer API key, sent as the `Inf-Api-Key` header. | — |\n| `MCP_TRANSPORT` | Transport mode (`stdio` or `http`) | `stdio` |\n| `MCP_HTTP_PORT` | HTTP server port | `8080` |\n| `AUTH_MODE` | Auth mode (`env` or `gateway`) | `env` |\n| `LOG_LEVEL` | Log level (`debug`, `info`, `warn`, `error`) | `info` |\n\nBoth `INFORCER_REGION` and `INFORCER_API_KEY` are required for any API call. Tool discovery (`tools/list`) works without them; the first real call will error if either is missing.\n\n## Tenant identifiers\n\nInforcer's tenant-scoped routes use an integer **Client Tenant ID** — which is **NOT** the same as the Azure AD tenant GUID (`msTenantId`). To make tools easy to use, the `tenant` argument accepts any of:\n\n- a numeric **Client Tenant ID** (e.g. `42`),\n- a **tenant DNS name** (e.g. `contoso.onmicrosoft.com`),\n- an **Azure AD tenant GUID** (`msTenantId`), or\n- a **friendly name** (e.g. `Contoso`).\n\nNames/DNS/GUIDs are resolved to the numeric Client Tenant ID via the SDK's `resolveTenantId` before each tenant-scoped call. If a name matches more than one tenant, the call fails with a clear \"ambiguous\" error — pass the numeric Client Tenant ID instead. Use `inforcer_tenants_resolve` to see exactly which Client Tenant ID an input maps to.\n\n## Domains and tools\n\nThe server uses decision-tree navigation. Start with `inforcer_navigate` to pick a domain, or call any tool directly. All tools are read-only except `inforcer_assessments_run` and `inforcer_reports_run`.\n\n| Domain | Tools | Read-only |\n|--------|-------|-----------|\n| **navigation** | `inforcer_navigate`, `inforcer_status` (live `baselines.list()` connectivity check) | ✅ |\n| **tenants** | `inforcer_tenants_list`, `inforcer_tenants_get`, `inforcer_tenants_resolve` | ✅ |\n| **baselines** | `inforcer_baselines_list` | ✅ |\n| **alignment** | `inforcer_alignment_scores`, `inforcer_alignment_details` (per-tenant drift) | ✅ |\n| **policies** | `inforcer_policies_list` (by tenant) | ✅ |\n| **secure-scores** | `inforcer_secure_scores_get` (by tenant) | ✅ |\n| **identity** | `inforcer_users_list`, `inforcer_users_get`, `inforcer_groups_list`, `inforcer_groups_get`, `inforcer_roles_list` | ✅ |\n| **audit** | `inforcer_audit_event_types`, `inforcer_audit_search` | ✅ |\n| **assessments** | `inforcer_assessments_list` (✅), `inforcer_assessments_run` (⚠ HIGH-IMPACT, **not** read-only) | mixed |\n| **reports** | `inforcer_reports_types_list`, `inforcer_reports_runs_list`, `inforcer_reports_run_status`, `inforcer_reports_download_output` (✅), `inforcer_reports_run` (⚠ HIGH-IMPACT, **not** read-only) | mixed |\n\n`inforcer_reports_run` queues asynchronously — poll the run with `inforcer_reports_run_status` until `isTerminal: true`, then fetch each output with `inforcer_reports_download_output` (returns base64-encoded file content).\n\n## Gateway connection\n\nWhen hosted behind the WYRE MCP Gateway, set `AUTH_MODE=gateway` and `MCP_TRANSPORT=http`. In this mode the server is stateless (a fresh MCP server + transport per request) and reads credentials from per-request HTTP headers injected by the gateway:\n\n| Header | Maps to |\n|--------|---------|\n| `x-inforcer-region` | `INFORCER_REGION` |\n| `x-inforcer-api-key` | `INFORCER_API_KEY` |\n\nWhen both headers are present the server updates the environment and invalidates its cached client so the next call uses the freshly-injected credentials. `tools/list` still works without credentials, so discovery is never blocked. The container image defaults to `MCP_TRANSPORT=http`; `/health` reports `ok` when credentials are configured and `degraded` otherwise.\n\n## Docker Deployment\n\nSee [docker-compose.yml](docker-compose.yml) for full configuration. Copy `.env.example` to `.env` and fill in your credentials:\n\n```bash\ncp .env.example .env\n# Edit .env with INFORCER_REGION and INFORCER_API_KEY\ndocker compose up -d\n```\n\n## Development\n\n```bash\nexport NODE_AUTH_TOKEN=$(gh auth token)\nnpm ci\nnpm run build       # Build the project\nnpm run dev         # Watch mode\nnpm run test        # Run tests\nnpm run lint        # Type-check\nnpm run clean       # Remove dist/\n```\n\n## Testing\n\n```bash\nnpm test            # Run test suite\nnpm run test:watch  # Watch mode\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nApache 2.0 — Copyright WYRE Technology\n",
  "bytes": 8726,
  "sha": "b1578c68ce804c8b613691181ea4e0d379a5628bf9b605c35345da88d6ef4458",
  "repo_slug": "wyre-ai/inforcer-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_wyre_ai_inforcer_mcp_8d94817c/readme"
}