Skip to main content
Glama
nocoo

MCP Work History Server

by nocoo

log_activity

Track AI tool usage by logging activity details like model, tokens, cost, and success status into daily worklog files for comprehensive metrics and analysis.

Instructions

Log AI tool activity to a daily worklog file with comprehensive metrics

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ai_modelNoAI model used (e.g., 'gemini-2.5-pro', 'claude-3-sonnet', 'gpt-4')
context_lengthNoContext window length used (optional)
cost_usdNoEstimated cost in USD (optional)
duration_msNoDuration of the operation in milliseconds (optional)
error_messageNoError message if operation failed (optional)
input_tokensNoInput tokens used (optional)
log_messageYesDetailed log message describing what was accomplished
output_tokensNoOutput tokens generated (optional)
successNoWhether the operation was successful (optional, defaults to true)
tagsNoTags to categorize the activity (e.g., ['coding', 'debugging', 'refactoring']) (optional)
tokens_usedNoTotal tokens consumed in the request (optional)
tool_nameYesName of the AI tool that performed the activity (e.g., 'Warp', 'Claude Code', 'GitHub Copilot')

Implementation Reference

  • The handler function that executes the log_activity tool. It parses arguments, constructs a formatted log entry with optional metadata (tokens, duration, cost, etc.), appends it to a daily Markdown worklog file in the 'logs' directory, and returns a success or error message.
    async handleLogActivity(args) { try { const { tool_name, log_message, ai_model, tokens_used, input_tokens, output_tokens, context_length, duration_ms, cost_usd, success = true, error_message, tags } = args; if (!tool_name || !log_message) { throw new Error("tool_name and log_message are required"); } const now = new Date(); const dateStr = now.toISOString().split('T')[0]; // YYYY-MM-DD format const timeStr = now.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }); const logsDir = path.join(__dirname, '..', 'logs'); const logFileName = `worklog-${dateStr}.md`; const logFilePath = path.join(logsDir, logFileName); // Ensure logs directory exists await fs.mkdir(logsDir, { recursive: true }); let logContent = ''; let fileExists = false; try { await fs.access(logFilePath); fileExists = true; logContent = await fs.readFile(logFilePath, 'utf-8'); } catch (error) { // File doesn't exist, create new content logContent = `# 📝 Work Log - ${dateStr}\n\n`; } // Build the log entry with optional metadata let logEntry = `${timeStr} - ${tool_name}`; if (ai_model) { logEntry += ` (${ai_model})`; } logEntry += `: ${log_message}`; // Add optional metadata const metadata = []; if (tokens_used !== undefined) { metadata.push(`${tokens_used} tokens`); } else if (input_tokens !== undefined || output_tokens !== undefined) { const inTokens = input_tokens || 0; const outTokens = output_tokens || 0; metadata.push(`${inTokens + outTokens} tokens (${inTokens}→${outTokens})`); } if (context_length !== undefined) { metadata.push(`${context_length}k ctx`); } if (duration_ms !== undefined) { const seconds = duration_ms >= 1000 ? `${(duration_ms / 1000).toFixed(1)}s` : `${duration_ms}ms`; metadata.push(seconds); } if (cost_usd !== undefined) { metadata.push(`$${cost_usd.toFixed(4)}`); } if (!success && error_message) { metadata.push(`❌ ${error_message}`); } if (tags && tags.length > 0) { metadata.push(`[${tags.join(', ')}]`); } if (metadata.length > 0) { logEntry += ` (${metadata.join(' | ')})`; } const statusIcon = success ? '✅' : '❌'; const newEntry = `- ${statusIcon} ${logEntry}\n`; // If it's a new file, add it directly. Otherwise, append to existing content if (!fileExists) { logContent += newEntry; } else { // Insert at the end of the file logContent += newEntry; } await fs.writeFile(logFilePath, logContent, 'utf-8'); return { content: [ { type: "text", text: `✅ Activity logged: ${logEntry}${fileExists ? '' : ' (new file created)'}` } ] }; } catch (error) { return { content: [ { type: "text", text: `❌ Error logging activity: ${error.message}` } ], isError: true }; } }
  • Input schema for the log_activity tool, defining required (tool_name, log_message) and optional parameters for logging AI activity metrics.
    inputSchema: { type: "object", properties: { tool_name: { type: "string", description: "Name of the AI tool that performed the activity (e.g., 'Warp', 'Claude Code', 'GitHub Copilot')" }, log_message: { type: "string", description: "Detailed log message describing what was accomplished" }, ai_model: { type: "string", description: "AI model used (e.g., 'gemini-2.5-pro', 'claude-3-sonnet', 'gpt-4')" }, tokens_used: { type: "number", description: "Total tokens consumed in the request (optional)" }, input_tokens: { type: "number", description: "Input tokens used (optional)" }, output_tokens: { type: "number", description: "Output tokens generated (optional)" }, context_length: { type: "number", description: "Context window length used (optional)" }, duration_ms: { type: "number", description: "Duration of the operation in milliseconds (optional)" }, cost_usd: { type: "number", description: "Estimated cost in USD (optional)" }, success: { type: "boolean", description: "Whether the operation was successful (optional, defaults to true)" }, error_message: { type: "string", description: "Error message if operation failed (optional)" }, tags: { type: "array", items: { type: "string" }, description: "Tags to categorize the activity (e.g., ['coding', 'debugging', 'refactoring']) (optional)" } }, required: ["tool_name", "log_message"] }
  • src/index.js:102-108 (registration)
    Registration of the CallToolRequest handler that routes 'log_activity' calls to the handleLogActivity method.
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "log_activity") { return await this.handleLogActivity(request.params.arguments); } throw new Error(`Unknown tool: ${request.params.name}`); });
  • src/index.js:35-99 (registration)
    Tool registration in the ListToolsRequest response, including name, description, and inputSchema for log_activity.
    return { tools: [ { name: "log_activity", description: "Log AI tool activity to a daily worklog file with comprehensive metrics", inputSchema: { type: "object", properties: { tool_name: { type: "string", description: "Name of the AI tool that performed the activity (e.g., 'Warp', 'Claude Code', 'GitHub Copilot')" }, log_message: { type: "string", description: "Detailed log message describing what was accomplished" }, ai_model: { type: "string", description: "AI model used (e.g., 'gemini-2.5-pro', 'claude-3-sonnet', 'gpt-4')" }, tokens_used: { type: "number", description: "Total tokens consumed in the request (optional)" }, input_tokens: { type: "number", description: "Input tokens used (optional)" }, output_tokens: { type: "number", description: "Output tokens generated (optional)" }, context_length: { type: "number", description: "Context window length used (optional)" }, duration_ms: { type: "number", description: "Duration of the operation in milliseconds (optional)" }, cost_usd: { type: "number", description: "Estimated cost in USD (optional)" }, success: { type: "boolean", description: "Whether the operation was successful (optional, defaults to true)" }, error_message: { type: "string", description: "Error message if operation failed (optional)" }, tags: { type: "array", items: { type: "string" }, description: "Tags to categorize the activity (e.g., ['coding', 'debugging', 'refactoring']) (optional)" } }, required: ["tool_name", "log_message"] } } ] };

Other Tools

Related Tools

Latest Blog Posts

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/nocoo/mcp-work-history'

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