Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions mcpjam-inspector/client/src/components/logger-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Trash2,
PanelRightClose,
Copy,
Download,
} from "lucide-react";
import { JsonEditor } from "@/components/ui/json-editor";
import { Input } from "@/components/ui/input";
Expand Down Expand Up @@ -67,6 +68,8 @@ interface RenderableRpcItem {
widgetId?: string;
}

type LogEntrySnapshot = Omit<RenderableRpcItem, 'id'>;

interface LoggerViewProps {
serverIds?: string[]; // Optional filter for specific server IDs
onClose?: () => void; // Optional callback to close/hide the panel
Expand Down Expand Up @@ -177,15 +180,36 @@ export function LoggerView({
setExpanded(new Set());
};

const copyLogs = async () => {
const logs = filteredItems.map((item) => ({
const extractLogs = (): Array<LogEntrySnapshot> => {
return filteredItems.map((item) => ({
timestamp: item.timestamp,
source: item.source,
serverId: item.serverId,
direction: item.direction,
method: item.method,
payload: item.payload,
}));
};

const exportLogs = () => {
const logs = extractLogs();

const blob = new Blob([JSON.stringify(logs, null, 2)], {
type: "application/json",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `mcp-logs-${new Date().toISOString()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast.success("Logs exported");
};

const copyLogs = async () => {
const logs = extractLogs();
try {
await navigator.clipboard.writeText(JSON.stringify(logs, null, 2));
toast.success("Logs copied to clipboard");
Expand Down Expand Up @@ -248,6 +272,16 @@ export function LoggerView({
<div className="flex items-center justify-between">
<h2 className="text-xs font-semibold text-foreground">Logs</h2>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
onClick={exportLogs}
disabled={filteredItemCount === 0}
className="h-7 w-7"
title="Export logs"
>
<Download className="h-3.5 w-3.5" />
</Button>
<Button
variant="ghost"
size="icon"
Expand Down