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

@hazem.hashad/toggl-mcp

v1.5.15

Published

Toggl Focus MCP server — @toggl/mcp on npm, @toggl/mcp-internal on GitHub Packages

Readme

Toggl Focus MCP Server

A local MCP (Model Context Protocol) server that connects to the Toggl Focus API. Works with any MCP client including Claude Code and Claude Desktop. Exposes generated entity-domain tools (tasks, projects, time-blocks, time-entries, and related domains), workspace/auth tools, and Focus query artifacts from packages/focus-queries.

Published as @toggl/mcp. The public package will install from npmjs.org once the Toggl npm org is live; until then it may be available from GitHub Packages (see below).

Each GitHub release also includes per-platform .mcpb bundles (standalone executables; no Node.js on PATH) so users can install without registry access.

Install from npm (public, target)

npm install @toggl/mcp
# or: pnpm add @toggl/mcp

No GitHub Packages token is required once @toggl/mcp is published to npm.

Install from GitHub Packages (Toggl staff)

Internal builds publish as @toggl/mcp-internal. You need a GitHub token with read:packages and access to the Toggl org, or installs can return 404.

  1. Copy .npmrc.example into your project or ~/.npmrc and replace <GH_NPM_TOKEN> with a PAT.
  2. Install:
npm install @toggl/mcp-internal
# or: pnpm add @toggl/mcp-internal

Run the CLI (after install):

npx @toggl/mcp auth

For one-off runs without a local install: npx -y @toggl/mcp auth (still requires .npmrc with registry + token).

Install from GitHub Release (.mcpb)

If you do not have access to the private package registry, install from the release bundle instead:

  1. Open the latest GitHub release.

  2. Download the .mcpb for your OS and CPU (and the matching .sha256 if you verify checksums):

    • Apple Silicon macOS: toggl-focus-mcp-<version>-darwin-arm64.mcpb
    • Intel macOS: toggl-focus-mcp-<version>-darwin-x64.mcpb
    • Linux x64: toggl-focus-mcp-<version>-linux-x64.mcpb
    • Windows x64: toggl-focus-mcp-<version>-win32-x64.mcpb
  3. Open the .mcpb file in a compatible MCP client (for example, Claude Desktop) to install.

These bundles embed a compiled server and do not require Node.js or @toggl/mcp registry access.

For development or debugging you can still package a Node-based MCPB (requires end users to have Node 20+): pnpm run build:mcpb:node from this package (outputs toggl-focus-mcp-<version>.mcpb).

Setup (from source)

git clone https://github.com/toggl/toggl-mcp.git
cd toggl-mcp
pnpm install
pnpm run build
node build/index.js auth

This will:

  1. Open your browser to sign in with your Toggl account
  2. Automatically discover your workspaces
  3. Let you select your workspace (if you have multiple)

Authentication uses OAuth2 with PKCE — no API keys or passwords are entered in the terminal. Access tokens refresh automatically (1-hour access token, 4-week refresh token).

Add to your MCP client

Claude Code

claude mcp add toggl-focus -- npx @toggl/mcp

Claude Desktop

Add to your Claude Desktop config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "toggl-focus": {
      "command": "node",
      "args": ["/absolute/path/to/toggl-mcp/build/index.js"]
    }
  }
}

Replace /absolute/path/to/toggl-mcp with the actual path to your clone, or use npx with command/args pointing at @toggl/mcp if installed from GitHub Packages (with .npmrc configured). Restart Claude Desktop to pick up the change.

Authentication

Uses OAuth2 with PKCE via the Toggl Accounts service. Credentials are stored in ~/.toggl/focus-tools.json (mode 0600). Access tokens refresh automatically — re-run npx @toggl/mcp auth only to switch workspaces or if your refresh token expires (after 4 weeks of inactivity).

Upgrading from an older version? Sessions previously stored at ~/.toggl-focus-mcp/config.json are still read automatically — no re-authentication needed.

Unified config vs legacy file: MCP logout (and config cleanup helpers) only remove credentials when there is a matching profile row under ~/.toggl/focus-tools.json with active.mcp set. If you authenticate solely via the legacy read shim and nothing was written to the unified file yet, logout may report that nothing was cleared—run npx @toggl/mcp auth once so tokens land in focus-tools.json, or remove the legacy file manually if you intend to discard that session.

