'array',
'result_summary' => 'array',
'success' => 'boolean',
'duration_ms' => 'integer',
];
// Relationships
public function workspace(): BelongsTo
{
return $this->belongsTo(Workspace::class);
}
// Scopes
public function scopeForServer(Builder $query, string $serverId): Builder
{
return $query->where('server_id', $serverId);
}
public function scopeForTool(Builder $query, string $toolName): Builder
{
return $query->where('tool_name', $toolName);
}
public function scopeSuccessful(Builder $query): Builder
{
return $query->where('success', true);
}
public function scopeFailed(Builder $query): Builder
{
return $query->where('success', false);
}
public function scopeRecent(Builder $query, int $hours = 24): Builder
{
return $query->where('created_at', '>=', now()->subHours($hours));
}
public function scopeToday(Builder $query): Builder
{
return $query->whereDate('created_at', today());
}
public function scopeThisWeek(Builder $query): Builder
{
return $query->where('created_at', '>=', now()->startOfWeek());
}
/**
* Log a tool call and update daily stats.
*/
public static function log(
string $serverId,
string $toolName,
array $params = [],
bool $success = true,
?int $durationMs = null,
?string $errorMessage = null,
?string $errorCode = null,
?array $resultSummary = null,
?string $sessionId = null,
?string $agentType = null,
?string $planSlug = null,
?int $workspaceId = null
): self {
$call = static::create([
'workspace_id' => $workspaceId,
'server_id' => $serverId,
'tool_name' => $toolName,
'input_params' => $params,
'success' => $success,
'duration_ms' => $durationMs,
'error_message' => $errorMessage,
'error_code' => $errorCode,
'result_summary' => $resultSummary,
'session_id' => $sessionId,
'agent_type' => $agentType,
'plan_slug' => $planSlug,
]);
// Update daily stats
McpToolCallStat::incrementForCall($call);
return $call;
}
// Helpers
public function getDurationForHumans(): string
{
if (! $this->duration_ms) {
return '-';
}
if ($this->duration_ms < 1000) {
return $this->duration_ms.'ms';
}
return round($this->duration_ms / 1000, 2).'s';
}
public function getStatusBadge(): string
{
return $this->success
? 'Success'
: 'Failed';
}
}