Fetches and aggregates time tracking data from Toggl API with intelligent Fibery entity reference parsing, user filtering, and smart caching capabilities
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Toggl MCP Servershow me time tracking data for the last 3 days"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Toggl MCP Server
A FastMCP-based Model Context Protocol (MCP) server that fetches and aggregates Toggl time tracking data with intelligent Fibery entity reference parsing and caching.
Features
Time Entry Aggregation: Fetch and aggregate time entries from Toggl API
Fibery Entity Parsing: Automatically extract Fibery entity references from Toggl descriptions (#ID [DB] [TYPE])
Caching: Smart caching with SQLite index and JSON file storage (1-hour TTL)
Rate Limiting: Exponential backoff handling for Toggl API rate limits
User Filtering: Optional filtering by single user or retrieve all workspace users
Date Range Validation: Enforces ISO 8601 format and max 7-day ranges per request
Installation
Prerequisites
Python 3.11+
uv (package manager)
Setup
Clone the repository:
git clone <repository-url>
cd toggl-mcp-customCreate virtual environment:
uv venv
source .venv/bin/activateInstall dependencies:
uv pip install -r requirements.txtConfigure environment:
cp .env.example .env
# Edit .env with your Toggl API credentialsConfiguration
Create a .env file in the project root with your Toggl credentials:
TOGGL_API_TOKEN=your_api_token_here
TOGGL_WORKSPACE_ID=your_workspace_id_hereGet your credentials:
API Token: Available at https://track.toggl.com/app/profile
Workspace ID: Available in Toggl settings or API responses
Using with Claude Code
Option 1: Project-Local Integration (Recommended)
The easiest way is to add the MCP server to your project's .mcp.json file:
{
"mcpServers": {
"toggl": {
"command": "/path/to/toggl-mcp-custom/.venv/bin/python",
"args": ["-m", "toggl_mcp.server"],
"cwd": "${workspaceRoot}"
}
}
}Replace /path/to/toggl-mcp-custom with the actual path to this project.
Claude Code will automatically discover and use this server. The tools will be available in your conversations.
Option 2: Global Integration
To use this server across all projects, add it to your global MCP config:
macOS/Linux:
mkdir -p ~/.config/claude-codeThen add to ~/.config/claude-code/mcp.json:
{
"mcpServers": {
"toggl": {
"command": "/path/to/toggl-mcp-custom/.venv/bin/python",
"args": ["-m", "toggl_mcp.server"],
"cwd": "/path/to/toggl-mcp-custom"
}
}
}Using in Other Projects
To add this MCP server to another project:
Copy the
cat > /path/to/other-project/.mcp.json << 'EOF' { "mcpServers": { "toggl": { "command": "/path/to/toggl-mcp-custom/.venv/bin/python", "args": ["-m", "toggl_mcp.server"], "cwd": "/path/to/toggl-mcp-custom" } } } EOFUpdate the paths to point to your toggl-mcp-custom installation
Restart Claude Code - it will automatically discover the server
Running the Server Manually
If you want to run the server directly:
source .venv/bin/activate
python -m toggl_mcp.serverThe server will start and expose two MCP tools:
1. get_workspace_users()
Lists all users in the Toggl workspace.
Response:
{
"status": "success",
"data": [
{"id": "12345", "email": "user@example.com", "name": "John Doe"},
{"id": "12346", "email": "jane@example.com", "name": "Jane Smith"}
],
"error": null
}2. get_toggl_aggregated_data(start_date, end_date, user_id=None)
Fetches and aggregates time entries for a date range.
Parameters:
start_date(string): ISO 8601 format (YYYY-MM-DD), e.g., "2025-10-06"end_date(string): ISO 8601 format, must be >= start_date and <= start_date + 7 daysuser_id(optional string): Filter by single user ID
Response:
{
"status": "success",
"data": {
"users": {
"user@example.com": {
"user_email": "user@example.com",
"matched_entities": [
{
"entity_database": "Scrum",
"entity_type": "Task",
"entity_id": "456",
"description": "Design UI",
"duration_hours": 7.5
}
],
"unmatched_activities": [
{
"description": "Team meeting",
"duration_hours": 1.0
}
],
"statistics": {
"total_duration_hours": 8.5,
"matched_duration_hours": 7.5,
"unmatched_duration_hours": 1.0
}
}
},
"statistics": {
"total_users": 1,
"total_duration_hours": 8.5,
"total_matched_duration_hours": 7.5,
"total_unmatched_duration_hours": 1.0
}
},
"error": null,
"metadata": {
"source": "api",
"entries_fetched": 15
}
}Description Parsing
The server automatically parses Toggl entry descriptions to extract Fibery entity references.
Format: "Description text #ID [DATABASE] [TYPE] [PROJECT]"
Examples:
"Design UI #456 [Scrum] [Task] [Moneyball]"→ Matched entity"#123 [Dev]"→ Minimal matched entity"Team meeting"→ Unmatched activity
Parsing Rules:
Extracts the rightmost
#IDif multiple existCaptures first 3 bracket values as DATABASE, TYPE, and PROJECT
Text before #ID becomes the description
Architecture
Services
CacheService: Manages caching with MD5 hash keys, SQLite index, and JSON file storage
TogglService: Handles Toggl API client with HTTP Basic Auth and rate limiting
ParserService: Parses descriptions to extract Fibery entity references
AggregatorService: Groups and aggregates time entries by user and entity
Models
User: Toggl workspace user
TimeEntry: Raw Toggl time entry
ParsedEntry: Entry with extracted metadata
UserAggregation: Aggregated data for single user
AggregatedData: Complete aggregated response
Testing
Run unit tests:
python -m pytest tests/ -vTest coverage:
26 unit tests covering:
Description parsing (7 tests)
Data aggregation (5 tests)
Cache operations (5 tests)
Date validation and utilities (9 tests)
Project Structure
toggl-mcp-custom/
├── src/toggl_mcp/
│ ├── __init__.py
│ ├── server.py # FastMCP server + tools
│ ├── config.py # Configuration from env vars
│ ├── models.py # Pydantic models
│ ├── utils.py # Utility functions
│ └── services/
│ ├── __init__.py
│ ├── cache_service.py # SQLite + JSON caching
│ ├── toggl_service.py # Toggl API client
│ ├── parser_service.py # Description parsing
│ └── aggregator_service.py # Data aggregation
├── tests/
│ ├── __init__.py
│ ├── test_parser_service.py
│ ├── test_aggregator_service.py
│ ├── test_cache_service.py
│ └── test_utils.py
├── cache/ # Runtime cache (auto-created)
│ ├── data/ # JSON cache files
│ └── index.db # SQLite index
├── requirements.txt # Python dependencies
├── .env.example # Environment template
└── README.md # This filePerformance Considerations
Rate Limiting
Toggl API limit: 3 requests per second
Exponential backoff on 429 (rate limit) responses:
Attempt 1: 60 seconds
Attempt 2: 120 seconds
Attempt 3: 240 seconds
After 3 retries: failure
Caching
Default TTL: 1 hour
Cache keys: MD5 hash of date range + optional user_id
Storage: SQLite index + JSON files
Automatic cleanup of expired entries on retrieval
Date Range Limits
Maximum range: 7 days per request
For larger ranges, make multiple requests and aggregate client-side
Day-by-day pagination to optimize API efficiency
Error Handling
The server returns structured error responses with error codes:
INVALID_DATE_FORMAT— Dates not in ISO 8601 formatINVALID_DATE_RANGE— end_date < start_dateDATE_RANGE_EXCEEDS_LIMIT— Range exceeds 7 daysUSER_NOT_FOUND— User ID not found in workspaceAPI_ERROR— Toggl API errorSERVICE_NOT_INITIALIZED— Services not properly initializedINTERNAL_ERROR— Server error
Development
Adding New Features
Add models to
models.pyImplement service methods
Write unit tests in
tests/Update MCP tool in
server.py
Running Tests
# All tests
python -m pytest tests/ -v
# Specific test file
python -m pytest tests/test_parser_service.py -v
# With coverage
python -m pytest tests/ --cov=src/toggl_mcpLicense
MIT
Support
For issues or questions, please refer to the implementation specification in /docs/features/1-initial-implementation/IMPLEMENTATION.md