Alternative: Environment Variables

For CI or headless environments where browser-based OAuth is not available:

claude mcp add toggl-focus \
  -s user \
  -e TOGGL_WORKSPACE_ID=<your-workspace-id> \
  -e TOGGL_API_TOKEN=<your-api-token> \
  -e TOGGL_ORGANIZATION_ID=<your-org-id> \
  -e TOGGL_USER_ID=<your-user-id> \
  -- npx @toggl/mcp

Tools

Entity tools

MCP exposes one tool per catalog entity domain — the tool id equals mcp.entityTool from @toggl/operations (for example tasks, projects, time-blocks, organization, org-invitations, shared-working-hours). Each tool accepts:

  • action (required) — discriminator for the operation
  • data (optional) — payload for that action
  • confirm_token (optional) — second step for mutating operations (see below)
  • dry_run (optional) — when true, validates data and returns { dry_run, operation, input } without calling the API (CLI --dry-run parity)

CLI bulk mutations are nested (toggl tasks bulk patch, etc.); MCP uses hyphenated action values such as bulk-patch on the same entity tools.

Mutation confirmation: mutating tools use a two-step flow. First call returns confirm_required with confirm_token; call the same tool again with confirm_token to execute once. dry_run: true skips execution and does not consume a token.

Tool inventory (full action list)

The server builds MCP instructions at startup from @toggl/operations, so clients always see the current domains and actions. CI checks durable inventory invariants in packages/mcp/src/__tests__/tool-inventory-invariants.test.ts instead of snapshotting the full generated action list.

Workspaces, profiles & auth

  • workspace-list — List cached workspaces; pass { "refresh": true } to refetch from Accounts first (CLI workspace list --refresh parity)
  • workspace-switch — Switch the active workspace for MCP
  • profile-list — List rows in ~/.toggl/focus-tools.json with MCP active flag (active.mcp)
  • profile-switch — Set active.mcp to an existing profile name (shared with CLI profiles)
  • profile-remove — Remove a profile row (shared storage; affects CLI too if it used that row). Same confirm_token two-step flow as entity mutations: first call returns confirm_required, second call passes confirm_token with the same profile_name.
  • auth — Authenticate the MCP server via OAuth
  • logout — Clear the current MCP active profile credentials

Agent-oriented guidance: skills/toggl-mcp/SKILL.md (bundled in the npm package under skills/).

Maintainers: regenerate Focus API coverage

pnpm run generate:focus-queries
pnpm run generate:focus-operations

Set GH_AUTH_TOKEN in packages/focus-queries/.env before generation (see packages/focus-queries/README.md). Querygen refreshes Focus request/type/schema artifacts first; the operations generator then exposes most generated endpoints to CLI/MCP by default, excluding internal, deprecated, unsafe, file-upload, and unsupported-signature endpoints blocklisted in packages/operations/src/focus/blocklist.ts.

Architecture

src/
├── index.ts                    # Entry point — CLI auth handler + MCP server bootstrap
├── instructions.ts             # MCP server instructions + tool inventory from @toggl/operations
├── auth.ts                     # OAuth2 PKCE auth flow, token refresh, config file management
├── client.ts                   # Re-export of @toggl/cli-core FocusClient
├── authenticated-client.ts
├── utils.ts                    # Date helpers (@toggl/stdlib + cli-core), markdown tables, MCP response helpers
├── runtime/
│   └── safety/                 # Mutation confirmation gate
└── tools/
    ├── generated-entity-tools.ts # Registers MCP entity tools from @toggl/operations
    ├── mcp-schema.ts
    ├── focus-tool-utils.ts
    ├── payload-helpers.ts
    └── workspace.ts            # Workspace/auth tools
packages/
├── cli-core/                   # Auth/config/token primitives and FocusClient
├── operations/                 # Shared operation catalog used by CLI and MCP
└── focus-queries/              # Querygen mirror for Focus API types, schemas, and requests

How it works

