
saulpatinojr/proj-cloud_architect_sidekick_mcp
Deployment & DevOpsAzure-native MCP server for Architecture Intelligence. Manage ADRs, detect architectural drift, analyze technology stacks, track decision history, identify contradictions, perform safety reviews, and...
Overview
An that lets Claude (Claude Code, Claude.ai, Claude Desktop, or any MCP client) work with as first-class, verifiable artifacts: - decisions in MADR style with structured, testable claims; search, version, supersede and archive them. - (manifests, IaC, config, code) through a fast direct-to-Blob upload with quarantine, hashing and content-safety scanning. - deterministically from .csproj, package.json, requirements, Dockerfiles, Bicep, Terraform, Kubernetes and CI files. - between accepted decisions and what the code and infrastructure actually do. - between decisions, with scope-aware false-positive guards. - of proposed decisions (security, availability, data loss, privacy, compliance, lock-in, cost, EOL, operability, rollback, blast radius). - tool calls, decisions and human feedback per tenant and workspace with explainable retrieval. And one guarantee above all: Analyzers write only to system-managed observations; every suggested edit is a proposal a human approves.
README
What is this?
An enterprise-ready remote Model Context Protocol server that lets Claude (Claude Code, Claude.ai, Claude Desktop, or any MCP client) work with Architectural Decision Records (ADRs) as first-class, verifiable artifacts:
- Record decisions in MADR style with structured, testable claims; search, version, supersede and archive them.
- Ingest evidence (manifests, IaC, config, code) through a fast direct-to-Blob upload with quarantine, hashing and content-safety scanning.
- Detect technologies deterministically from
.csproj,package.json, requirements, Dockerfiles, Bicep, Terraform, Kubernetes and CI files. - Detect drift between accepted decisions and what the code and infrastructure actually do.
- Detect contradictions between decisions, with scope-aware false-positive guards.
- Review safety of proposed decisions (security, availability, data loss, privacy, compliance, lock-in, cost, EOL, operability, rollback, blast radius).
- Remember tool calls, decisions and human feedback per tenant and workspace with explainable retrieval.
And one guarantee above all: the server never changes a human decision on its own. Analyzers write only to system-managed observations; every suggested edit is a proposal a human approves.
How it works
flowchart LR
C[Claude / MCP client] -->|HTTPS JSON-RPCStreamable HTTP| E[Azure FunctionsMCP extension]
E --> P[Pipeline: auth · tenant · validationidempotency · audit · memory]
P --> S[ADR services & deterministic analyzers]
S --> COS[(Cosmos DBmetadata, history, findings)]
S --> BLOB[(Blob StorageADR sources, evidence, sanitized)]
S --> Q[[Queue → background analysis]]
C -. direct PUT, single-blob SAS .-> BLOB
- Transport: Streamable HTTP at
https://.azurewebsites.net/runtime/webhooks/mcp(SSE fallback at/sse). - Auth:
mcp_extensionsystem key header by default, or Azure built-in Entra authentication (preview) for OAuth-based clients. - Identity: user-assigned managed identity for every data-plane call; no connection strings, no account keys.
- Hosting: Azure Functions Flex Consumption, .NET 10 (LTS) isolated worker, MCP extension 1.6.0 (GA).
More detail: Architecture · Security & threat model · Decisions.
Quick start (local, no Azure subscription)
Prerequisites: .NET 10 SDK (10.0.1xx), Node.js 20+, Python 3.9+.
npm i -g azure-functions-core-tools@4 azurite
cp src/AdrMcp.Functions/local.settings.json.example src/AdrMcp.Functions/local.settings.json
mkdir -p .azurite && (azurite --silent --location .azurite --skipApiVersionCheck &)
dotnet build AdrMcp.sln
(cd src/AdrMcp.Functions && func start --port 7071)
Verify with the protocol smoke test (initialize, tools/list, read and write calls):
python3 scripts/smoke-test.py --url http://localhost:7071/runtime/webhooks/mcp --write
Connect Claude Code:
claude mcp add --transport http adr-local http://localhost:7071/runtime/webhooks/mcp
The example settings use in-memory persistence, so only Azurite is needed locally. The same code runs against Cosmos DB in Azure.
Deploy to Azure
azd auth login
azd init -e adr-dev
azd env set AZURE_LOCATION eastus2 # any Flex Consumption region
azd up # Bicep provision + deploy
azd up creates: resource group, user-assigned identity, Storage (blob + queue, shared keys disabled), Cosmos DB serverless, Key Vault, Log Analytics + Application Insights, the Flex Consumption Function App, and least-privilege role assignments. Optional flags: ADR_AUTH_MODE=EntraBuiltIn, ADR_PRIVATE_NETWORKING=true, ADR_DEFENDER_STORAGE=true.
Post-deploy check (the key is read from Azure at run time and never stored in the repo):
RG=$(azd env get-value AZURE_RESOURCE_GROUP); APP=$(azd env get-value AZURE_FUNCTION_APP_NAME)
ADR_MCP_KEY="$(az functionapp keys list -g "$RG" -n "$APP" --query systemKeys.mcp_extension -o tsv)" \
python3 scripts/smoke-test.py --url "$(azd env get-value MCP_ENDPOINT)"
Full walkthrough: Local development & deployment.
Connect Claude
| Client | How |
|---|---|
| Claude Code | claude mcp add --transport http adr https://.azurewebsites.net/runtime/webhooks/mcp --header "x-functions-key: ${ADR_MCP_KEY}" or commit .mcp.json (already included; reads ADR_MCP_URL / ADR_MCP_KEY from your environment) |
| Claude.ai / Desktop / Cowork / mobile | Customize → Connectors → Add custom connector with the MCP URL; choose request headers (x-functions-key) or custom OAuth client for Entra. Claude connects from Anthropic’s cloud, so the endpoint must be reachable from the internet. |
| VS Code / Copilot | .vscode/mcp.json (prompts for host and key) |
| Anything else | Any MCP client that speaks Streamable HTTP |
Details, OAuth notes and upload guidance: Connecting Claude.
Tools
| Group | Tools |
|---|---|
| ADR management | adr_create adr_get adr_list adr_search adr_update adr_propose_change adr_approve_change adr_reject_change adr_supersede adr_archive adr_history adr_export |
| Evidence | file_upload_request file_register_upload evidence_attach evidence_list evidence_remove |
| Analysis | technology_detect technology_refresh adr_detect_drift adr_check_contradictions adr_safety_review finding_review |
| Jobs & memory | analysis_job_get analysis_job_cancel analysis_job_results decision_memory_search |
| Specified for later phases | file_import_from_repository adr_find_related_code adr_impact_analysis architecture_fitness_check dependency_map_generate c4_model_generate decision_lineage_get architecture_rule_create architecture_rule_validate governance_check deployment_readiness_check |
Every tool advertises an exact JSON Schema and returns a compact envelope { ok, data, error, meta }. Full contracts with examples are generated from code: MCP tool contracts.
Typical flow
adr_createa decision with claims (e.g. “must not use Newtonsoft.Json”).file_upload_request→PUTthe manifest to the returned URL →file_register_upload.adr_detect_drift→ each claim is Compliant / Drifted / Uncertain / Unsupported / NotApplicable with evidence and confidence.adr_check_contradictions→ findings withneedsSemanticReviewwhen deterministic confidence is low.- A human records the outcome with
finding_review; any text change goes throughadr_propose_change→adr_approve_change.
Configuration
All settings are plain app settings (Section__Key). Placeholders only; secrets come from Key Vault references or your local, git-ignored local.settings.json.
| Setting | Default | Purpose |
|---|---|---|
Persistence__Provider |
Cosmos |
Cosmos or InMemory (local/testing) |
Cosmos__AccountEndpoint |
— | https://.documents.azure.com:443/ (managed identity) |
Storage__BlobServiceUri / Storage__QueueServiceUri |
— | Storage endpoints (managed identity); Storage__ConnectionString=UseDevelopmentStorage=true for Azurite |
Auth__Mode |
FunctionKey |
FunctionKey (system key at the edge, static tenant binding) or EntraBuiltIn (App Service auth, roles from Entra app roles) |
Auth__StaticRoles__n |
none → Reader | Roles for the key-based principal (Reader, Author, Approver, Admin) |
Auth__DefaultRoleWhenNoAppRoles |
None |
Entra mode: role for a caller with no mapped app role (None refuses it; Reader lets any tenant user read) |
Auth__Tenants__n__Id / __MapTo / __Workspaces__n |
none | Entra mode: enrolled tenant (tid GUID), optional ADR tenant ID to store it under, and its workspaces (default when empty). Once any tenant is enrolled, other tenants are refused; each tenant needs its own ADR tenant ID. Bicep enrolls the deployment tenant |
Auth__TenantWorkspaces____n |
default |
Workspaces a tenant may use, keyed by ADR tenant ID. Linux app setting names allow only letters, digits and _, so use Auth__Tenants for a GUID tenant |
Adr__PrincipalHashSalt |
Key Vault reference | Salt for hashed principals in audit/memory |
Uploads__MaxFileBytes |
52428800 |
Upload size cap (50 MiB) |
Uploads__UploadUrlTtlMinutes |
15 |
Lifetime of the single-blob upload grant |
Uploads__BlockOnCriticalSafetyFinding |
true |
Reject uploads containing critical secrets |
Uploads__RequireDefenderScanResult |
false |
Require Microsoft Defender for Storage verdict before approval |
SafetyPolicy__BlockingRuleIds__n |
none | Safety-review rules that hard-block acceptance (organization policy) |
ContentSafety__* |
see options | Custom patterns, allow-list fingerprints, disabled detectors |
Complete list: src/AdrMcp.Application/Options/AdrOptions.cs, src/AdrMcp.Infrastructure/Options/InfrastructureOptions.cs, src/AdrMcp.Analysis/Safety/CompositeContentSafetyService.cs.
Security model in one minute
- Authentication at the edge (system key or Entra built-in auth); authorization per tool by role (Reader ⊂ Author ⊂ Approver ⊂ Admin).
- Tenant and workspace are resolved from the authenticated principal, never from tool arguments; all data is partitioned by
tenant|workspace. - Managed identity only; shared-key access and Cosmos local auth are disabled; Key Vault holds the only secret material.
- Uploads: allow-listed types, size caps, quarantine, server-side SHA-256, MIME sniffing, deterministic secret/PII masking, prompt-injection neutralization; analyzers read sanitized content only.
- Human-owned fields have a single write path requiring human provenance; every revision is snapshotted with a content hash.
- Logs, errors and audit records pass through a redactor; principals are stored hashed.
Full details and the STRIDE table: Security & threat model. Report vulnerabilities privately per SECURITY.md.
Working with AI agents in this repo
- Claude Code:
CLAUDE.mdholds project rules;.claude/agents/ships a tailored agent pack (ADR author, drift investigator, contradiction reviewer, security reviewer, Bicep reviewer, MCP contract guardian, test engineer, release engineer, docs keeper, multi-cloud architect). See.claude/agents/README.md. - GitHub Copilot: equivalents in
.github/agents/*.agent.mdand.github/copilot-instructions.md. - Cloud provider MCP servers (Azure, AWS, Google Cloud, Terraform, GitHub) are pre-wired read-only in
.mcp.json,.vscode/mcp.jsonand documented in.github/mcp/README.md. They use your own CLI identity; no credentials are stored.
Documentation index
Project status
Verified in this repository: clean Release build, 124 unit tests and 6 of 7 integration tests passing (the Cosmos DB test is skipped unless ADR_TEST_COSMOS_ENDPOINT or ADR_TEST_COSMOS_CONNECTION_STRING is set), Bicep builds without warnings, and an end-to-end MCP smoke test against the real local Functions host. Items marked [VERIFY] in the docs (preview features, external redirect URIs, API versions) and [REVIEW REQUIRED] (identity setup) should be checked by a human before production use.
Contributing & community
Contributing guide · Code of conduct · Support · Changelog · Security policy
Acknowledgements
Concepts were informed by the MIT-licensed mcp-adr-analysis-server; no code was copied (see THIRD-PARTY-NOTICES.md). Built on the Azure Functions MCP extension.
License
Install
This server does not publish a one-line install command.
Open the repository installation guide