Custom Agents - Observed command-capable MCP tool invocation
Custom Command Capable Mcp Tool Invocation
Query
let Evidence=materialize(CustomAgentInlineContent(1h));
CustomAgentSpans(1h)
| where Classification !in ('Excluded managed platform', 'Unattributed GenAI') and HasLineage
| where IsTool and ExplicitMcp and CommandCapable
| extend Signal='Command-capable MCP tool span; downstream execution unproven'
| extend TimeGenerated=EventTime, ResourceId=_ResourceId, TraceId=OperationId,
EventCount=tolong(column_ifexists('EventCount', 1)),
SuccessfulCalls=tolong(column_ifexists('SuccessfulCalls', 0)),
FailedCalls=tolong(column_ifexists('FailedCalls', 0))
| project TimeGenerated, ResourceId, Agent, AgentId, AgentKey, AppRoleName,
TraceId, SpanId, Conversation, Model, Tool, TargetHost, ServerDisplay,
Signal, EventCount, SuccessfulCalls, FailedCalls,
TriggerSpanId=tostring(column_ifexists('TriggerSpanId', '')),
TriggerTime=todatetime(column_ifexists('TriggerTime', datetime(null))),
TriggerTool=tostring(column_ifexists('TriggerTool', '')),
TriggerToolResult=tostring(column_ifexists('TriggerToolResult', '')),
TriggerServerDisplay=tostring(column_ifexists('TriggerServerDisplay', '')),
TriggerTargetHost=tostring(column_ifexists('TriggerTargetHost', '')),
RiskyOutputKind=tostring(column_ifexists('RiskyOutputKind', '')),
RelatedToolResults=tolong(column_ifexists('RelatedToolResults', 0)),
MatchedIntentPrompt=tostring(column_ifexists('IntentPrompt', '')),
MatchedIntentSpanId=tostring(column_ifexists('IntentSpanId', ''))
| join kind=leftouter (Evidence
| project ResourceId=_ResourceId, TraceId=OperationId, SpanId, AgentKey, Prompt, Output, ToolArguments, ToolResult, InputMessages, OutputMessages,
EvidenceSource, PromptEvidenceOrigin, OutputEvidenceOrigin, PromptEvidenceSpanId, OutputEvidenceSpanId,
InputParseState, OutputParseState, ToolArgumentsState, ToolResultState)
on ResourceId, TraceId, SpanId, AgentKey
| extend Prompt=coalesce(MatchedIntentPrompt, Prompt),
PromptEvidenceOrigin=iff(isnotempty(MatchedIntentPrompt), 'Matched intent span: user role', PromptEvidenceOrigin),
PromptEvidenceSpanId=coalesce(MatchedIntentSpanId, PromptEvidenceSpanId)
| extend PreviewCharacters=toint(min_of(160, max_of(0, (1500 - string_size(tostring(bag_pack(
'AgentId', AgentId, 'AgentKey', AgentKey, 'TraceId', TraceId, 'SpanId', SpanId,
'Conversation', Conversation, 'ResourceId', ResourceId, 'Signal', Signal)))) / 12)))
| extend PromptPreview=substring(Prompt, 0, PreviewCharacters),
OutputPreview=substring(Output, 0, PreviewCharacters)
| extend EvidencePreviewStatus=case(PreviewCharacters == 0, 'Metadata exhausted preview budget; inspect full query results',
strlen(Prompt) > PreviewCharacters or strlen(Output) > PreviewCharacters, 'Inline evidence; previews shortened; full text in query results',
isempty(Prompt) and isempty(Output), 'No prompt/output captured or parsed; not a protection verdict',
'Inline evidence; full recorded text in query results')
| project TimeGenerated, ResourceId, Agent, AgentId, AgentKey, AppRoleName,
TraceId, SpanId, Conversation, Model, Tool, TargetHost, ServerDisplay,
Signal, EventCount, SuccessfulCalls, FailedCalls, Prompt, Output, ToolArguments, ToolResult, InputMessages, OutputMessages,
EvidenceSource, PromptEvidenceOrigin, OutputEvidenceOrigin, PromptEvidenceSpanId, OutputEvidenceSpanId,
InputParseState, OutputParseState, ToolArgumentsState, ToolResultState,
PromptPreview, OutputPreview, EvidencePreviewStatus, TriggerSpanId, TriggerTime, TriggerTool, TriggerToolResult,
TriggerServerDisplay, TriggerTargetHost, RiskyOutputKind, RelatedToolResults
| order by TimeGenerated descExplanation
This query is designed to detect instances where a specific type of tool, known as an MCP (Managed Command Platform) tool, is used in a way that suggests it has the capability to execute commands. The query is part of a scheduled alert system with the following key points:
-
Purpose: It flags instances where an MCP tool is observed with command execution capabilities. However, it notes that just because the tool is observed, it doesn't necessarily mean that any commands were actually executed.
-
Severity: The alert is classified as "High" severity, indicating that it is considered a significant security concern.
-
Data Sources: It relies on data from Application Insights, specifically looking at application requests and dependencies.
-
Frequency and Period: The query runs every hour and looks back over the past 14 days to identify relevant events.
-
Conditions:
- It filters out certain classifications and focuses on tools that are explicitly identified as MCP and command-capable.
- It gathers various details about the event, such as the time it was generated, the resource involved, and the tool's success or failure in making calls.
-
Evidence and Previews:
- It attempts to provide a preview of the evidence by summarizing the prompt and output associated with the tool's use.
- It also provides a status message about the evidence preview, indicating whether the full text is available or if it has been shortened.
-
Output: The results are ordered by the time they were generated, and various details about the event are projected for further analysis.
-
Entity Mapping: The query maps certain fields to Azure resources and cloud applications for better identification and tracking.
-
Custom Details and Grouping: It includes custom details for each alert and is configured to create incidents in a security incident management system, grouping alerts by specific details like AgentKey and ResourceId.
-
Version and Tags: The query is versioned and tagged for categorization and management within a larger system.
Overall, this query is part of a security monitoring setup that aims to detect potentially risky tool usage within an application environment, providing detailed insights and evidence for further investigation.