A community-driven registry for Claude, Cursor, Windsurf, Cline & more. Not affiliated with Anthropic.
Are you the author? Sign in to claim
MCP server for managing Tempo worklogs in Jira
A Model Context Protocol (MCP) server for managing Tempo worklogs in Jira. This server provides tools for tracking time and managing worklogs through Tempo's API, making it accessible through Claude, Cursor and other MCP-compatible clients.
There are three ways to use this MCP server:
npx on your laptop, no clone required.If you just want to use the server, option 1 is the easiest and works on phones too. If you're a maintainer deploying for your team, see the Remote deployment guide.
Once your team has the server deployed, the flow is:
https://<your-deployment>.workers.dev/setup.https://<your-deployment>.workers.dev/mcp/u_<random>. Copy it.For ChatGPT: enable Settings → Apps → Advanced → Developer mode (Pro/Plus/Business+), then add the URL as a custom MCP server. Plus/Pro accounts can read; write tools (create/edit worklogs) require Business+ per OpenAI's tier.
The URL contains your credentials — treat it like a password, don't share or commit it.
Free-tier hosting on Cloudflare Workers. ~5–10 minutes from clone to live URL. Anyone can fork and self-host — no upstream coordination needed.
npm locally — only used for wrangler CLI; the Worker runtime itself doesn't run Node.git clone https://github.com/ivelin-web/tempo-mcp-server.git
cd tempo-mcp-server
npm install
# 1. Log in to Cloudflare (opens browser).
npx wrangler login
# 2. Create your own KV namespace for per-user credentials.
npx wrangler kv namespace create USERS
⚠️ If you forked the repo: the committed
wrangler.jsonckv_namespaces[0].idbelongs to the upstream maintainer's Cloudflare account. Replace it with the id step 2 just returned, otherwisewrangler deploywill fail withKV namespace … is not valid. KV namespace ids are public per-account identifiers, not secrets, but each account has its own.
# 3. Generate and store the encryption key.
# Used to AES-GCM-encrypt per-user credentials in KV.
openssl rand -base64 48 | npx wrangler secret put ENCRYPTION_KEY
# 4. (Optional) Pin the CORS origin. Defaults to "*". Set it if you only
# want browsers from a specific app to call the Worker.
echo "https://claude.ai" | npx wrangler secret put ALLOWED_ORIGIN
# 5. Deploy.
npm run remote:deploy
# → outputs https://tempo-mcp-server.<your-account>.workers.dev
Visit /setup on the deployed URL to onboard your first user.
After pulling new commits from upstream:
npm install # picks up any new deps
npm run remote:deploy # ships the new Worker bundle
Secrets and KV data persist across deploys. compatibility_date and compatibility_flags in wrangler.jsonc are pinned, so behaviour doesn't drift silently when Cloudflare ships runtime changes.
cp .dev.vars.example .dev.vars
# edit .dev.vars and put a real ENCRYPTION_KEY (any value works locally)
npm run remote:dev
# → http://localhost:8787 with a mock KV; data is wiped between sessions
Other useful scripts:
npm run remote:typecheck — type-check the Worker bundle (uses tsconfig.worker.json).npm run remote:tail — stream live logs from the deployed Worker.KV namespace … is not valid — kv_namespaces[0].id in wrangler.jsonc is empty (or wrong). Run npx wrangler kv namespace create USERS and paste the new id.ENCRYPTION_KEY is not defined at runtime — secret wasn't set. Re-run step 3.Rate limit binding … not available — your account's plan doesn't include the Workers Rate Limiting API. Either upgrade, or remove the ratelimits block in wrangler.jsonc and the SETUP_RATE_LIMITER.limit(...) call in src/remote/worker.ts./mcp/u_… — the user id is unknown (or never existed). The Worker returns 404 by design for invalid/missing ids; have the user re-run /setup.ENCRYPTION_KEY; existing AES-GCM blobs can't be decrypted with the new key. See the warning below.Credential storage: the /setup POST handler AES-GCM encrypts the form data with ENCRYPTION_KEY and stores it in KV under user:u_<random>. Each MCP request reads + decrypts that record, builds an McpServer for that single request, and dispatches via Cloudflare's official createMcpHandler. No credentials are held in memory between requests; no Durable Objects are used.
Treat
ENCRYPTION_KEYas long-lived. Rotating it invalidates every existing user record (the AES-GCM tag won't validate against the new key), and all your users will need to re-run/setup. Pick a key fromopenssl rand -base64 48once and never change it.
Auth model: the URL /mcp/u_<id> is the credential. The 22-char base64url id carries ~128 bits of entropy. We never return 401 for that path (Claude.ai web has known bugs around the 401-then-OAuth flow), and we return 404 for unknown ids. This matches the URL-token pattern used by Zapier MCP, Pipedream MCP, and similar.
Hardening already in place:
POST /setup, via Cloudflare's native Rate Limiting binding.Cache-Control: no-store on /setup responses so the success page (which contains the MCP URL) and the error re-render (which echoes tokens back) never sit in any cache.Referrer-Policy: no-referrer on every HTML page so the MCP URL doesn't leak via referrer headers.Limits to know about:
The easiest way to use this server is via npx without installation:
Open your MCP client configuration file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonAdd the following configuration:
{
"mcpServers": {
"Jira_Tempo": {
"command": "npx",
"args": ["-y", "@ivelin-web/tempo-mcp-server"],
"env": {
"TEMPO_API_TOKEN": "your_tempo_api_token_here",
"JIRA_API_TOKEN": "your_jira_api_token_here",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_BASE_URL": "https://your-org.atlassian.net"
}
}
}
}
# Clone the repository
git clone https://github.com/ivelin-web/tempo-mcp-server.git
cd tempo-mcp-server
# Install dependencies
npm install
# Build TypeScript files
npm run build
There are two ways to run the server locally:
npm run inspect
You can run the server directly with Node by pointing to the built JavaScript file:
{
"mcpServers": {
"Jira_Tempo": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/tempo-mcp-server/build/index.js"],
"env": {
"TEMPO_API_TOKEN": "your_tempo_api_token_here",
"JIRA_API_TOKEN": "your_jira_api_token_here",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_BASE_URL": "https://your-org.atlassian.net"
}
}
}
}
Tempo API Token:
getMissingWorklogDays (reads the user-schedule)Jira API Token:
basic auth out of the box.https://api.atlassian.com/ex/jira/{cloudId}/...) with the cloud ID, which this server's basic auth path does not currently route to. They will fail with 401 against your site URL. If you only have a scoped token available (e.g. your org disabled classic tokens), use the OAuth 2.0 PKCE flow instead — it routes through the gateway automatically.The server requires the following environment variables:
TEMPO_API_TOKEN # Your Tempo API token
JIRA_API_TOKEN # Your Jira API token (required for basic and bearer auth)
JIRA_EMAIL # Your Jira account email (required for basic auth)
JIRA_BASE_URL # Your Jira instance URL (e.g., https://your-org.atlassian.net)
JIRA_AUTH_TYPE # Optional: 'basic' (default), 'bearer', or 'oauth'
JIRA_OAUTH_CLIENT_ID # OAuth 2.0 client ID (required for oauth auth)
JIRA_OAUTH_CLIENT_SECRET # OAuth 2.0 client secret (required for oauth auth)
JIRA_TEMPO_ACCOUNT_CUSTOM_FIELD_ID # Optional: Custom field ID for Tempo accounts
You can set these in your environment or provide them in the MCP client configuration.
The server supports three authentication methods for the Jira API:
Uses email and API token. This is the traditional method:
{
"env": {
"JIRA_API_TOKEN": "your_api_token",
"JIRA_EMAIL": "your_email@example.com",
"JIRA_AUTH_TYPE": "basic"
}
}
For users who want to use OAuth 2.0 scoped tokens for enhanced security:
{
"env": {
"JIRA_API_TOKEN": "your_oauth_access_token",
"JIRA_AUTH_TYPE": "bearer"
}
}
Note: When using bearer auth, JIRA_EMAIL is not required as the user is identified from the token.
Some Atlassian organizations restrict API token access via admin policy, which causes basic and bearer authentication to fail. The oauth type implements the full OAuth 2.0 authorization code flow with PKCE and works regardless of API token restrictions — tokens are short-lived and refreshed automatically without any manual management.
On first use, a browser window opens for you to authorize access. Tokens are stored locally at ~/.tempo-mcp-server/tokens.json and refreshed automatically.
Create an OAuth 2.0 app in Atlassian Developer Console with the read:jira-user and read:jira-work scopes and http://localhost:7788/callback as the callback URL.
Configure the server:
{
"env": {
"JIRA_BASE_URL": "https://your-org.atlassian.net",
"JIRA_AUTH_TYPE": "oauth",
"JIRA_OAUTH_CLIENT_ID": "your_client_id",
"JIRA_OAUTH_CLIENT_SECRET": "your_client_secret"
}
}
Note: JIRA_API_TOKEN and JIRA_EMAIL are not required when using oauth auth.
If your Tempo instance requires worklogs to be linked to accounts, set the custom field ID that contains the account information:
JIRA_TEMPO_ACCOUNT_CUSTOM_FIELD_ID=10234
To find your custom field ID:
Fetches worklogs for the configured user between start and end dates.
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
Creates a new worklog for a specific Jira issue.
Parameters:
- issueKey: String (e.g., "PROJECT-123")
- timeSpentHours: Number (positive)
- date: String (YYYY-MM-DD)
- description: String (optional)
- startTime: String (HH:MM format, optional)
Creates multiple worklogs in a single operation.
Parameters:
- worklogEntries: Array of {
issueKey: String
timeSpentHours: Number
date: String (YYYY-MM-DD)
description: String (optional)
startTime: String (HH:MM format, optional)
}
Modifies an existing worklog.
Parameters:
- worklogId: String
- timeSpentHours: Number (positive)
- description: String (optional)
- date: String (YYYY-MM-DD, optional)
- startTime: String (HH:MM format, optional)
Removes an existing worklog.
Parameters:
- worklogId: String
Reports working days in a date range where the user has logged less time than expected. Expected hours per day come from the user's Tempo schedule, so holidays, non-working days, and part-time schedules are honoured automatically.
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
- minHoursPerDay: Number (optional) — override the per-day threshold;
non-working days are still skipped
Required Tempo scope: the
TEMPO_API_TOKENmust include the Schemes scope (covers Workload Schemes, Holiday Schemes, User Schedule) in addition to Worklogs. Tempo does not allow modifying scopes on an existing token — if your current token only has Worklogs, create a new one at Tempo > Settings > API Integration.
Aggregates worklogs in a date range and returns hours, worklog count, and percentage per group, sorted by hours descending.
Parameters:
- startDate: String (YYYY-MM-DD)
- endDate: String (YYYY-MM-DD)
- groupBy: "issue" | "account" | "day" | "week" | "month" (optional, default "issue")
tempo-mcp-server/
├── src/ # Source code
│ ├── config.ts # Configuration management
│ ├── index.ts # MCP server implementation
│ ├── jira.ts # Jira API integration
│ ├── oauth.ts # OAuth 2.0 PKCE flow and token management
│ ├── tools.ts # Tool implementations
│ ├── types.ts # TypeScript types and schemas
│ └── utils.ts # Utility functions
├── build/ # Compiled JavaScript (generated)
├── tsconfig.json # TypeScript configuration
└── package.json # Project metadata and scripts
If you encounter issues:
npm run inspectThis server implements the Model Context Protocol specification created by Anthropic.
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
A trilingual (繁中 / English / 简中) learning roadmap for agentic AI: from LLM basics to multi-agent systems, with 240+ cura
MCP server integration for DaVinci Resolve Studio