toggl-focus-mcp
MCP server for Toggl Focus 2.0, enabling project, task, and time-entry management with live timer control through natural language.
README
toggl-focus-mcp
MCP server for Toggl Focus (2.0) — not Toggl Track 1.0.
Connect Claude, Cursor, Codex, or OpenCode to your Focus workspace with a Bearer API key (toggl_sk_…) and npx. No OAuth browser flow required.
npx -y toggl-focus-mcp
| Auth | Focus Bearer API key (Authorization: Bearer toggl_sk_…) |
| API | https://focus.toggl.com/api |
| Transport | stdio MCP |
| Node | ≥ 20 (CI / .nvmrc → latest Current) |
Track “API Token” values (Basic Auth / profile token for Track) do not work. Create a Focus / Toggl 2.0 key in settings. Official OAuth MCP:
@togglhq/mcp.
Prerequisites
- A Toggl Focus / 2.0 API key (
toggl_sk_…) — shown once when created - Your organization ID and workspace ID (strongly recommended)
- Node.js 20+ (for
npx)
Find org/workspace IDs in the Focus URL, e.g.
https://focus.toggl.com/.../organizations/21504582/workspaces/21503801/...
Setting both IDs avoids extra discovery calls and protects against Focus hourly quota limits.
Environment variables
| Variable | Required | Description |
|---|---|---|
TOGGL_FOCUS_API_TOKEN |
Yes* | Focus API key (toggl_sk_…) |
TOGGL_API_KEY |
Yes* | Alias for the Focus API key |
TOGGL_API_TOKEN |
Yes* | Additional alias |
TOGGL_ORGANIZATION_ID |
Recommended | Default organization ID |
TOGGL_WORKSPACE_ID |
Recommended | Default workspace ID |
TOGGL_FOCUS_BASE_URL |
No | API base (default https://focus.toggl.com/api) |
* Exactly one of TOGGL_FOCUS_API_TOKEN, TOGGL_API_KEY, or TOGGL_API_TOKEN is required.
Most tools accept optional organization_id / workspace_id arguments that override the env defaults for that call.
Install
Replace toggl_sk_..., 123, and 456 with your real key and IDs.
Claude Code
claude mcp add toggl-focus \
-e TOGGL_FOCUS_API_TOKEN=toggl_sk_... \
-e TOGGL_ORGANIZATION_ID=123 \
-e TOGGL_WORKSPACE_ID=456 \
-- npx -y toggl-focus-mcp
Verify:
claude mcp list
Claude Desktop
Edit claude_desktop_config.json, then restart Claude Desktop.
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"toggl-focus": {
"command": "npx",
"args": ["-y", "toggl-focus-mcp"],
"env": {
"TOGGL_FOCUS_API_TOKEN": "toggl_sk_...",
"TOGGL_ORGANIZATION_ID": "123",
"TOGGL_WORKSPACE_ID": "456"
}
}
}
}
Cursor
Add to project .cursor/mcp.json or your global Cursor MCP settings:
{
"mcpServers": {
"toggl-focus": {
"command": "npx",
"args": ["-y", "toggl-focus-mcp"],
"env": {
"TOGGL_FOCUS_API_TOKEN": "toggl_sk_...",
"TOGGL_ORGANIZATION_ID": "123",
"TOGGL_WORKSPACE_ID": "456"
}
}
}
}
Enable the server in Cursor Settings → MCP, then confirm tools like focus_whoami appear.
Codex
CLI (recommended):
codex mcp add toggl-focus \
--env TOGGL_FOCUS_API_TOKEN=toggl_sk_... \
--env TOGGL_ORGANIZATION_ID=123 \
--env TOGGL_WORKSPACE_ID=456 \
-- npx -y toggl-focus-mcp
Or edit ~/.codex/config.toml (or project .codex/config.toml in a trusted repo):
[mcp_servers.toggl-focus]
command = "npx"
args = ["-y", "toggl-focus-mcp"]
[mcp_servers.toggl-focus.env]
TOGGL_FOCUS_API_TOKEN = "toggl_sk_..."
TOGGL_ORGANIZATION_ID = "123"
TOGGL_WORKSPACE_ID = "456"
To keep secrets out of the file, set them in your shell and forward by name:
[mcp_servers.toggl-focus]
command = "npx"
args = ["-y", "toggl-focus-mcp"]
env_vars = ["TOGGL_FOCUS_API_TOKEN", "TOGGL_ORGANIZATION_ID", "TOGGL_WORKSPACE_ID"]
Shared across Codex CLI, IDE extension, and ChatGPT desktop Codex host. Docs: developers.openai.com/codex/mcp.
OpenCode
Add to opencode.json / opencode.jsonc (project or global):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"toggl-focus": {
"type": "local",
"command": ["npx", "-y", "toggl-focus-mcp"],
"enabled": true,
"environment": {
"TOGGL_FOCUS_API_TOKEN": "toggl_sk_...",
"TOGGL_ORGANIZATION_ID": "123",
"TOGGL_WORKSPACE_ID": "456"
}
}
}
}
You can also reference shell env vars with OpenCode’s {env:VAR} syntax where supported. Docs: opencode.ai/docs/mcp-servers.
Quick start prompts
Once the server is connected, try:
- “Who am I in Toggl Focus?”
- “List my projects”
- “Start a timer on project X”
- “Create a task called Ship MCP docs on project Y”
- “Show time entries for this week”
Creates, updates, deletes, and timer start/stop apply immediately (no confirmation token).
Tools
24 tools. All are Focus/2.0 only. Shared optional args on almost every tool:
| Arg | Type | Notes |
|---|---|---|
organization_id |
number | Overrides TOGGL_ORGANIZATION_ID |
workspace_id |
number | Overrides TOGGL_WORKSPACE_ID |
page |
number | Default 1 (list tools) |
per_page |
number | Default 50, max 100 (list tools) |
Account & context
focus_whoami
Account metadata + user settings for the authenticated Focus key.
| Arg | Type | Required | Description |
|---|---|---|---|
include_settings |
boolean | No | Default true — also fetch GET /users/me/settings |
organization_id / workspace_id |
number | No | Optional scope |
focus_get_workspace_context
Resolve and cache organization_id / workspace_id for later tools. Prefer setting both env vars. Does not call the session-only /workspaces/{id}/context endpoint (that returns 403 for API keys).
focus_list_org_users
List organization users (assignee lookup). Read-only.
| Arg | Type | Required | Description |
|---|---|---|---|
filter |
string | No | Search name/email |
active_status |
string | No | Active-status filter when supported |
page / per_page |
number | No | Pagination |
Projects
focus_list_projects
List workspace projects.
| Arg | Type | Description |
|---|---|---|
name |
string | Filter by project or client name |
archived / completed / pinned |
boolean | Status filters |
client_id |
number[] | Filter by client IDs |
tag_id |
number[] | Filter by tag IDs |
focus_get_project
| Arg | Type | Required |
|---|---|---|
project_id |
number | Yes |
focus_create_project
Creates immediately. Requires name.
| Arg | Type | Description |
|---|---|---|
name |
string | Required |
description |
string | |
client_id |
number | Supported on create |
color |
string | |
private / pinned / billable |
boolean | |
start_date / end_date |
string | YYYY-MM-DD |
tag_ids |
number[] | Applied via follow-up PATCH; may be forbidden on some plans/roles — project still creates and a warning is returned |
parent_project_id |
number |
focus_update_project
Partial update (PATCH). Requires project_id. Same optional fields as create, plus nullable client_id and optional archived.
Tasks
focus_list_tasks
| Arg | Type | Description |
|---|---|---|
name |
string | Name filter |
project_id |
number[] | Project IDs |
status_id |
number[] | Status IDs |
assignee_user_id |
number[] | Assignees |
tag_id |
number[] | Tags |
pinned / archived |
boolean | |
parent_task_id |
number[] | Parent tasks |
include_assignees |
boolean | Expand assignees |
focus_get_task
Requires task_id. Optional include_assignees.
focus_create_task
Creates immediately. Requires name.
| Arg | Type | Description |
|---|---|---|
name |
string | Required |
description / notes |
string | |
project_id / parent_task_id / status_id |
number | |
assignee_user_ids / tag_ids |
number[] | |
estimated_mins |
number | |
priority |
"none" | "low" | "medium" | "high" |
|
pinned / private / billable |
boolean | |
start_date / end_date |
string | YYYY-MM-DD |
focus_update_task
Partial update. Requires task_id. Same mutable fields as create (all optional).
Live tracking
focus_get_current_timer
Returns the running timer for the workspace, or { "running": false }.
focus_start_timer
Starts immediately. type defaults to "activity".
| Arg | Type | Description |
|---|---|---|
type |
"activity" | "break" |
Default activity |
task_id / project_id |
number | |
description |
string | |
billable |
boolean | |
tag_ids |
number[] | |
time_block_id |
number | |
start |
string | RFC3339; server default = now |
focus_stop_timer
Stops the running timer. Optional end (RFC3339); defaults to current UTC.
Time entries
focus_list_time_entries
Requires a date range. Accepts YYYY-MM-DD or RFC3339 (YYYY-MM-DD is expanded to start/end of day UTC).
| Arg | Type | Required | Description |
|---|---|---|---|
date_from |
string | Yes | Range start |
date_to |
string | Yes | Range end |
task_id |
number | No | |
type |
"activity" | "break" |
No | |
archived / include_taskless |
boolean | No | |
time_block_id |
number | No |
focus_create_time_entry
Creates a completed entry immediately. If task_id is set, uses the task-scoped endpoint; otherwise creates a taskless entry. type defaults to "activity".
| Arg | Type | Description |
|---|---|---|
task_id / project_id |
number | |
description |
string | |
start |
string | RFC3339 |
duration |
number | Seconds |
billable |
boolean | |
tag_ids |
number[] | |
time_block_id |
number | |
type |
"activity" | "break" |
focus_update_time_entry
Partial update. Requires time_entry_id. Optional task_id selects the task-scoped path.
focus_delete_time_entry
Deletes immediately. Requires time_entry_id. Optional task_id for the task-scoped path.
Clients
focus_list_clients
Optional name filter plus pagination.
focus_create_client
Requires name. Optional currency (ISO 4217).
Tags
focus_list_tags
Optional name, tag_id (array), pagination.
focus_create_tag
Requires name and color (hex or Focus color token).
Statuses & search
focus_list_statuses
List task statuses. Optional name, type, pagination.
focus_search
Unified search across time entries, tasks, and projects.
| Arg | Type | Required | Description |
|---|---|---|---|
keyword |
string | Yes | Search text |
per_group |
number | No | Results per group |
project_id / task_id |
number | No | Scope |
only_me / include_drafts |
boolean | No |
Behavior notes
- Mutations are immediate — create / update / delete / start / stop have no confirmation step.
- Project tags on create — some Focus plans/roles reject
tag_idsonPOST. The tool creates the project first, then PATCHes tags; on failure you still get the project plus awarning. - Workspace context — session cookie endpoints are not used; set org + workspace env vars.
- Quota — Focus enforces per-user-per-org hourly limits (e.g. Free ~30/hour). HTTP 402 means quota exhausted; wait for
X-Toggl-Quota-Resets-In. Prefer env IDs so tools do not rediscover context every call.
Development
git clone https://github.com/copperline-ai/toggl-focus-mcp.git
cd toggl-focus-mcp
npm install
npm run check # typecheck + unit/mocked MCP tests + build (CI gate)
npm run test:live # optional — real Focus API; local only, needs .env
node dist/index.js
npm run check is the same gate used by GitHub Actions on PRs and before publish. It uses mocked Focus responses — CI never calls your real Toggl account.
Live MCP tests (local only)
Optional suite against a real Focus workspace. Not run in CI.
- Copy
.env.example→.envand set your Focus key + org/workspace IDs - Run:
npm run test:live
Reuses stable fixtures (client Toggl Focus, project Toggl Focus MCP, task MCP live test, tag MCP live). Disposable time entries are deleted. Paces ~1 req/sec for rate limits. .env is gitignored and not published.
Publishing
Releases use release-it + AI Gateway (semver bump, changelog, GitHub Release, npm publish):
npm run release:dry-run
npm pack --dry-run
CI secrets: NPM_ACCESS_TOKEN, AI_GATEWAY_API_KEY.
Vendored OpenAPI: openapi/focus.json from Focus OpenAPI.
Related
- Focus docs: engineering.toggl.com/docs/focus
- Focus auth: Bearer API keys
- Official OAuth MCP:
@togglhq/mcp
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.