timetastic-mcp 0.1.0__tar.gz

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.
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # Cancel superseded runs on the same ref.
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ test:
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v6
25
+ with:
26
+ enable-cache: true
27
+
28
+ - name: Set up Python ${{ matrix.python-version }}
29
+ run: uv python install ${{ matrix.python-version }}
30
+
31
+ - name: Install dependencies
32
+ run: uv sync --locked
33
+
34
+ - name: Run tests
35
+ run: uv run --python ${{ matrix.python-version }} pytest
@@ -0,0 +1,91 @@
1
+ name: Publish
2
+
3
+ # Publish to PyPI when release branch is pushed. This workflow will:
4
+ # 1. Build the package and run tests
5
+ # 2. Publish the package to PyPI
6
+ # 3. Tag the release in git
7
+
8
+ on:
9
+ push:
10
+ branches: [release]
11
+
12
+ # Cancel superseded runs on the same ref.
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v6
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: Set up Python 3.13
28
+ run: uv python install 3.13
29
+
30
+ - name: Install dependencies
31
+ run: uv sync --locked
32
+
33
+ - name: Run tests
34
+ run: uv run --python 3.13 pytest
35
+ - name: Build sdist and wheel
36
+ run: uv build
37
+
38
+ - name: Upload build artifacts
39
+ uses: actions/upload-artifact@v4
40
+ with:
41
+ name: dist
42
+ path: dist/
43
+
44
+ publish:
45
+ needs: build
46
+ runs-on: ubuntu-latest
47
+ environment:
48
+ name: pypi
49
+ url: https://pypi.org/p/timetastic-mcp
50
+ permissions:
51
+ id-token: write
52
+ steps:
53
+ - name: Download build artifacts
54
+ uses: actions/download-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
58
+
59
+ - name: Publish to PyPI
60
+ uses: pypa/gh-action-pypi-publish@release/v1
61
+ with:
62
+ # skip on duplicate version
63
+ skip-existing: true
64
+
65
+ tag:
66
+ needs: publish
67
+ runs-on: ubuntu-latest
68
+ permissions:
69
+ contents: write
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+ with:
73
+ fetch-depth: 0
74
+ fetch-tags: true
75
+
76
+ - name: Install uv
77
+ uses: astral-sh/setup-uv@v6
78
+
79
+ - name: Tag the released version
80
+ run: |
81
+ version="$(uv version --short)"
82
+ tag="v${version}"
83
+ # Idempotent: skip rather than fail on tag conflict
84
+ if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
85
+ echo "Tag ${tag} already exists — skipping."
86
+ exit 0
87
+ fi
88
+ git config user.name "github-actions[bot]"
89
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
90
+ git tag -a "${tag}" -m "Release ${version}"
91
+ git push origin "${tag}"
@@ -0,0 +1,168 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ .pdm-python
87
+ .pdm-build/
88
+
89
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
90
+ __pypackages__/
91
+
92
+ # RabbitMQ
93
+ mnesia/
94
+ rabbitmq/
95
+ rabbitmq-data/
96
+
97
+ # Environments
98
+ .env
99
+ .envrc
100
+ .venv
101
+ env/
102
+ venv/
103
+ ENV/
104
+ env.bak/
105
+ venv.bak/
106
+
107
+ # Spyder project settings
108
+ .spyderproject
109
+ .spyproject
110
+
111
+ # Rope project settings
112
+ .ropeproject
113
+
114
+ # mkdocs documentation
115
+ /site
116
+
117
+ # mypy
118
+ .mypy_cache/
119
+ .dmypy.json
120
+ dmypy.json
121
+
122
+ # Pyre type checker
123
+ .pyre/
124
+
125
+ # pytype static type analyzer
126
+ .pytype/
127
+
128
+ # Cython debug symbols
129
+ cython_debug/
130
+
131
+ # PyCharm
132
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
133
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
134
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
135
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
136
+ # .idea/
137
+
138
+ # Abstra
139
+ # Abstra is an AI-powered process automation framework.
140
+ # Ignore directories containing user credentials, local state, and settings.
141
+ # Learn more at https://abstra.io/docs
142
+ .abstra/
143
+
144
+ # Visual Studio Code
145
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
146
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
147
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
148
+ # you could uncomment the following to ignore the entire vscode folder
149
+ # .vscode/
150
+ # Temporary file for partial code execution
151
+ tempCodeRunnerFile.py
152
+
153
+ # Ruff stuff:
154
+ .ruff_cache/
155
+
156
+ # PyPI configuration file
157
+ .pypirc
158
+
159
+ # Marimo
160
+ marimo/_static/
161
+ marimo/_lsp/
162
+ __marimo__/
163
+
164
+ # Streamlit
165
+ .streamlit/secrets.toml
166
+
167
+ # API configuration reference data
168
+ swagger.json
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marc Lequime
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: timetastic-mcp
3
+ Version: 0.1.0
4
+ Summary: An unofficial MCP server for Timetastic, exposing its absence & leave API to agentic clients.
5
+ Project-URL: Homepage, https://github.com/mlequime/timetastic-mcp
6
+ Project-URL: Repository, https://github.com/mlequime/timetastic-mcp
7
+ Project-URL: Issues, https://github.com/mlequime/timetastic-mcp/issues
8
+ Author-email: Marc Lequime <marc@lequi.me>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: absence,hr,leave,mcp,model-context-protocol,timetastic
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Office/Business :: Scheduling
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Requires-Python: >=3.13
19
+ Requires-Dist: httpx>=0.28.1
20
+ Requires-Dist: mcp[cli]>=1.28.1
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Timetastic MCP
24
+
25
+ An unofficial [MCP](https://modelcontextprotocol.io) server for
26
+ [Timetastic](https://timetastic.co.uk), exposing the Timetastic API to
27
+ agentic clients so they can query and manage absence & leave data.
28
+
29
+ ## Setup
30
+
31
+ You need an **admin** API token, generated at
32
+ <https://app.timetastic.co.uk/api>. The server reads it from the
33
+ `TIMETASTIC_API_TOKEN` environment variable.
34
+
35
+ The quickest way to run it is with [uv](https://docs.astral.sh/uv/)'s `uvx`,
36
+ which fetches and runs the published package without a manual install:
37
+
38
+ ```bash
39
+ export TIMETASTIC_API_TOKEN="your-token-here"
40
+ uvx timetastic-mcp
41
+ ```
42
+
43
+ Or install it as a tool so the `timetastic-mcp` command is on your `PATH`:
44
+
45
+ ```bash
46
+ uv tool install timetastic-mcp # or: pipx install timetastic-mcp
47
+ ```
48
+
49
+ > [!IMPORTANT]
50
+ > Only admin users can generate API tokens on Timetastic. The above URL is only accessible to admin users.
51
+
52
+ ## Client configuration
53
+
54
+ Add the server to your MCP client (e.g. Claude Desktop / Claude Code):
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "timetastic": {
60
+ "command": "uvx",
61
+ "args": ["timetastic-mcp"],
62
+ "env": { "TIMETASTIC_API_TOKEN": "your-token-here" }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ Pin a version with `"args": ["timetastic-mcp@0.1.0"]`. If you installed the
69
+ command on your `PATH` instead, use `"command": "timetastic-mcp"` with
70
+ `"args": []`. In Claude Code you can also add it from the CLI:
71
+
72
+ ```bash
73
+ claude mcp add timetastic --env TIMETASTIC_API_TOKEN=your-token -- uvx timetastic-mcp
74
+ ```
75
+
76
+ ## Tools
77
+
78
+ Tools are grouped by resource and named `<verb>_<resource>`.
79
+
80
+ | Group | Tools |
81
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
+ | **Absences** | `list_absences` |
83
+ | **Holidays** (leave bookings) | `list_holidays`, `get_holiday`, `book_holiday`, `action_holiday` |
84
+ | **Users** | `list_users`, `get_user`, `get_user_contact`, `add_user`, `edit_user`, `archive_user`, `restore_user`, `assign_public_holidays_to_user` |
85
+ | **Departments** | `list_departments`, `get_department`, `add_department`, `edit_department`, `delete_department` |
86
+ | **Leave types** | `list_leave_types`, `get_leave_type`, `list_leave_type_colors`, `list_leave_type_icons`, `create_leave_type`, `update_leave_type`, `delete_leave_type` |
87
+ | **Allowances** | `list_all_allowances`, `get_user_allowance`, `update_user_allowance`, `update_user_carry_forward`, `add_user_toil`, `update_user_toil`, `delete_user_toil` |
88
+ | **Locked dates** | `list_locked_dates`, `add_locked_date`, `delete_locked_date` |
89
+ | **Public holidays** | `list_public_holidays`, `get_public_holiday`, `list_public_holiday_countries` |
90
+ | **Webhooks** | `list_webhook_events` |
91
+
92
+ > **Note:** Timetastic calls all leave bookings "holidays" for historical
93
+ > reasons — the _Holidays_ tools cover any kind of absence, not just annual
94
+ > leave.
95
+
96
+ ## Layout
97
+
98
+ The package lives under [`src/timetastic_mcp/`](src/timetastic_mcp/):
99
+
100
+ - [`timetastic.py`](src/timetastic_mcp/timetastic.py) — async HTTP client (auth,
101
+ base URL, rate-limit retries, error handling).
102
+ - [`server.py`](src/timetastic_mcp/server.py) — the shared `FastMCP` instance
103
+ and `get_client()`, the lazily-created API client the tools call.
104
+ - [`tools/`](src/timetastic_mcp/tools/) — one module per resource area, each
105
+ registering its tools on the shared server: `absences`, `holidays`, `users`,
106
+ `departments`, `leave_types`, `allowances`, `locked_dates`,
107
+ `public_holidays`, `webhooks`.
108
+ - [`main.py`](src/timetastic_mcp/main.py) — entry point (the `timetastic-mcp`
109
+ console script); imports `tools` to register everything, then runs the server.
110
+
111
+ ## Development
112
+
113
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
114
+
115
+ ```bash
116
+ uv sync # create the venv and install the package + dev deps
117
+ uv run pytest # run the test suite
118
+ uv run timetastic-mcp # run the server from your checkout
119
+ ```
120
+
121
+ ## Notes
122
+
123
+ - The API is rate limited to 5 requests/second per token (1/second for
124
+ `list_absences`); the client retries once on a `429`.
125
+ - Write and admin operations require appropriate permissions on the token's
126
+ user account.
@@ -0,0 +1,104 @@
1
+ # Timetastic MCP
2
+
3
+ An unofficial [MCP](https://modelcontextprotocol.io) server for
4
+ [Timetastic](https://timetastic.co.uk), exposing the Timetastic API to
5
+ agentic clients so they can query and manage absence & leave data.
6
+
7
+ ## Setup
8
+
9
+ You need an **admin** API token, generated at
10
+ <https://app.timetastic.co.uk/api>. The server reads it from the
11
+ `TIMETASTIC_API_TOKEN` environment variable.
12
+
13
+ The quickest way to run it is with [uv](https://docs.astral.sh/uv/)'s `uvx`,
14
+ which fetches and runs the published package without a manual install:
15
+
16
+ ```bash
17
+ export TIMETASTIC_API_TOKEN="your-token-here"
18
+ uvx timetastic-mcp
19
+ ```
20
+
21
+ Or install it as a tool so the `timetastic-mcp` command is on your `PATH`:
22
+
23
+ ```bash
24
+ uv tool install timetastic-mcp # or: pipx install timetastic-mcp
25
+ ```
26
+
27
+ > [!IMPORTANT]
28
+ > Only admin users can generate API tokens on Timetastic. The above URL is only accessible to admin users.
29
+
30
+ ## Client configuration
31
+
32
+ Add the server to your MCP client (e.g. Claude Desktop / Claude Code):
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "timetastic": {
38
+ "command": "uvx",
39
+ "args": ["timetastic-mcp"],
40
+ "env": { "TIMETASTIC_API_TOKEN": "your-token-here" }
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ Pin a version with `"args": ["timetastic-mcp@0.1.0"]`. If you installed the
47
+ command on your `PATH` instead, use `"command": "timetastic-mcp"` with
48
+ `"args": []`. In Claude Code you can also add it from the CLI:
49
+
50
+ ```bash
51
+ claude mcp add timetastic --env TIMETASTIC_API_TOKEN=your-token -- uvx timetastic-mcp
52
+ ```
53
+
54
+ ## Tools
55
+
56
+ Tools are grouped by resource and named `<verb>_<resource>`.
57
+
58
+ | Group | Tools |
59
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
+ | **Absences** | `list_absences` |
61
+ | **Holidays** (leave bookings) | `list_holidays`, `get_holiday`, `book_holiday`, `action_holiday` |
62
+ | **Users** | `list_users`, `get_user`, `get_user_contact`, `add_user`, `edit_user`, `archive_user`, `restore_user`, `assign_public_holidays_to_user` |
63
+ | **Departments** | `list_departments`, `get_department`, `add_department`, `edit_department`, `delete_department` |
64
+ | **Leave types** | `list_leave_types`, `get_leave_type`, `list_leave_type_colors`, `list_leave_type_icons`, `create_leave_type`, `update_leave_type`, `delete_leave_type` |
65
+ | **Allowances** | `list_all_allowances`, `get_user_allowance`, `update_user_allowance`, `update_user_carry_forward`, `add_user_toil`, `update_user_toil`, `delete_user_toil` |
66
+ | **Locked dates** | `list_locked_dates`, `add_locked_date`, `delete_locked_date` |
67
+ | **Public holidays** | `list_public_holidays`, `get_public_holiday`, `list_public_holiday_countries` |
68
+ | **Webhooks** | `list_webhook_events` |
69
+
70
+ > **Note:** Timetastic calls all leave bookings "holidays" for historical
71
+ > reasons — the _Holidays_ tools cover any kind of absence, not just annual
72
+ > leave.
73
+
74
+ ## Layout
75
+
76
+ The package lives under [`src/timetastic_mcp/`](src/timetastic_mcp/):
77
+
78
+ - [`timetastic.py`](src/timetastic_mcp/timetastic.py) — async HTTP client (auth,
79
+ base URL, rate-limit retries, error handling).
80
+ - [`server.py`](src/timetastic_mcp/server.py) — the shared `FastMCP` instance
81
+ and `get_client()`, the lazily-created API client the tools call.
82
+ - [`tools/`](src/timetastic_mcp/tools/) — one module per resource area, each
83
+ registering its tools on the shared server: `absences`, `holidays`, `users`,
84
+ `departments`, `leave_types`, `allowances`, `locked_dates`,
85
+ `public_holidays`, `webhooks`.
86
+ - [`main.py`](src/timetastic_mcp/main.py) — entry point (the `timetastic-mcp`
87
+ console script); imports `tools` to register everything, then runs the server.
88
+
89
+ ## Development
90
+
91
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
92
+
93
+ ```bash
94
+ uv sync # create the venv and install the package + dev deps
95
+ uv run pytest # run the test suite
96
+ uv run timetastic-mcp # run the server from your checkout
97
+ ```
98
+
99
+ ## Notes
100
+
101
+ - The API is rate limited to 5 requests/second per token (1/second for
102
+ `list_absences`); the client retries once on a `429`.
103
+ - Write and admin operations require appropriate permissions on the token's
104
+ user account.
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "timetastic-mcp"
3
+ version = "0.1.0"
4
+ description = "An unofficial MCP server for Timetastic, exposing its absence & leave API to agentic clients."
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Marc Lequime", email = "marc@lequi.me" }]
10
+ keywords = ["mcp", "timetastic", "model-context-protocol", "absence", "leave", "hr"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Intended Audience :: Developers",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.13",
16
+ "Topic :: Office/Business :: Scheduling",
17
+ "Topic :: Software Development :: Libraries",
18
+ ]
19
+ dependencies = [
20
+ "httpx>=0.28.1",
21
+ "mcp[cli]>=1.28.1",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/mlequime/timetastic-mcp"
26
+ Repository = "https://github.com/mlequime/timetastic-mcp"
27
+ Issues = "https://github.com/mlequime/timetastic-mcp/issues"
28
+
29
+ [project.scripts]
30
+ timetastic-mcp = "timetastic_mcp.main:main"
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=9.1.1",
35
+ ]
36
+
37
+ [build-system]
38
+ requires = ["hatchling"]
39
+ build-backend = "hatchling.build"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/timetastic_mcp"]
43
+
44
+ [tool.pytest.ini_options]
45
+ # The package lives under src/, so make it importable for the test suite.
46
+ pythonpath = ["src"]
47
+ testpaths = ["tests"]
@@ -0,0 +1,11 @@
1
+ """Unofficial MCP server for the Timetastic API.
2
+
3
+ Exposes Timetastic's absence & leave data to MCP clients. The console script
4
+ ``timetastic-mcp`` (see ``main.main``) runs the server over stdio.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ __version__ = "0.1.0"
10
+
11
+ __all__ = ["__version__"]
@@ -0,0 +1,8 @@
1
+ """Enable ``python -m timetastic_mcp`` to run the server."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .main import main
6
+
7
+ if __name__ == "__main__":
8
+ main()
@@ -0,0 +1,25 @@
1
+ """Timetastic MCP server — entry point.
2
+
3
+ Exposes the Timetastic API (https://app.timetastic.co.uk/api) as MCP tools,
4
+ grouped by resource under the ``tools`` package: absences, holidays (leave
5
+ bookings), users, departments, leave types, allowances, locked dates, public
6
+ holidays and webhooks.
7
+
8
+ Importing ``tools`` registers every tool on the shared ``mcp`` server defined
9
+ in ``server.py``. Set the ``TIMETASTIC_API_TOKEN`` environment variable to an
10
+ admin API token before running, then run the ``timetastic-mcp`` console script.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from . import tools # noqa: F401 — imported for its tool-registration side effects
16
+ from .server import mcp
17
+
18
+
19
+ def main() -> None:
20
+ """Run the MCP server over stdio."""
21
+ mcp.run()
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()
File without changes