Report API and MCP
IntensiveReports can serve its reports to scripts and other tools (the report API, /ir-api/v1) and to AI
assistants (the MCP server, /ir-mcp). Both read the same data as the pages, through the same
checks. This page is the administrator’s side. How clients call the API is in API and MCP.
Everything here is on Settings > API access and needs an IntensiveReports administrator.
Switch it on
Section titled “Switch it on”The API is off after installation. While it is off, every API, MCP and API sign-in address answers 404, as if it
did not exist.
Turn on Report API at the top of the tab. The tab also shows the MCP server’s address for AI assistants.
Create a client
Section titled “Create a client”Every script, tool or assistant gets its own client. Press Add client and fill in:
| Field | Meaning |
|---|---|
| Name | who or what uses it, for example Monitoring script or AI assistant for the helpdesk |
| Sign-in | Token, Certificate or Entra ID (user, group or app); see below |
| Preset | Reader: read everything. Operator: read and refresh everything. AI assistant: read only the areas you tick. Custom: set each area yourself. |
| Access per product area | for each area (Entra ID, Security, Intune, Exchange Online, SharePoint Online, OneDrive, Teams and collaboration, Licensing, Compliance, Tenant): No access, Read, Read and refresh or Read, refresh and run scans. Run scan includes refresh, refresh includes read. |
| Never show these reports | reports this client never sees, whatever its access, for example reports you do not want an AI assistant to read. Reports built from a hidden report’s rows are hidden too; the tab lists them. |
| Expires after (days) | 365 by default; 0 means never. A client past its expiry is refused. |
A client sees only the reports of the areas it may read. Any other report answers 404, exactly like a report that
does not exist. An action above its access (for example a refresh with read access) answers 403. Which report belongs
to which area is shown on each report’s page in the report reference.
Sign-in types
Section titled “Sign-in types”IntensiveReports generates a token of the form ir1.<client id>.<secret> and shows it once, when you save the
client. Copy it then; IntensiveReports keeps only a hash of it. The client sends it as
Authorization: Bearer <token>.
Certificate
Section titled “Certificate”For automation without a stored secret. Upload the client’s public certificate (.cer, .crt or .pem). The
client signs its own short-lived token (at most one hour) with the private key and sends it as
Authorization: Bearer <JWT>. The token’s audience must be the site’s address, so set
IntensiveReportsConfig:Api:PublicUrl (or pin AllowedHosts); otherwise certificate clients are refused.
setup\New-IrApiClientAssertion.ps1 creates such a token, for testing or for scripts:
.\setup\New-IrApiClientAssertion.ps1 -ClientId <client id> -BaseUrl https://reports.example.com -Thumbprint <thumbprint>It reads the certificate from the user’s store (-StoreLocation LocalMachine for the machine store) or from a file
(-PfxPath), and makes a token valid for 30 minutes (-LifetimeMinutes, 1 to 60).
Entra ID (user, group or app)
Section titled “Entra ID (user, group or app)”People, groups or apps sign in with Entra ID instead of a token. This is how AI assistants such as Claude.ai, Claude Desktop or Claude Code connect with each user’s own account. It needs a second app registration, IntensiveReports API, which holds no Microsoft Graph permissions; it only identifies the API.
-
Create it, as a Global Administrator or Application Administrator:
Terminal window .\setup\New-IrApiResourceApp.ps1 -AssignUser admin@example.comParameter Meaning -AssignUser,-AssignGroup,-AssignAppgive users (sign-in name), groups (object ID) or apps (app ID) the role IR.Api.Access. Only assigned identities get a token at all.-NewClientSecretcreates a client secret for the Claude.ai or Claude Desktop custom connector (shown once; valid 6 months, -SecretMonthsto change)-ClaudeCodeCallbackPortthe local callback port for Claude Code (default 8080) -DisplayNamename of the app registration (default IntensiveReports API) The script is safe to run again, for example to assign more users.
-
Put the printed application ID into
appsettings.jsonand restart the app:"IntensiveReportsConfig": { "Api": { "Entra": { "ApiAppId": "<printed app id>" } } } -
On Settings > API access, add a client with sign-in Entra ID (user, group or app) for each user, group or app, and give it its access. Entra ID proves who calls; the client’s access and hidden reports decide what it reads.
The tab shows how each AI assistant connects. Details for users: API and MCP.
Manage clients
Section titled “Manage clients”The client list shows each client’s name, access, sign-in type, expiry and Last used.
| To | Do |
|---|---|
| stop a client for a while | switch off Enabled |
| replace a lost or leaked token | New token: the old token stops working at once |
| change access or expiry | Edit |
| remove a client | Delete: its token stops working at once |
Audit log
Section titled “Audit log”Every API and MCP call is written to App_Data\api-audit\<yyyy-MM-dd>.jsonl, one line per call: time, client, address,
method, path, report, action, status, number of rows and details. Refusals (401, 403, 404, 429) are logged too.
Files are kept for 90 days. Back them up with the rest of App_Data if you need them longer.
Settings in appsettings.json
Section titled “Settings in appsettings.json”| Key | Default | Meaning |
|---|---|---|
IntensiveReportsConfig:Api:PublicUrl | empty | the site’s public address; needed for certificate clients and MCP sign-in with Entra ID |
IntensiveReportsConfig:Api:RequestsPerMinute | 120 | requests a minute per client |
IntensiveReportsConfig:Api:AnonymousRequestsPerMinute | 20 | requests a minute per address without a valid token |
IntensiveReportsConfig:Api:Entra:ApiAppId | empty | the IntensiveReports API app; turns on Entra sign-in for clients |
IntensiveReportsConfig:Api:Entra:TenantId | the data tenant | the tenant of that app |
IntensiveReportsConfig:Api:Entra:AccessRole | IR.Api.Access | the app role callers need |
Above the limits, the API answers 429 with Retry-After.