Building and customizing solutions using Microsoft 365 Copilot APIs and tools
Enable environment-level telemetry to Application Insights, then query ExecuteTool spans in the dependencies table for daily MCP invocation counts, agent, tool, outcome, timestamp, and environment ID.^1^
Configure telemetry export
Environment-level telemetry is currently preview, applies only to managed environments, and is the appropriate scope for centralized tool-execution monitoring across agents. It supports both the standard and Microsoft Copilot harnesses, although Application Insights logs are available only for standard-harness agents built in Copilot Studio.^1^
Prerequisites include:
- Power Platform Administrator or Dynamics 365 Administrator at tenant level.
- Environment Administrator or System Administrator in Dataverse.
- Contributor, Writer, or Administrator rights to the Application Insights resource.
- An Application Insights resource dedicated to the environment or tenant.
- Local authentication enabled for the Application Insights integration.^2^
Configure it as follows:
- Open Power Platform admin center → Manage → Data export.
- Select App Insights → New data export.
- Select Copilot Studio as the export type.
- Select the source environment.
- Select the Azure subscription, resource group, and Application Insights resource.
- Create the export package.
- Run a test conversation that invokes an MCP tool.
- Allow up to 24 hours for initial telemetry delivery, then open Application Insights → Logs and verify that
ExecuteToolrows appear independencies.^2^
Query daily MCP tool usage
Copilot Studio exports InvokeAgent, ExecuteTool, and OutputMessages as dependency spans. Tool spans include:
-
timestamp -
successandresultCode -
gen_ai.agent.idandgen_ai.agent.name -
gen_ai.tool.name -
gen_ai.tool.type -
gen_ai.tool.call.id -
env.id - Optional arguments, results, and failure information^1^
Run this in Application Insights → Logs:
dependencies
| where timestamp >= startofday(ago(30d))
| where name == "ExecuteTool"
| extend
AgentId = tostring(customDimensions["gen_ai.agent.id"]),
AgentName = tostring(customDimensions["gen_ai.agent.name"]),
ToolName = tostring(customDimensions["gen_ai.tool.name"]),
ToolType = tostring(customDimensions["gen_ai.tool.type"]),
ToolCallId = tostring(customDimensions["gen_ai.tool.call.id"]),
EnvironmentId = tostring(customDimensions["env.id"])
| where ToolType startswith "MCP"
| summarize
TotalCalls = count(),
SuccessfulCalls = countif(success == true),
FailedCalls = countif(success == false)
by Day = startofday(timestamp), EnvironmentId,
AgentId, AgentName, ToolType, ToolName
| order by Day desc, AgentName asc, ToolName asc
For an invocation-level audit rather than daily aggregation:
dependencies
| where timestamp >= ago(30d) and name == "ExecuteTool"
| extend
AgentName = tostring(customDimensions["gen_ai.agent.name"]),
ToolName = tostring(customDimensions["gen_ai.tool.name"]),
ToolType = tostring(customDimensions["gen_ai.tool.type"]),
ToolCallId = tostring(customDimensions["gen_ai.tool.call.id"]),
EnvironmentId = tostring(customDimensions["env.id"]),
Failure = tostring(customDimensions["Status.message"])
| where ToolType startswith "MCP"
| project timestamp, EnvironmentId, AgentName, ToolName,
ToolType, ToolCallId, success, resultCode, Failure
| order by timestamp desc
Because telemetry properties can evolve during preview, inspect the live schema before operationalizing a dashboard:
dependencies
| where timestamp > ago(7d)
| mv-expand Key = bag_keys(customDimensions) to typeof(string)
| summarize Events = make_set(name),
SampleValue = take_any(tostring(customDimensions[Key])) by Key
| order by Key asc
Mapping to the requested metrics
| Requirement | Available field |
|---|---|
| Total MCP calls per day | Count of MCP ExecuteTool spans grouped by startofday(timestamp) |
| Calls by agent | gen_ai.agent.id, gen_ai.agent.name |
| Calls by individual tool | gen_ai.tool.name |
| Successful/failed calls | success, resultCode, Status.code, Status.message |
| Execution date/time | timestamp in UTC |
| Environment ID | env.id |
| MCP server | No separate, documented MCP-server-ID field |
gen_ai.tool.name can contain a server-qualified value—for example, workiqsharepoint:mcp_SharePointRemoteServer—but that naming convention should not be assumed universally. Check the values emitted by each MCP integration. If they consistently encode server identity, extract it with a deployment-specific parsing rule; otherwise, correlate with telemetry emitted by the MCP server itself.
For Business Central specifically, its server-side MCP telemetry provides configurationName, configurationSystemId, toolName, dynamicToolName, and invocation outcome. That schema is Business Central-specific and should not be generalized to every Copilot Studio MCP server.^3^
Historical and API access
Historical analysis is available only for telemetry collected after the export is enabled; the export does not document retroactive backfill. Azure Monitor Logs supports KQL analysis and configurable retention. Application Insights Analytics retention is normally 90 days and can be extended, with total retention available up to 12 years depending on configuration.^4^
There is no documented standalone Copilot Studio API dedicated to historical MCP invocation counts. For programmatic access, query the exported Application Insights/Azure Monitor data using the Application Insights Query API or Azure Monitor Logs Query API.^5^
The Application Insights → Agents (preview) → Tools view also aggregates ExecuteTool spans by call frequency and performance, but KQL is required for the requested environment, agent, tool, date, and outcome breakdown.^1^
References