@souravpn/toggl-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # toggl-mcp
2
+
3
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gives Claude access to your [Toggl Track](https://toggl.com/track/) time tracking data.
4
+
5
+ Ask Claude things like:
6
+ - *"What am I tracking right now?"*
7
+ - *"How much time did I spend on each project this week?"*
8
+ - *"Start a timer for writing documentation on the Blog project"*
9
+ - *"Stop my timer"*
10
+ - *"What did I work on yesterday?"*
11
+
12
+ ---
13
+
14
+ ## Tools
15
+
16
+ | Tool | What it does |
17
+ |------|-------------|
18
+ | `get_current_timer` | Shows the currently running time entry |
19
+ | `get_recent_entries` | Time entries for the past N days (default 7) |
20
+ | `get_projects` | Lists all your projects |
21
+ | `get_summary` | Total time by project for a date range |
22
+ | `start_timer` | Starts a new time entry |
23
+ | `stop_timer` | Stops the current timer |
24
+ | `get_profile` | Your Toggl profile and workspaces |
25
+
26
+ ---
27
+
28
+ ## Setup
29
+
30
+ ### 1. Get your API token
31
+
32
+ 1. Go to **https://track.toggl.com/profile**
33
+ 2. Scroll to the bottom
34
+ 3. Click **"Click to reveal"** under API Token
35
+ 4. Copy the token
36
+
37
+ ### 2. Install
38
+
39
+ ```bash
40
+ npm install -g toggl-mcp
41
+ ```
42
+
43
+ Find the installed path:
44
+ ```bash
45
+ which toggl-mcp
46
+ ```
47
+
48
+ ### 3. Add to Claude Desktop
49
+
50
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "toggl": {
56
+ "command": "/path/from/which/toggl-mcp",
57
+ "env": {
58
+ "TOGGL_API_TOKEN": "your_token_here"
59
+ }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ Or if running from source:
66
+
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "toggl": {
71
+ "command": "node",
72
+ "args": ["/path/to/toggl-mcp/dist/index.js"],
73
+ "env": {
74
+ "TOGGL_API_TOKEN": "your_token_here"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ Restart Claude Desktop. You should see a green "running" badge in **Settings → Developer**.
82
+
83
+ ### 4. Test it
84
+
85
+ ```
86
+ What am I currently tracking in Toggl?
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Example queries
92
+
93
+ **Daily check-in:**
94
+ ```
95
+ What have I tracked today in Toggl?
96
+ ```
97
+
98
+ **Weekly review:**
99
+ ```
100
+ Give me a summary of how I spent my time this week by project
101
+ ```
102
+
103
+ **Start tracking:**
104
+ ```
105
+ Start a Toggl timer for "reviewing PRs" on my Engineering project
106
+ ```
107
+
108
+ **Stop and summarize:**
109
+ ```
110
+ Stop my timer and tell me how long I worked
111
+ ```
112
+
113
+ **Productivity analysis:**
114
+ ```
115
+ How much time did I track last week vs the week before?
116
+ Which project took the most time?
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Development
122
+
123
+ ```bash
124
+ git clone https://github.com/yourusername/toggl-mcp
125
+ cd toggl-mcp
126
+ npm install
127
+ npm run build
128
+
129
+ # Test locally
130
+ TOGGL_API_TOKEN=your_token node dist/index.js
131
+ ```
132
+
133
+ ### Project structure
134
+
135
+ ```
136
+ toggl-mcp/
137
+ ├── src/
138
+ │ ├── index.ts # MCP server + tool definitions
139
+ │ └── toggl.ts # Toggl API v9 client + formatters
140
+ ├── package.json
141
+ ├── tsconfig.json
142
+ └── README.md
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Rate limits
148
+
149
+ Toggl's free plan allows 30 requests/hour per workspace. This MCP server batches calls where possible (e.g. fetching projects and entries in parallel) to stay well within limits for normal use.
150
+
151
+ ---
152
+
153
+ ## Contributing
154
+
155
+ PRs welcome. Ideas for extension:
156
+ - Tags management
157
+ - Client listing
158
+ - Detailed reports (daily breakdown)
159
+ - Time entry editing
160
+
161
+ ---
162
+
163
+ ## License
164
+
165
+ MIT
166
+
167
+ ---
168
+
169
+ ## Acknowledgements
170
+
171
+ Built with the [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) and the [Toggl Track API v9](https://engineering.toggl.com/docs/track/).
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+ // =============================================================================
3
+ // index.ts — toggl-mcp server
4
+ //
5
+ // Exposes Toggl Track data as MCP tools Claude can call.
6
+ //
7
+ // TOOLS:
8
+ // get_current_timer — what you're tracking right now
9
+ // get_recent_entries — time entries for the past N days
10
+ // get_projects — list all your projects
11
+ // get_summary — total time by project for a date range
12
+ // start_timer — start tracking time on a description/project
13
+ // stop_timer — stop the currently running timer
14
+ // get_profile — your Toggl profile and workspace info
15
+ //
16
+ // AUTH:
17
+ // Set TOGGL_API_TOKEN env variable.
18
+ // Get it from https://track.toggl.com/profile → scroll to bottom → API Token
19
+ //
20
+ // USAGE IN claude_desktop_config.json:
21
+ // {
22
+ // "mcpServers": {
23
+ // "toggl": {
24
+ // "command": "node",
25
+ // "args": ["/path/to/toggl-mcp/dist/index.js"],
26
+ // "env": { "TOGGL_API_TOKEN": "your_token" }
27
+ // }
28
+ // }
29
+ // }
30
+ // =============================================================================
31
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
32
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
33
+ import { z } from 'zod';
34
+ import { TogglClient, formatDuration, formatTimeEntry, isRunning, getActualDuration, } from './toggl.js';
35
+ // ---- Validate env -----------------------------------------------------------
36
+ const apiToken = process.env.TOGGL_API_TOKEN;
37
+ if (!apiToken) {
38
+ process.stderr.write('[toggl-mcp] Error: TOGGL_API_TOKEN is not set.\n' +
39
+ '[toggl-mcp] Get your token from https://track.toggl.com/profile\n');
40
+ process.exit(1);
41
+ }
42
+ const client = new TogglClient(apiToken);
43
+ // ---- MCP Server -------------------------------------------------------------
44
+ const server = new McpServer({
45
+ name: 'toggl',
46
+ version: '1.0.0',
47
+ });
48
+ // Helper — wraps tool handlers with consistent error handling
49
+ function safe(fn) {
50
+ return fn()
51
+ .then(text => ({ content: [{ type: 'text', text }] }))
52
+ .catch(err => ({
53
+ content: [{
54
+ type: 'text',
55
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
56
+ }],
57
+ }));
58
+ }
59
+ // ---- Tools ------------------------------------------------------------------
60
+ // 1. Current running timer
61
+ server.tool('get_current_timer', 'Get the currently running Toggl time entry, if any', {}, () => safe(async () => {
62
+ const entry = await client.getCurrentTimeEntry();
63
+ if (!entry)
64
+ return 'No timer is currently running.';
65
+ const wsId = await client.getDefaultWorkspaceId();
66
+ const projects = await client.getProjectMap(wsId);
67
+ return formatTimeEntry(entry, projects);
68
+ }));
69
+ // 2. Recent time entries
70
+ server.tool('get_recent_entries', 'Get time entries from the past N days (default 7). Useful for reviewing what you worked on.', {
71
+ days: z.number().min(1).max(90).default(7)
72
+ .describe('Number of days to look back (max 90)'),
73
+ }, ({ days }) => safe(async () => {
74
+ const [entries, wsId] = await Promise.all([
75
+ client.getRecentTimeEntries(days),
76
+ client.getDefaultWorkspaceId(),
77
+ ]);
78
+ const projects = await client.getProjectMap(wsId);
79
+ if (entries.length === 0)
80
+ return `No time entries found in the past ${days} days.`;
81
+ const lines = entries
82
+ .slice(0, 50) // cap at 50 to avoid context overflow
83
+ .map(e => formatTimeEntry(e, projects))
84
+ .join('\n\n---\n\n');
85
+ const totalSeconds = entries
86
+ .filter(e => !isRunning(e))
87
+ .reduce((sum, e) => sum + getActualDuration(e), 0);
88
+ return `${entries.length} entries in the past ${days} days\nTotal tracked: ${formatDuration(totalSeconds)}\n\n${'='.repeat(40)}\n\n${lines}`;
89
+ }));
90
+ // 3. List projects
91
+ server.tool('get_projects', 'List all Toggl projects in your workspace', {}, () => safe(async () => {
92
+ const wsId = await client.getDefaultWorkspaceId();
93
+ const projects = await client.getProjects(wsId);
94
+ if (projects.length === 0)
95
+ return 'No projects found. Create one at https://track.toggl.com';
96
+ const active = projects.filter(p => p.active);
97
+ const archived = projects.filter(p => !p.active);
98
+ const lines = [
99
+ `${active.length} active projects:`,
100
+ ...active.map(p => ` • ${p.name} (id: ${p.id})${p.billable ? ' 💰' : ''}`),
101
+ ];
102
+ if (archived.length > 0) {
103
+ lines.push(`\n${archived.length} archived projects (not shown)`);
104
+ }
105
+ return lines.join('\n');
106
+ }));
107
+ // 4. Summary by project
108
+ server.tool('get_summary', 'Get total time tracked per project for a date range. Defaults to the current week.', {
109
+ start_date: z.string().optional()
110
+ .describe('Start date in YYYY-MM-DD format (default: start of current week)'),
111
+ end_date: z.string().optional()
112
+ .describe('End date in YYYY-MM-DD format (default: today)'),
113
+ }, ({ start_date, end_date }) => safe(async () => {
114
+ const wsId = await client.getDefaultWorkspaceId();
115
+ // Default to current week
116
+ const now = new Date();
117
+ const startOfWeek = new Date(now);
118
+ startOfWeek.setDate(now.getDate() - now.getDay());
119
+ startOfWeek.setHours(0, 0, 0, 0);
120
+ const start = start_date ?? startOfWeek.toISOString().split('T')[0];
121
+ const end = end_date ?? now.toISOString().split('T')[0];
122
+ const summary = await client.getSummary(wsId, start, end);
123
+ if (summary.byProject.length === 0) {
124
+ return `No time tracked between ${start} and ${end}.`;
125
+ }
126
+ // Sort by most time first
127
+ const sorted = summary.byProject.sort((a, b) => b.seconds - a.seconds);
128
+ const lines = [
129
+ `Time summary: ${start} → ${end}`,
130
+ `Total: ${formatDuration(summary.totalSeconds)}`,
131
+ '',
132
+ ...sorted.map(p => {
133
+ const pct = ((p.seconds / summary.totalSeconds) * 100).toFixed(0);
134
+ return ` ${p.name}: ${formatDuration(p.seconds)} (${pct}%)`;
135
+ }),
136
+ ];
137
+ return lines.join('\n');
138
+ }));
139
+ // 5. Start a timer
140
+ server.tool('start_timer', 'Start a new Toggl time entry. Provide a description and optionally a project name.', {
141
+ description: z.string().describe('What you are working on'),
142
+ project_name: z.string().optional()
143
+ .describe('Project name to log time against (must match an existing project name exactly)'),
144
+ tags: z.array(z.string()).optional()
145
+ .describe('Optional tags to apply to this time entry'),
146
+ }, ({ description, project_name, tags }) => safe(async () => {
147
+ const wsId = await client.getDefaultWorkspaceId();
148
+ let projectId;
149
+ if (project_name) {
150
+ const projects = await client.getProjects(wsId);
151
+ const match = projects.find(p => p.name.toLowerCase() === project_name.toLowerCase() && p.active);
152
+ if (!match) {
153
+ const names = projects.filter(p => p.active).map(p => p.name).join(', ');
154
+ return `Project "${project_name}" not found. Available projects: ${names}`;
155
+ }
156
+ projectId = match.id;
157
+ }
158
+ const entry = await client.startTimer(wsId, description, projectId, tags);
159
+ const projects = await client.getProjectMap(wsId);
160
+ return `✅ Timer started!\n\n${formatTimeEntry(entry, projects)}`;
161
+ }));
162
+ // 6. Stop current timer
163
+ server.tool('stop_timer', 'Stop the currently running Toggl time entry', {}, () => safe(async () => {
164
+ const current = await client.getCurrentTimeEntry();
165
+ if (!current)
166
+ return 'No timer is currently running.';
167
+ const wsId = await client.getDefaultWorkspaceId();
168
+ const stopped = await client.stopTimer(wsId, current.id);
169
+ const projects = await client.getProjectMap(wsId);
170
+ return `⏹ Timer stopped!\n\n${formatTimeEntry(stopped, projects)}`;
171
+ }));
172
+ // 7. Profile
173
+ server.tool('get_profile', "Get the user's Toggl profile — name, email, timezone, and workspace info", {}, () => safe(async () => {
174
+ const [me, workspaces] = await Promise.all([
175
+ client.getMe(),
176
+ client.getWorkspaces(),
177
+ ]);
178
+ return [
179
+ `Name: ${me.fullname}`,
180
+ `Email: ${me.email}`,
181
+ `Timezone: ${me.timezone}`,
182
+ `Default workspace ID: ${me.default_workspace_id}`,
183
+ '',
184
+ `Workspaces (${workspaces.length}):`,
185
+ ...workspaces.map(w => ` • ${w.name} (id: ${w.id})${w.premium ? ' [Premium]' : ' [Free]'}`),
186
+ ].join('\n');
187
+ }));
188
+ // ---- Start ------------------------------------------------------------------
189
+ const transport = new StdioServerTransport();
190
+ await server.connect(transport);
191
+ process.stderr.write('[toggl-mcp] Server running\n');
192
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ export interface TogglUser {
2
+ id: number;
3
+ email: string;
4
+ fullname: string;
5
+ timezone: string;
6
+ default_workspace_id: number;
7
+ beginning_of_week: number;
8
+ }
9
+ export interface TogglWorkspace {
10
+ id: number;
11
+ name: string;
12
+ premium: boolean;
13
+ plan: string;
14
+ }
15
+ export interface TogglProject {
16
+ id: number;
17
+ name: string;
18
+ workspace_id: number;
19
+ color: string;
20
+ active: boolean;
21
+ billable: boolean | null;
22
+ client_id: number | null;
23
+ }
24
+ export interface TogglTag {
25
+ id: number;
26
+ name: string;
27
+ workspace_id: number;
28
+ }
29
+ export interface TogglTimeEntry {
30
+ id: number;
31
+ workspace_id: number;
32
+ project_id: number | null;
33
+ task_id: number | null;
34
+ billable: boolean;
35
+ start: string;
36
+ stop: string | null;
37
+ duration: number;
38
+ description: string | null;
39
+ tag_ids: number[];
40
+ tags: string[];
41
+ at: string;
42
+ }
43
+ export interface TogglClient {
44
+ id: number;
45
+ name: string;
46
+ workspace_id: number;
47
+ }
48
+ export declare function formatDuration(seconds: number): string;
49
+ export declare function formatDate(iso: string): string;
50
+ export declare function isRunning(entry: TogglTimeEntry): boolean;
51
+ export declare function getActualDuration(entry: TogglTimeEntry): number;
52
+ export declare function formatTimeEntry(entry: TogglTimeEntry, projects: Map<number, string>): string;
53
+ export declare class TogglClient {
54
+ private authHeader;
55
+ private _workspaceId;
56
+ constructor(apiToken: string);
57
+ private request;
58
+ getMe(): Promise<TogglUser>;
59
+ getWorkspaces(): Promise<TogglWorkspace[]>;
60
+ getDefaultWorkspaceId(): Promise<number>;
61
+ getProjects(workspaceId: number): Promise<TogglProject[]>;
62
+ getProjectMap(workspaceId: number): Promise<Map<number, string>>;
63
+ getTags(workspaceId: number): Promise<TogglTag[]>;
64
+ getCurrentTimeEntry(): Promise<TogglTimeEntry | null>;
65
+ getTimeEntries(startDate?: string, endDate?: string): Promise<TogglTimeEntry[]>;
66
+ getRecentTimeEntries(days?: number): Promise<TogglTimeEntry[]>;
67
+ startTimer(workspaceId: number, description: string, projectId?: number, tags?: string[]): Promise<TogglTimeEntry>;
68
+ stopTimer(workspaceId: number, entryId: number): Promise<TogglTimeEntry>;
69
+ getSummary(workspaceId: number, startDate: string, endDate: string): Promise<{
70
+ totalSeconds: number;
71
+ byProject: {
72
+ name: string;
73
+ seconds: number;
74
+ }[];
75
+ }>;
76
+ }
77
+ //# sourceMappingURL=toggl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggl.d.ts","sourceRoot":"","sources":["../src/toggl.ts"],"names":[],"mappings":"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"}
package/dist/toggl.js ADDED
@@ -0,0 +1,170 @@
1
+ // =============================================================================
2
+ // toggl.ts — Toggl Track API v9 client
3
+ //
4
+ // Auth: HTTP Basic — API token as username, "api_token" as password
5
+ // Base URL: https://api.track.toggl.com/api/v9
6
+ //
7
+ // API docs: https://engineering.toggl.com/docs/track/
8
+ // =============================================================================
9
+ const BASE_URL = 'https://api.track.toggl.com/api/v9';
10
+ const REPORTS_URL = 'https://api.track.toggl.com/reports/api/v3';
11
+ // ---- Helpers ----------------------------------------------------------------
12
+ export function formatDuration(seconds) {
13
+ if (seconds < 0)
14
+ return 'Running...';
15
+ const h = Math.floor(seconds / 3600);
16
+ const m = Math.floor((seconds % 3600) / 60);
17
+ const s = seconds % 60;
18
+ if (h > 0)
19
+ return `${h}h ${m}m`;
20
+ if (m > 0)
21
+ return `${m}m ${s}s`;
22
+ return `${s}s`;
23
+ }
24
+ export function formatDate(iso) {
25
+ return new Date(iso).toLocaleString();
26
+ }
27
+ export function isRunning(entry) {
28
+ return entry.duration < 0;
29
+ }
30
+ export function getActualDuration(entry) {
31
+ if (entry.duration >= 0)
32
+ return entry.duration;
33
+ // Running entry: duration = -(start time in epoch seconds)
34
+ return Math.floor(Date.now() / 1000) + entry.duration;
35
+ }
36
+ export function formatTimeEntry(entry, projects) {
37
+ const running = isRunning(entry);
38
+ const duration = getActualDuration(entry);
39
+ const projectName = entry.project_id
40
+ ? (projects.get(entry.project_id) ?? `Project #${entry.project_id}`)
41
+ : 'No project';
42
+ return [
43
+ `${running ? '▶ [RUNNING] ' : ''}${entry.description ?? '(no description)'}`,
44
+ `Project: ${projectName}`,
45
+ `Duration: ${formatDuration(duration)}${running ? ' (so far)' : ''}`,
46
+ `Started: ${formatDate(entry.start)}`,
47
+ entry.stop ? `Stopped: ${formatDate(entry.stop)}` : null,
48
+ entry.tags.length > 0 ? `Tags: ${entry.tags.join(', ')}` : null,
49
+ entry.billable ? `Billable: Yes` : null,
50
+ ].filter(Boolean).join('\n');
51
+ }
52
+ // ---- API Client -------------------------------------------------------------
53
+ export class TogglClient {
54
+ authHeader;
55
+ _workspaceId = null;
56
+ constructor(apiToken) {
57
+ // Toggl auth: base64(token:api_token)
58
+ this.authHeader = 'Basic ' + Buffer.from(`${apiToken}:api_token`).toString('base64');
59
+ }
60
+ async request(path, options = {}, baseUrl = BASE_URL) {
61
+ const url = `${baseUrl}${path}`;
62
+ const response = await fetch(url, {
63
+ ...options,
64
+ headers: {
65
+ Authorization: this.authHeader,
66
+ 'Content-Type': 'application/json',
67
+ ...options.headers,
68
+ },
69
+ });
70
+ if (!response.ok) {
71
+ const body = await response.text();
72
+ throw new Error(`Toggl API error ${response.status} on ${path}: ${body}`);
73
+ }
74
+ // 204 No Content
75
+ if (response.status === 204)
76
+ return null;
77
+ return response.json();
78
+ }
79
+ // ---- User & Workspace ----
80
+ async getMe() {
81
+ return this.request('/me');
82
+ }
83
+ async getWorkspaces() {
84
+ return this.request('/workspaces');
85
+ }
86
+ // Get default workspace ID (cached)
87
+ async getDefaultWorkspaceId() {
88
+ if (this._workspaceId)
89
+ return this._workspaceId;
90
+ const me = await this.getMe();
91
+ this._workspaceId = me.default_workspace_id;
92
+ return this._workspaceId;
93
+ }
94
+ // ---- Projects ----
95
+ async getProjects(workspaceId) {
96
+ const projects = await this.request(`/workspaces/${workspaceId}/projects`);
97
+ return projects ?? [];
98
+ }
99
+ async getProjectMap(workspaceId) {
100
+ const projects = await this.getProjects(workspaceId);
101
+ return new Map(projects.map(p => [p.id, p.name]));
102
+ }
103
+ // ---- Tags ----
104
+ async getTags(workspaceId) {
105
+ const tags = await this.request(`/workspaces/${workspaceId}/tags`);
106
+ return tags ?? [];
107
+ }
108
+ // ---- Time Entries ----
109
+ async getCurrentTimeEntry() {
110
+ try {
111
+ return await this.request('/me/time_entries/current');
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ async getTimeEntries(startDate, endDate) {
118
+ const params = new URLSearchParams();
119
+ if (startDate)
120
+ params.set('start_date', startDate);
121
+ if (endDate)
122
+ params.set('end_date', endDate);
123
+ const query = params.toString() ? `?${params}` : '';
124
+ const entries = await this.request(`/me/time_entries${query}`);
125
+ return entries ?? [];
126
+ }
127
+ async getRecentTimeEntries(days = 7) {
128
+ const start = new Date();
129
+ start.setDate(start.getDate() - days);
130
+ return this.getTimeEntries(start.toISOString());
131
+ }
132
+ // ---- Start / Stop ----
133
+ async startTimer(workspaceId, description, projectId, tags) {
134
+ return this.request(`/workspaces/${workspaceId}/time_entries`, {
135
+ method: 'POST',
136
+ body: JSON.stringify({
137
+ created_with: 'toggl-mcp',
138
+ description,
139
+ project_id: projectId ?? null,
140
+ tags: tags ?? [],
141
+ start: new Date().toISOString(),
142
+ duration: -1, // -1 means running
143
+ workspace_id: workspaceId,
144
+ }),
145
+ });
146
+ }
147
+ async stopTimer(workspaceId, entryId) {
148
+ return this.request(`/workspaces/${workspaceId}/time_entries/${entryId}/stop`, { method: 'PATCH' });
149
+ }
150
+ // ---- Summary / Reports ----
151
+ async getSummary(workspaceId, startDate, endDate) {
152
+ // Use the reports API for aggregated data
153
+ const body = await this.request(`/workspace/${workspaceId}/summary/time_entries`, {
154
+ method: 'POST',
155
+ body: JSON.stringify({
156
+ start_date: startDate.split('T')[0], // reports API wants YYYY-MM-DD
157
+ end_date: endDate.split('T')[0],
158
+ grouping: 'projects',
159
+ sub_grouping: 'time_entries',
160
+ }),
161
+ }, REPORTS_URL);
162
+ const byProject = (body.groups ?? []).map(g => ({
163
+ name: g.title.project ?? 'No project',
164
+ seconds: g.sub_groups.reduce((sum, sg) => sum + sg.seconds, 0),
165
+ }));
166
+ const totalSeconds = byProject.reduce((sum, p) => sum + p.seconds, 0);
167
+ return { totalSeconds, byProject };
168
+ }
169
+ }
170
+ //# sourceMappingURL=toggl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggl.js","sourceRoot":"","sources":["../src/toggl.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@souravpn/toggl-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Toggl Track — gives Claude access to your time tracking data",
5
+ "keywords": [
6
+ "mcp",
7
+ "toggl",
8
+ "time-tracking",
9
+ "productivity",
10
+ "claude",
11
+ "ai"
12
+ ],
13
+ "author": "Sourav Nayak",
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "bin": {
17
+ "toggl-mcp": "./dist/index.js"
18
+ },
19
+ "main": "./dist/index.js",
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "dev": "tsc --watch",
26
+ "start": "node dist/index.js",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.10.0",
31
+ "zod": "^3.23.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.0.0",
35
+ "typescript": "^5.4.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "mcpName": "io.github.souravpn/toggl-mcp",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/souravpn/toggl-mcp.git"
44
+ }
45
+ }