About tm-mcp
tm-mcp is an MCP server for Pyunto Time Management, for assistants that need to inspect schedules and manage logged time. It supports encrypted content, with decryption performed locally when a password is provided.
Key features
- 01View projects and tasks
- 02List schedule blocks and summarize time
- 03Create, update, and delete time blocks
- 04Decrypt encrypted names and memos locally
Use cases
- 01Review hours logged by project or date
- 02Record time through an AI assistant
- 03Inspect a schedule without decrypting content
MCP support
Exposes Pyunto Time Management account and time-tracking operations as tools to MCP clients. It can start without an API key to advertise its tools, but account data requires one.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
npx -y @pyunto/tm-mcpPYUNTO_TM_API_KEYSecretAPI key (ptm_...) minted in Settings → Account → API keysPYUNTO_TM_BASE_URLBase URL, for self-hosted instancesPYUNTO_TM_PASSWORDSecretAccount password; unwraps the private key locally so E2EE project and task names decryptPYUNTO_TM_PASSWORD_FILESecretPath to a file holding the account password, instead of PYUNTO_TM_PASSWORDLocal servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.
Tools
10Saved tool list · updated 2w ago
This tool takes no parameters.
Details
From the project README@pyunto/tm-mcp
MCP (Model Context Protocol) server for Pyunto Time Management. Connects Claude Code, Claude Desktop, Codex CLI, Cursor and any other MCP client to a Pyunto TM account so an assistant can read the schedule, summarise where the hours went, and log time.
User-facing setup instructions live at https://tm.pyunto.com/docs/mcp.en.md (日本語: https://tm.pyunto.com/docs/mcp.ja.md). This file is the developer view.
Tools
| Tool | Scope |
|---|---|
whoami — account, key name, scopes, decryption status | — |
list_projects | projects:read |
list_tasks (filter by project or by a date the task covers) | projects:read |
list_time_blocks (range ≤ 92 days) | blocks:read |
time_summary (grouped by project / task / date) | record:read |
log_time (writes) | blocks:write |
update_time_block (writes) | blocks:write |
delete_time_block — one id, permanent, takes attachments with it | blocks:delete |
Every tool returns JSON as text. Failures come back as isError results whose
message names the fix (missing scope, wrong key, locked E2EE) rather than
throwing at the transport level — an agent can act on that, a stack trace it
cannot.
Install
npx -y @pyunto/tm-mcp # what an MCP client config runs
Build from source
This package lives in an npm-workspaces repository together with the SDK it depends on; build from the repository root so the workspace link is used:
npm install
npm run build # both packages
npm test # sdk crypto round-trips + 25 MCP tool checks
Result: mcp/dist/cli.js, the executable stdio server (dist/index.js
stays a side-effect-free module the tests can import).
Configuration
Environment only — MCP clients spawn the process and inject env from their config file.
The server starts without an API key and answers tools/list — a client or
a directory can see what it offers before anyone signs up. Calling a tool
without one returns the same guidance as an isError rather than an opaque
401, and whoami reports the missing key instead of failing.
| Variable | Required | Default | Purpose |
|---|---|---|---|
PYUNTO_TM_API_KEY | for data | — | ptm_…, minted in Settings → Account → API keys. Listing the tools works without it |
PYUNTO_TM_BASE_URL | https://tm.pyunto.com | Self-hosted instances | |
PYUNTO_TM_PASSWORD | none | Unwraps the private key locally so E2EE names/memos decrypt | |
PYUNTO_TM_PASSWORD_FILE | none | Same, read from a file instead of the env |
{
"mcpServers": {
"pyunto-tm": {
"command": "npx",
"args": ["-y", "@pyunto/tm-mcp"],
"env": { "PYUNTO_TM_API_KEY": "ptm_…" }
}
}
}
How E2EE is handled
Content fields are encrypted in the user's browser; the server never holds the
plaintext, and neither does this process by default. Given a password, the
server's password-wrapped private key blob (GET /api/v1/keys, scope
keys:read) is unwrapped here, in memory, and used to open each project's
sealed DEK. The password is never transmitted and nothing is written to disk.
Without a password the server still answers everything schedule-shaped — ids,
dates, times, durations, aggregates — and name fields come back empty with a
NOTE: explaining why, so the model reports the limitation instead of inventing
names.
Layout
src/index.ts tool definitions + implementations + server wiring
src/cli.ts the bin: calls start()
test/tools.mjs stub /api/v1 server, exercises every tool and error path
test/cli.mjs spawns the built bin (directly and via symlink) over real MCP
callTool(name, args) is exported for tests; start() attaches the transport
and is called only by cli.ts.
delete_time_block is deliberately single-id: no range or filter delete is
exposed, because an automated caller getting a range wrong destroys an unbounded
amount of data that has no restore path. Its tool description requires the model
to show the user the exact block first and get a yes for that block.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.