npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

toggl-focus-mcp

v1.0.2

Published

MCP server for Toggl Focus (2.0) — API-key auth, curated tools for Claude, Cursor, and Codex

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

  1. A Toggl Focus / 2.0 API key (toggl_sk_…) — shown once when created
  2. Your organization ID and workspace ID (strongly recommended)
  3. 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_ids on POST. The tool creates the project first, then PATCHes tags; on failure you still get the project plus a warning.
  • 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.

  1. Copy .env.example → .env and set your Focus key + org/workspace IDs
  2. 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

License

MIT