Skip to main content
Glama
8bitgentleman

ActivityWatch MCP Server

activitywatch_get_events

Retrieve raw time tracking events from ActivityWatch buckets to analyze application usage, browsing history, and productivity patterns with customizable date ranges and limits.

Instructions

Get raw events from an ActivityWatch bucket

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
bucketIdYesID of the bucket to fetch events from
limitNoMaximum number of events to return (default: 100)
startNoStart date/time in ISO format (e.g. '2024-02-01T00:00:00Z')
endNoEnd date/time in ISO format (e.g. '2024-02-28T23:59:59Z')

Implementation Reference

  • The main handler function that fetches raw events from an ActivityWatch bucket via the API, constructs query params, makes axios GET request, returns JSON data or detailed error messages.
      handler: async (args: { bucketId: string; limit?: number; start?: string; end?: string }) => {
        try {
          // Construct query parameters
          const params: Record<string, string> = {};
          
          if (args.limit) {
            params.limit = String(args.limit);
          }
          
          if (args.start) {
            params.start = args.start;
          }
          
          if (args.end) {
            params.end = args.end;
          }
          
          // Build query string
          const queryString = Object.entries(params)
            .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
            .join('&');
          
          const url = `${AW_API_BASE}/buckets/${encodeURIComponent(args.bucketId)}/events${queryString ? `?${queryString}` : ''}`;
          
          console.error(`Fetching events from: ${url}`);
          
          // Make the request
          const response = await axios.get(url);
          
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(response.data, null, 2)
              }
            ]
          };
        } catch (error) {
          console.error("Error in raw events tool:", error);
          
          // Check if the error is an Axios error with a response property
          if (axios.isAxiosError(error) && error.response) {
            const statusCode = error.response.status;
            let errorMessage = `Failed to fetch events: ${error.message} (Status code: ${statusCode})`;
            
            // Include response data if available
            if (error.response.data) {
              const errorDetails = typeof error.response.data === 'object'
                ? JSON.stringify(error.response.data)
                : String(error.response.data);
              errorMessage += `\nDetails: ${errorDetails}`;
            }
            
            // Special handling for 404 errors - likely bucket not found
            if (statusCode === 404) {
              errorMessage = `Bucket not found: ${args.bucketId}
              
    Please check that you've entered the correct bucket ID. You can get a list of available buckets using the activitywatch_list_buckets tool.
    `;
            }
            
            return {
              content: [{ type: "text", text: errorMessage }],
              isError: true
            };
          } 
          // Handle network errors or other axios errors without response
          else if (axios.isAxiosError(error)) {
            const errorMessage = `Failed to fetch events: ${error.message}
    
    This appears to be a network or connection error. Please check:
    - The ActivityWatch server is running
    - The API base URL is correct (currently: ${AW_API_BASE})
    - No firewall or network issues are blocking the connection
    `;
            return {
              content: [{ type: "text", text: errorMessage }],
              isError: true
            };
          } 
          // Handle non-axios errors
          else if (error instanceof Error) {
            return {
              content: [{ type: "text", text: `Failed to fetch events: ${error.message}` }],
              isError: true
            };
          } 
          // Fallback for unknown errors
          else {
            return {
              content: [{ type: "text", text: "Failed to fetch events: Unknown error" }],
              isError: true
            };
          }
        }
      }
  • Input schema defining the tool parameters: required bucketId (string), optional limit (number), start and end (ISO strings).
    const inputSchema = {
      type: "object",
      properties: {
        bucketId: {
          type: "string",
          description: "ID of the bucket to fetch events from"
        },
        limit: {
          type: "number",
          description: "Maximum number of events to return (default: 100)"
        },
        start: {
          type: "string",
          description: "Start date/time in ISO format (e.g. '2024-02-01T00:00:00Z')"
        },
        end: {
          type: "string",
          description: "End date/time in ISO format (e.g. '2024-02-28T23:59:59Z')"
        }
      },
      required: ["bucketId"]
    };
  • src/index.ts:59-63 (registration)
    Tool registration in the ListToolsRequestHandler, exposing name, description, and inputSchema to MCP clients.
    {
      name: activitywatch_get_events_tool.name,
      description: activitywatch_get_events_tool.description,
      inputSchema: activitywatch_get_events_tool.inputSchema
    },
  • src/index.ts:248-265 (registration)
    Dispatch and argument validation logic in the CallToolRequestHandler that routes requests to the tool's handler.
    } else if (request.params.name === activitywatch_get_events_tool.name) {
      // For the raw events tool
      if (!args.bucketId || typeof args.bucketId !== 'string') {
        return makeSafeToolResponse(() => ({
          content: [{
            type: "text",
            text: "Error: Missing required parameter 'bucketId' (must be a string)"
          }],
          isError: true
        }))();
      }
      
      return makeSafeToolResponse(activitywatch_get_events_tool.handler)({
        bucketId: args.bucketId,
        limit: typeof args.limit === 'number' ? args.limit : undefined,
        start: typeof args.start === 'string' ? args.start : undefined,
        end: typeof args.end === 'string' ? args.end : undefined
      });
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure but offers minimal information. It doesn't mention whether this is a read-only operation, if it requires authentication, potential rate limits, error conditions, or what format the 'raw events' are returned in. The description is functionally adequate but lacks important operational context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise - a single sentence that communicates the essential purpose without any wasted words. It's front-loaded with the core functionality and doesn't include unnecessary elaboration, making it efficient for quick understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 4 parameters, no annotations, and no output schema, the description is insufficiently complete. It doesn't explain what 'raw events' means in terms of data structure, doesn't mention any limitations or constraints, and provides no context about the ActivityWatch system. The agent would need to guess about the return format and operational characteristics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the input schema already documents all 4 parameters thoroughly. The description adds no additional parameter information beyond what's in the schema, so it meets the baseline expectation but doesn't provide extra value regarding parameter usage or semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Get raw events') and resource ('from an ActivityWatch bucket'), making the purpose immediately understandable. However, it doesn't differentiate this tool from sibling tools like 'activitywatch_query_examples' or 'activitywatch_run_query', which might also retrieve event data but with different approaches or formats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With sibling tools like 'activitywatch_query_examples' and 'activitywatch_run_query' that might serve similar purposes, there's no indication of when this raw event retrieval is preferred over those query-based approaches, leaving the agent without context for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/8bitgentleman/activitywatch-mcp-server'

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