The server runs as a stdio MCP process. Claude Code spawns it as a subprocess and communicates via JSON-RPC over stdin/stdout (stderr is used for logging).

Startup flow:

  1. index.ts checks for the auth CLI argument — if present, runs the auth flow and exits.
  2. Otherwise, it loads credentials from ~/.toggl/focus-tools.json when available (falls back to ~/.toggl-focus-mcp/config.json for sessions created by older versions).
  3. Creates an auth-aware FocusClient proxy that resolves credentials lazily per tool call.
  4. Creates an McpServer and registers entity tools from @toggl/operations, plus workspace/auth tools.
  5. Connects via StdioServerTransport and waits for tool calls.

Environment configuration:

The server reads an optional .env file from the project root and defaults to production (focus.toggl.com). You can override URLs directly via TOGGL_FOCUS_API_URL and TOGGL_ACCOUNTS_API_URL environment variables.

Authentication details

The auth flow (auth.ts) uses OAuth2 Authorization Code with PKCE:

  1. Generates a PKCE code verifier and challenge (SHA-256, base64url).
  2. Starts a local HTTP callback server on localhost:8716.
  3. Opens the browser to accounts.toggl.com/focus/login/ with OAuth parameters.
  4. User logs in via the browser — the callback receives the authorization code.
  5. Exchanges the code for access + refresh tokens via POST /api/oauth/token.
  6. Fetches user info (GET /api/me) and workspaces (GET /org/api/organizations/me).
  7. Saves tokens and workspace info to ~/.toggl/focus-tools.json (mode 0600).

Token refresh happens automatically: before each API request, the client checks the access token's expiry and refreshes it if it expires within 60 seconds. The refresh token is valid for 4 weeks.

The stored config looks like:

{
  "access_token": "<OAuth access token>",
  "refresh_token": "<OAuth refresh token>",
  "expires_at": 1700000000,
  "user_id": 1234567,
  "organization_id": 12345,
  "workspace_id": 67890,
  "workspace_name": "My Workspace",
  "accounts_api_url": "https://accounts.toggl.com",
  "focus_api_url": "https://focus.toggl.com",
  "authenticated_at": "2025-01-15T10:00:00.000Z",
  "workspaces": [...]
}

HTTP client (@toggl/cli-core/focus-client)

The MCP package re-exports FocusClient from @toggl/cli-core. That client uses generated request functions from @toggl/focus-queries and @toggl/queries where available, and handles:

  • Auth: Resolves a fresh token via the token provider before each request (handles OAuth2 refresh transparently).
  • Required headers: Includes X-Toggl-PostHog-Data: {"platform_origin":"web"} on all requests — the Focus API rejects write operations without this header.
  • Generated request execution: Calls generated request helpers for Focus, org, and shared-data endpoints instead of hand-building paths in the MCP package.
  • Validation: Validates outgoing mutation payloads with generated Valibot schemas and soft-validates responses for typed callers.
  • Error handling: Returns a discriminated union (ApiResponse<T>) — callers check .ok before accessing .data.

Runtime design

  • Entity tool handlers are generated at startup from the shared @toggl/operations catalog.
  • Input schemas come from operation metadata; most payload schemas are generated Valibot schemas from query packages, with small hand-written wrappers for route IDs and curated list filters.
  • Mutation gate (src/runtime/safety/mutation-gate.ts) issues confirm_token values until the caller re-invokes the same mutating tool with that token.

Key Focus API concepts

| Concept | Description | | -------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Task | Core work item. Has name, priority, status, project, assignees, dates, description, notes. | | Project | Groups tasks. Has name, color, dates, estimated time. | | Time Block | A scheduled calendar slot for a task (planned time). Has start time + duration in seconds. | | Time Entry | Actual tracked time. Created by start/stop tracking. Types: activity or break. | | Status | Workflow state (e.g. Todo, Doing, Done). Workspace-level, fetched from /workspaces/{id}/statuses. | | User ID | user_account_id from the workspace API response. Used as assignee_user_id in tasks and for the toggl_user_id query filter. |

Maintenance model

