CODA (Cosmos Observability and Diagnostic Agent) is a local, read-only diagnostic tool for Azure Cosmos DB for NoSQL. Select an account or resource group to find throughput waste, throttling, partition hot spots, expensive queries, and configuration risks.
CODA has a browser UI and an optional MCP server. Its 24 detectors share the same Python engine; the web app does not require an AI model, an API key, or a hosted CODA service.
Preview release. Package checks do not establish complete live validation of every detector. Fresh all-detector acceptance and signed-in verification of the Portal links are deferred for this preview. Review the detector limitations and incomplete evaluations; do not treat absence of a finding as proof that a resource is healthy.
Example account analysis. Subscription and resource identifiers have been replaced with demo names; findings and estimated savings depend on your workload and available evidence.
| Guide | What you will find |
|---|---|
| Detector reference | Every detector, its data sources, analysis window, and recommended next step |
| Permissions and sign-in | Microsoft Entra authentication, RBAC roles and scopes, optional cost access |
| Log Analytics setup and readiness | Required categories, resource-specific tables, collection time, and troubleshooting |
| Architecture and data flow | Components, Azure services, outbound connections, and data handling |
CODA is diagnose-only and read-only. It reads resource configuration, Azure Monitor metrics, and supported Log Analytics records. It does not modify Azure resources or read application documents.
Authentication uses Microsoft Entra ID only. CODA does not accept or require account keys, connection strings, or other long-lived credentials. Sign in with an identity that has only the read permissions needed for the resources you choose to diagnose.
- Windows, macOS, or Linux
- Python 3.12 or newer
- Azure CLI for the simplest local sign-in
- Microsoft Entra access to the Azure resources you want to diagnose; see RBAC
- Outbound HTTPS access to Azure authentication and monitoring APIs
Log Analytics is optional: four detectors require its resource-specific logs. Other checks use configuration and metrics, but some still need historical metrics or a sufficiently old resource. Enabling logs does not make every detector fire. See readiness.
Enable diagnostic categories on the Cosmos DB account and send them to a Log Analytics workspace. The tables are populated in that workspace; they are not Cosmos DB containers.
| Detector | Log Analytics dependency | Table(s) used |
|---|---|---|
| DX-002 - Cross-partition query fan-out | Required | CDBQueryRuntimeStatistics and raw CDBDataPlaneRequests |
| DX-003 - Shared-throughput starvation | Required | CDBDataPlaneRequests5M preferred; raw CDBDataPlaneRequests supported |
| DX-007 - Shard-key misalignment | Required | CDBQueryRuntimeStatistics and raw CDBDataPlaneRequests |
| DX-010 - Uncontrolled ingestion | Required | CDBDataPlaneRequests5M preferred; raw CDBDataPlaneRequests supported |
| DX-016 - Expensive consistency | Optional read-charge enrichment; the finding uses ARM configuration | CDBDataPlaneRequests5M preferred; raw CDBDataPlaneRequests supported |
Twenty detectors do not require Log Analytics; DX-016 can optionally use it for enrichment. See the full detector-to-data-source and production-window table for metrics, configuration, and optional cost/pricing inputs.
An administrator configures collection:
- Choose an existing Log Analytics workspace, or create one under your organization's policies.
- In Azure Portal, open the Cosmos DB account > Monitoring > Diagnostic settings > Add diagnostic setting.
- Select DataPlaneRequests5M for DX-003, DX-010, and optional DX-016 enrichment. Also select DataPlaneRequests and QueryRuntimeStatistics if you need DX-002/DX-007. Enable only the categories needed for your diagnostics rather than indiscriminately enabling all logs.
- Choose Send to Log Analytics workspace, select the workspace, and select Resource specific table mode. Save the setting. CODA's resource-context queries use the Analytics table plan.
- Grant the diagnosing identity the appropriate resource/log read access. Allow representative workload activity and ingestion before interpreting results.
The four log-dependent detectors request 24 hours of logs. New settings collect future events; they do not backfill history. Ingestion/retention can incur charges, and readable records alone do not prove a complete window or sufficient per-container traffic. Full-text query logging is not required. Follow the detailed setup and readiness guide.
Check before analyzing: after signing in and selecting a subscription and resource group, select an account and click Run Pre-Checks. Leave Account empty to check NoSQL accounts in the group. Hover over the button for its scope: ARM, Resource Graph, Azure Monitor metrics, Log Analytics configuration/data, and optional subscription Cost Management.
Green checks indicate successful read probes—not complete history or account health. Empty cost or metric results are not permission failures. ARG discovery and diagnosis use the same SDK credential. Cost and ARG warnings do not block ordinary diagnosis.
For an issue, choose View fix. The popup shows the issue, exact scope and original requester. If the required administrative action is reported for that identity, it can offer Copy PowerShell. Otherwise it provides Copy admin request, identifying the read role or setup action for your subscription administrator or delegated scope administrator.
CODA never executes these scripts. They use Azure CLI, preview by default, and require an
explicit -Apply when run separately after review. Role scripts target the original requester,
not the administrator running them. Logging scripts require an approved existing workspace,
preserve existing exports and stop rather than overwrite settings. Reported rights do not bypass
PIM, role conditions, deny assignments or Azure Policy. No administrator role is required merely
to run CODA.
Choose a release wheel for normal use, or clone/download the repository to run from source.
PyPI publication is not available: do not use an unqualified pip install coda.
If the Releases page has no release yet, use the
source option below.
In a new, empty working folder, create an isolated environment:
python -m venv .venvActivate it with .\.venv\Scripts\Activate.ps1 in Windows PowerShell, or
source .venv/bin/activate on macOS/Linux. If PowerShell blocks activation, use
.\.venv\Scripts\python.exe and .\.venv\Scripts\coda.exe directly instead.
If your system names Python python3, use that name for the initial environment-creation command.
For automatic downloads, install GitHub CLI and sign in with
gh auth login if needed. This is separate from the Azure sign-in used when running CODA.
The commands below select the newest non-draft release, including Preview releases. There is
no version to replace, and the wheel and checksums come from the same selected tag. A newer source
checkout or merged PR is not selected until its release is published.
Run the block for your shell in the activated environment. Downloads intentionally fail if files already exist; use a fresh working folder rather than mixing releases.
$ErrorActionPreference = "Stop"
$repo = "AzureCosmosDB/coda"
$tag = gh release list --repo $repo --exclude-drafts --order desc --limit 1 --json tagName --jq '.[0].tagName'
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($tag)) { throw "Could not select a published CODA release." }
$version = $tag -replace '^v', ''
$wheel = "coda-$version-py3-none-any.whl"
gh release download $tag --repo $repo --pattern $wheel --pattern SHA256SUMS.txt
if ($LASTEXITCODE -ne 0) { throw "Release download failed." }
python -c "import hashlib,pathlib,sys; wheel=pathlib.Path(sys.argv[1]); rows=[line.split() for line in pathlib.Path('SHA256SUMS.txt').read_text(encoding='utf-8').splitlines()]; expected=next(row[0] for row in rows if len(row)==2 and row[1].lstrip('*')==wheel.name); actual=hashlib.sha256(wheel.read_bytes()).hexdigest(); sys.exit('SHA-256 mismatch') if actual!=expected else print('SHA-256 verified')" $wheel
if ($LASTEXITCODE -ne 0) { throw "Checksum verification failed; nothing was installed." }
python -m pip install "./$wheel"
if ($LASTEXITCODE -ne 0) { throw "Installation failed." }set -euo pipefail
repo="AzureCosmosDB/coda"
tag=$(gh release list --repo "$repo" --exclude-drafts --order desc --limit 1 --json tagName --jq '.[0].tagName')
test -n "$tag" || { echo "Could not select a published CODA release." >&2; exit 1; }
version="${tag#v}"
wheel="coda-$version-py3-none-any.whl"
gh release download "$tag" --repo "$repo" --pattern "$wheel" --pattern SHA256SUMS.txt
python -c "import hashlib,pathlib,sys; wheel=pathlib.Path(sys.argv[1]); rows=[line.split() for line in pathlib.Path('SHA256SUMS.txt').read_text(encoding='utf-8').splitlines()]; expected=next(row[0] for row in rows if len(row)==2 and row[1].lstrip('*')==wheel.name); actual=hashlib.sha256(wheel.read_bytes()).hexdigest(); sys.exit('SHA-256 mismatch') if actual!=expected else print('SHA-256 verified')" "$wheel"
python -m pip install "./$wheel"For optional MCP support, after either block installs the verified wheel, run:
python -m pip install "./${wheel}[mcp]"The base installation already includes the web UI; MCP is the only optional extra.
If you do not want to use GitHub CLI, or need to pin a particular release, use the following steps.
Download coda-<version>-py3-none-any.whl and SHA256SUMS.txt from the same
GitHub Release. Replace <version> with the
selected version everywhere below. In the download directory, verify the wheel:
python -c "import hashlib, pathlib; wheel = pathlib.Path('coda-<version>-py3-none-any.whl'); lines = pathlib.Path('SHA256SUMS.txt').read_text(encoding='utf-8').splitlines(); expected = next(line.split()[0] for line in lines if line.split()[-1].lstrip('*') == wheel.name); actual = hashlib.sha256(wheel.read_bytes()).hexdigest(); assert actual == expected, f'SHA-256 mismatch: {actual} != {expected}'; print(f'SHA-256 verified: {actual}')"Install the verified local wheel:
python -m pip install "./coda-<version>-py3-none-any.whl"Alternatively, install directly from the versioned release URL:
pip install "https://github.com/AzureCosmosDB/coda/releases/download/v<version>/coda-<version>-py3-none-any.whl"To use the MCP server, install the optional mcp extra from that same wheel asset:
pip install "coda[mcp] @ https://github.com/AzureCosmosDB/coda/releases/download/v<version>/coda-<version>-py3-none-any.whl"For a downloaded wheel with MCP support, use
python -m pip install "./coda-<version>-py3-none-any.whl[mcp]".
Install uv at the version required by
pyproject.toml (currently 0.12.3). Then:
git clone https://github.com/AzureCosmosDB/coda.git
cd coda
uv sync --locked
uv run --no-sync coda webWithout Git, choose Code > Download ZIP on the repository page, extract it, open a terminal in
the extracted directory containing pyproject.toml, and run the last two commands.
For a specific released source version, select its tag rather than the moving main branch.
To add MCP support to a source checkout:
uv sync --locked --extra mcp
uv run --no-sync coda mcpStop the stdio MCP process with Ctrl+C when testing it from a terminal; normally an MCP client starts and manages that process.
Use your own tenant and subscription, not a service account or account key:
az login --tenant "<tenant-id>"
az account set --subscription "<subscription-id>"CODA uses DefaultAzureCredential. Its Sign in button enables use of your existing local Azure
credential; it is not a separate CODA account or guaranteed browser login prompt. If discovery
fails, complete az login first. See credential selection and troubleshooting.
Start the installed application (or use uv run --no-sync coda web in a source checkout):
coda webOpen http://127.0.0.1:8000/. If that port is occupied, use coda web --port 8080 and open
http://127.0.0.1:8080/ instead. Keep the terminal open; Ctrl+C stops the app.
- Select Sign in, then select your subscription. Enable All subscriptions if the default Cosmos-named subscription filter hides yours.
- Select a resource group and optionally an account. Run Pre-Checks performs optional prerequisite read checks for that account, or the group when Account is empty.
- Choose Scan resource group for its supported NoSQL accounts, or Analyze account for the selected account. Missing log prerequisites do not prevent other applicable checks.
- Review findings and recommendations, then expand Detector/resource evaluations we couldn't complete. Missing permissions, missing logs, and insufficient history are not a clean result.
Web scans use production analysis windows. A large resource group can take time; start with a single account if you are checking setup. Discovery lists account metadata within the selected subscription, but the web scan itself is restricted to the selected resource group.
CODA recommends changes; you decide whether and how to apply them. Resource links open Azure Portal. Agent Kit identifiers and detailed metadata remain in structured reports rather than cluttering the web results.
Keep CODA bound to loopback. Do not expose it with --host 0.0.0.0, port forwarding, or a public
reverse proxy. This is a single-user local application, not an authenticated multi-user service.
With the mcp extra installed, configure your client to start:
coda mcpFor example, a VS Code .vscode/mcp.json entry:
{
"servers": {
"coda": {
"type": "stdio",
"command": "coda",
"args": ["mcp"]
}
}
}The client must be able to find the installed executable and Azure credentials. If it does not
inherit your activated environment, set command to the full path of that environment's coda
executable. For source installs you can instead configure uv with the checkout's working directory.
Ask the client to list detectors or diagnose a specific account. MCP also exposes subscription
scan tools; explicitly request resource-group/account filters for large subscriptions. The
coda terminal launcher has web and mcp commands, not a coda diagnose command.
MCP reports are returned to your chosen client. Its model/provider may process those reports under its own privacy settings; review that policy before sharing customer telemetry with an AI service.
| Symptom | Check |
|---|---|
| Authentication failed or no subscriptions | Run az login, confirm the tenant and roles, and check All subscriptions |
| Missing resource group/account | Verify Azure access; discovery currently selects NoSQL accounts |
| A prerequisite check fails | Use Run Pre-Checks > View fix. Review the scoped PowerShell or administrator request; do not assume every error needs a role assignment. |
| Log Analytics checks cannot complete | Verify the relevant categories, Resource specific mode, ingestion and access; use the issue popup and setup guide. |
| Too new, too few samples, or no finding | Check the detector's window, resource applicability, traffic volume, and thresholds; absence of a finding is not proof of full coverage |
| Dollar savings replaced by recoverable RU/s | Expand the report's incomplete section for the cost-estimate reason. Cost Management throttling (429) needs time before retrying, not an extra role; capacity findings remain valid. |
coda is not found |
Activate the installation environment or use the full executable path |
coda mcp says the extra is missing |
Reinstall the selected wheel with [mcp], or run uv sync --locked --extra mcp |
For a wheel install, download and verify the new release, then install that wheel with
python -m pip install --upgrade "./coda-<version>-py3-none-any.whl" (include [mcp] if needed).
For a clean source checkout, use git pull --ff-only and uv sync --locked before restarting.
Do not discard local changes to update. Packaged web/MCP processes do not self-update.
Use public GitHub Issues for product problems, feature
requests, and diagnostic feedback. When sharing diagnostic feedback, attach only the
*-redacted.json artifact after reviewing it. Never attach a full report, credentials, resource
identifiers, or customer data.
External code contributions are not accepted. See CONTRIBUTING.md and SUPPORT.md for the public feedback and support policy.
Do not report suspected vulnerabilities in a public Issue. Use GitHub Private Vulnerability Reporting as described in SECURITY.md.
