Skip to main content
Glama
tool-call-logger.ts3.89 kB
/** * Modern Tool Call Logger - Separated Search and Fetch Logging * Optimal solution with dedicated tables for different MCP tool call types */ import { logger } from "../utils/logger.js"; export interface SearchLogEntry { userId: string; mcpToken?: string | null; searchQuery: string; resultCount: number; responseTimeMs: number; statusCode?: number; errorCode?: string | null; ipAddress?: string; } export interface FetchLogEntry { userId: string; mcpToken?: string | null; requestedUrl: string; actualUrl?: string | null; pageId?: string | null; responseTimeMs: number; statusCode?: number; errorCode?: string | null; ipAddress?: string; } export class ToolCallLogger { private d1: D1Database; constructor(d1: D1Database) { this.d1 = d1; } /** * Log search operation to D1 database (async, non-blocking) */ async logSearch(entry: SearchLogEntry): Promise<void> { try { await this.executeSearchLog(entry); } catch (error) { logger.error( `Search log failed: ${error instanceof Error ? error.message : String(error)} (userId: ${entry.userId})` ); // 不重新抛出错误,避免影响主流程 } } /** * Log fetch operation to D1 database (async, non-blocking) */ async logFetch(entry: FetchLogEntry): Promise<void> { try { await this.executeFetchLog(entry); } catch (error) { logger.error( `Fetch log failed: ${error instanceof Error ? error.message : String(error)} (userId: ${entry.userId})` ); // 不重新抛出错误,避免影响主流程 } } /** * Execute search log operation with environment-aware connection */ private async executeSearchLog(entry: SearchLogEntry): Promise<void> { try { const now = new Date().toISOString(); // Generate UTC timestamp with timezone info const result = await this.d1 .prepare( `INSERT INTO search_logs (user_id, mcp_token, search_query, result_count, response_time_ms, status_code, error_code, ip_address, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)` ) .bind( entry.userId, entry.mcpToken, entry.searchQuery, entry.resultCount, entry.responseTimeMs, entry.statusCode, entry.errorCode || null, entry.ipAddress || null, now ) .run(); if (!result.success) { throw new Error("D1 search log execution failed"); } } catch (error) { // Re-throw for caller's catch block throw new Error( `D1 search logging failed: ${error instanceof Error ? error.message : String(error)}` ); } } /** * Execute fetch log operation with environment-aware connection */ private async executeFetchLog(entry: FetchLogEntry): Promise<void> { try { const now = new Date().toISOString(); // Generate UTC timestamp with timezone info const result = await this.d1 .prepare( `INSERT INTO fetch_logs (user_id, mcp_token, requested_url, actual_url, page_id, response_time_ms, status_code, error_code, ip_address, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ) .bind( entry.userId, entry.mcpToken, entry.requestedUrl, entry.actualUrl || null, entry.pageId || null, entry.responseTimeMs, entry.statusCode, entry.errorCode || null, entry.ipAddress || null, now ) .run(); if (!result.success) { throw new Error("D1 fetch log execution failed"); } } catch (error) { // Re-throw for caller's catch block throw new Error( `D1 fetch logging failed: ${error instanceof Error ? error.message : String(error)}` ); } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/adimowis/appler'

If you have feedback or need assistance with the MCP directory API, please join our Discord server