The intended maintenance direction is to keep MCP and CLI surfaces driven by generated API artifacts:

  1. Regenerate @toggl/focus-queries when the Focus API changes.
  2. Prefer generated request functions, generated Valibot payload schemas, and generated response schemas over hand-written HTTP/path/payload logic.
  3. Keep @toggl/operations as the curated exposure layer for now: it defines which generated endpoints become public CLI/MCP operations, plus safety flags, command grouping, descriptions, and examples.
  4. When exposing new endpoints, add operation metadata and FocusClient bindings only where the generated request layer cannot be consumed directly yet.

Longer term, the main low-maintenance opportunity is generating the base operation catalog from querygen output and applying a small override map for visibility, safety, names, examples, and agent guidance.

MCP Apps (inline UI)

Cursor 2.6+, Claude Desktop, and other MCP App hosts can render view tools inline in chat. The stdio server is unchanged; view tools are additive alongside entity tools (tasks, projects, …).

  • Resource: ui://toggl-focus/app.html (single React iframe bundled with @toggl/design-system)
  • When to use: Prefer view tools when the user asks to show, see, or visualize Focus data. Use entity tools for mutations, scripting, and non-UI hosts.
  • Refresh: The iframe re-calls the same view tool via app.callServerTool — there are no separate *-refresh tools.

View tools

| Tool | Use when | | ------------------------------ | ---------------------------- | | focus-tasks-inbox | Task list / backlog | | focus-task-detail | Single task deep-dive | | focus-status-board | Kanban-style status snapshot | | focus-projects-overview | Project list | | focus-project-detail | Single project overview | | focus-milestones-roadmap | Milestones by due date | | focus-search-results | Search across entities | | focus-week-at-a-glance | Week plan vs tracked time | | focus-day-today | Today's schedule | | focus-time-log | Time entries table | | focus-time-blocks | Scheduled blocks | | focus-report-workload | Team workload / utilization | | focus-report-time-by-project | Time grouped by project | | focus-report-time-by-member | Time grouped by member | | focus-report-billable | Billable summary | | focus-report-task-throughput | Task completion throughput | | focus-team-roster | Workspace members | | focus-clients-directory | Client list | | focus-time-off-calendar | Time off in range | | focus-holidays-calendar | Public holidays | | focus-mutation-review | Confirm pending mutation | | focus-dry-run-preview | Preview dry-run payload |

Hosts without MCP App support still receive the same JSON tool results as entity tools.

Adding a new entity action

  1. Regenerate @toggl/focus-queries if the endpoint or schema is new.
  2. Reuse the generated request function and Valibot schemas in @toggl/cli-core / @toggl/operations.
  3. Add or update operation metadata in packages/operations/src.
  4. Rebuild (pnpm run build) and update docs/skill guidance if the user-facing workflow changes.

Development

pnpm install         # Install dependencies
pnpm run build       # Build MCP App iframe + compile TypeScript → build/
pnpm run build:mcpb       # Node-based .mcpb (same as build:mcpb:node)
pnpm run build:mcpb:binary -- --target darwin-arm64   # Binary .mcpb (requires Bun); targets: darwin-arm64, darwin-x64, linux-x64, win32-x64
pnpm run lint        # Run Oxlint checks
pnpm run lint:fix    # Auto-fix lint issues when possible
node build/index.js auth   # (Re-)authenticate

Releases use Changesets: run pnpm run changeset on a branch when you need a version bump, merge to main, and CI publishes to GitHub Packages when pending changesets exist.

The project uses TypeScript with ES2022 target and Node16 module resolution. Output goes to build/. Package tests: pnpm --filter @toggl/mcp test (tool inventory invariants vs @toggl/operations).

Publishing

CI publishes @toggl/mcp to GitHub Packages when pending Changesets are merged to main.

The same publish workflow also cross-compiles binary MCP bundles with Bun and attaches, per platform:

  • toggl-focus-mcp-<version>-darwin-arm64.mcpb (+ .sha256)
  • toggl-focus-mcp-<version>-darwin-x64.mcpb (+ .sha256)
  • toggl-focus-mcp-<version>-linux-x64.mcpb (+ .sha256)
  • toggl-focus-mcp-<version>-win32-x64.mcpb (+ .sha256)

These assets are attached to the GitHub release tag @toggl/mcp@<version>.