Python client for the Kaneo project management API
Project description
kaneo
A Python SDK and MCP server for the Kaneo project management API.
Use it as a Python library in your scripts, or as an MCP server that plugs straight into Claude Code, Cursor, Windsurf, or any MCP-compatible AI tool.
Installation
pip install kaneo # just the SDK
pip install kaneo[mcp] # SDK + MCP server for AI agents
Requires Python 3.10+.
Python SDK
Quick Start
from kaneo import KaneoClient
# picks up KANEO_TOKEN from your environment
client = KaneoClient()
# or pass it directly
client = KaneoClient(token="your-api-token")
# list every project in a workspace
projects = client.projects.list(workspace_id="your-workspace-id")
for p in projects:
print(f"{p.name} ({p.slug})")
# create a task
task = client.tasks.create(
project_id="your-project-id",
title="Fix the login bug",
priority="high",
status="to-do",
description="Users are seeing 500 errors on /login",
)
print(f"Created: {task.id}")
# move it to in-progress
updated = client.tasks.update_status(task.id, "in-progress")
print(f"Status: {updated.status}")
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
KANEO_TOKEN |
Yes (unless passed to constructor) | — | Your Kaneo API token |
KANEO_BASE_URL |
No | https://cloud.kaneo.app/api |
API base URL |
You can always override these by passing token and base_url to KaneoClient().
Self-hosted Kaneo
If you're running your own Kaneo instance, just point the client at it:
export KANEO_TOKEN=your-token
export KANEO_BASE_URL=https://kaneo.yourdomain.com/api
# or in code
client = KaneoClient(
token="your-token",
base_url="https://kaneo.yourdomain.com/api",
)
Projects
# list all projects in a workspace
projects = client.projects.list(workspace_id="ws-id")
# get a single project (comes with its tasks)
project = client.projects.get(project_id="proj-id", workspace_id="ws-id")
print(project.name, project.is_public, len(project.tasks))
# create one
project = client.projects.create(
workspace_id="ws-id",
name="My Project",
slug="MP",
icon="Layout",
)
# delete it
client.projects.delete(project_id="proj-id")
Tasks
# list all tasks in a project (pulled from every board column)
tasks = client.tasks.list(project_id="proj-id")
# get a single task
task = client.tasks.get(task_id="task-id")
# create a task with all the options
task = client.tasks.create(
project_id="proj-id",
title="Implement OAuth",
priority="high", # no-priority | low | medium | high | urgent
status="to-do", # backlog | to-do | in-progress | done | cancelled
description="Add Google OAuth support",
due_date="2026-12-31", # optional
user_id="user-id", # optional assignee
)
# update fields individually
client.tasks.update_status(task.id, "in-progress")
client.tasks.update_priority(task.id, "urgent")
client.tasks.update_title(task.id, "Implement OAuth 2.0")
client.tasks.update_description(task.id, "Add Google and GitHub OAuth")
# delete
client.tasks.delete(task_id="task-id")
Priorities: no-priority, low, medium, high, urgent
Statuses: backlog, to-do, in-progress, done, cancelled
Pass something invalid and you'll get a ValueError before the API is even called.
Columns
# add a column to a project board
client.columns.create(
project_id="proj-id",
name="In Review",
is_final=False, # True for columns that mean "done"
)
# remove a column
client.columns.delete(column_id="col-id")
Config
# check what the server has enabled
config = client.config.get()
print(config.has_smtp)
print(config.has_github_sign_in)
print(config.disable_registration)
Error Handling
Every exception carries a status_code so you know exactly what went wrong:
from kaneo.exceptions import AuthError, NotFoundError, ValidationError, ServerError
try:
task = client.tasks.get("nonexistent-id")
except NotFoundError as e:
print(f"Not found (HTTP {e.status_code})")
except AuthError:
print("Bad token — check KANEO_TOKEN")
except ValidationError as e:
print(f"Bad request: {e}")
except ServerError:
print("Kaneo is having a bad day — try again later")
| Exception | HTTP Status | When |
|---|---|---|
AuthError |
401 | Invalid or missing token |
NotFoundError |
404 | Resource doesn't exist |
ValidationError |
400 | Bad input or missing fields |
ServerError |
5xx | Server-side failure |
KaneoError |
Any other 4xx | Catch-all base class |
MCP Server (for AI agents)
The MCP server wraps the SDK and exposes every operation as a tool over the Model Context Protocol. Your AI agent discovers the tools automatically — no extra prompting needed.
your AI tool <--stdin/stdout--> kaneo-mcp <--HTTPS--> Kaneo API
Install
pip install kaneo[mcp]
Claude Code
Add to ~/.claude/settings.json:
{
"mcpServers": {
"kaneo": {
"command": "kaneo-mcp",
"env": {
"KANEO_TOKEN": "your-api-token",
"KANEO_WORKSPACE_ID": "your-workspace-id"
}
}
}
}
Self-hosted? Just add KANEO_BASE_URL:
{
"mcpServers": {
"kaneo": {
"command": "kaneo-mcp",
"env": {
"KANEO_TOKEN": "your-api-token",
"KANEO_WORKSPACE_ID": "your-workspace-id",
"KANEO_BASE_URL": "https://kaneo.yourdomain.com/api"
}
}
}
}
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"kaneo": {
"command": "kaneo-mcp",
"env": {
"KANEO_TOKEN": "your-api-token",
"KANEO_WORKSPACE_ID": "your-workspace-id"
}
}
}
}
Available Tools
| Tool | What it does |
|---|---|
get_config |
Check server settings (SMTP, SSO, registration) |
list_projects |
List all projects in a workspace |
get_project |
Get a project with its tasks |
create_project |
Create a new project |
delete_project |
Delete a project |
list_tasks |
List all tasks in a project |
get_task |
Get a single task by ID |
create_task |
Create a task with title, priority, status, description, due date, assignee |
delete_task |
Delete a task |
update_task_status |
Move a task: backlog / to-do / in-progress / done / cancelled |
update_task_priority |
Reprioritize: no-priority / low / medium / high / urgent |
update_task_title |
Rename a task |
update_task_description |
Edit task description (markdown supported) |
create_column |
Add a board column |
delete_column |
Remove a board column |
MCP Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
KANEO_TOKEN |
Yes | — | API token |
KANEO_BASE_URL |
No | https://cloud.kaneo.app/api |
For self-hosted instances |
KANEO_WORKSPACE_ID |
No | — | Default workspace (saves passing it to every project tool) |
Development
git clone https://github.com/drtinkerer/kaneo-python-client.git
cd kaneo-python-client
pip install -e ".[dev,mcp]"
# run tests
pytest tests/ -v
# with coverage
pytest tests/ --cov=src/kaneo --cov-report=term-missing
# lint
black --check src/ tests/
isort --check-only src/ tests/
flake8 src/ tests/ --max-line-length=88
# build
pip install build && python -m build
Project Layout
src/kaneo/
client.py HTTP client, auth, error handling
exceptions.py typed exceptions (AuthError, NotFoundError, etc.)
models/
project.py Project dataclass
task.py Task dataclass
config.py Config dataclass
resources/
projects.py list, get, create, delete
tasks.py CRUD + field-level updates
columns.py create, delete
config.py get
mcp/
server.py MCP server wrapping the SDK
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kaneo-0.1.0.tar.gz.
File metadata
- Download URL: kaneo-0.1.0.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8eff3a5c453ad2e1bf2a4b8db626540ce76598360806d7c108c759903ef386b3
|
|
| MD5 |
465c45b85ea5e5fe3a640620e8a17b96
|
|
| BLAKE2b-256 |
196cf9bef1acba844f12681997aecf378abd295099471a3febb3ddcf1ab3b4bd
|
Provenance
The following attestation bundles were made for kaneo-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on drtinkerer/kaneo-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kaneo-0.1.0.tar.gz -
Subject digest:
8eff3a5c453ad2e1bf2a4b8db626540ce76598360806d7c108c759903ef386b3 - Sigstore transparency entry: 1151249146
- Sigstore integration time:
-
Permalink:
drtinkerer/kaneo-python-client@f5819fb8328ce518f42fd5e426355d270f4b3833 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/drtinkerer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@f5819fb8328ce518f42fd5e426355d270f4b3833 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file kaneo-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kaneo-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f5aa9cf238c9fc76222f85fbdc68c532aff9ac757f7fb9619ad8778a5633387
|
|
| MD5 |
11de53f85fc925c160e1cbef0c0f307b
|
|
| BLAKE2b-256 |
1b54a579d1ebd2fc70f85b4d6497b18f11e3738f917fd2e43988a0877d9d7317
|
Provenance
The following attestation bundles were made for kaneo-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on drtinkerer/kaneo-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kaneo-0.1.0-py3-none-any.whl -
Subject digest:
5f5aa9cf238c9fc76222f85fbdc68c532aff9ac757f7fb9619ad8778a5633387 - Sigstore transparency entry: 1151249201
- Sigstore integration time:
-
Permalink:
drtinkerer/kaneo-python-client@f5819fb8328ce518f42fd5e426355d270f4b3833 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/drtinkerer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@f5819fb8328ce518f42fd5e426355d270f4b3833 -
Trigger Event:
workflow_dispatch
-
Statement type: