ActivityWatch MCP Server
import axios, { AxiosError } from 'axios';
const AW_API_BASE = "http://localhost:5600/api/0";
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"]
};
export const activitywatch_get_events_tool = {
name: "activitywatch_get_events",
description: "Get raw events from an ActivityWatch bucket",
inputSchema: inputSchema,
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
};
}
}
}
};