Sandtime.io MCP Server
The Model Context Protocol (MCP) lets AI clients like Claude, ChatGPT, and Claude Code talk to Sandtime.io directly. Connect once and create, review, and report on time entries from the tools you already use.
What is MCP?
The Model Context Protocol is an open standard for connecting AI assistants to external tools and data. The Sandtime.io MCP server exposes your time tracking workspace - activities, projects, reports, timesheets, and more - as a set of tools an assistant can call on your behalf.
Read actions return clean, materialized data with formatted durations and local times. Destructive actions, like deleting a project or removing a member, deliberately hand off to a human by returning a deep link to the right page in the app.
New to logging time from your editor? See how developers use Sandtime.io day to day.
Need plain HTTP or cURL instead? See the REST API for the lower-level integration surface.
What you can ask
Talk to your assistant in plain language. It resolves the right user, project, and dates, then calls the tools for you.
Connect your assistant
The quickest way is browser sign-in: paste the server URL into your assistant, sign in to Sandtime.io, and approve. No API key, no config files.
https://mcp.sandtime.io/mcpClaude.ai (Web)
- Open Settings, then Connectors, and choose to add a custom connector.
- Paste the server URL above, then add the connector.
- Sign in to Sandtime.io in the browser and approve access.
On Team or Enterprise plans, an owner enables the connector in the organization settings first.
Claude Desktop
- Add Sandtime.io as a remote connector - there is no config file to edit.
- Sign in and approve when the browser opens.
ChatGPT (Web)
- Turn on developer mode, then open Connectors and add a custom connector.
- Paste the server URL above, then sign in and approve.
ChatGPT Desktop
- Add Sandtime.io once as a connector in ChatGPT - see the ChatGPT (Web) steps above.
- Open the ChatGPT desktop app with the same account and enable Sandtime.io in a chat; sign in and approve if prompted.
ChatGPT connectors are shared across your account, so there is no separate desktop config.
Claude Code
- Run these in your terminal - the second opens your browser to approve access.
claude mcp add --transport http --scope user sandtime https://mcp.sandtime.io/mcpclaude mcp login sandtimeOr send this to your AI agent and it will connect itself:
Connect this workspace to the Sandtime.io MCP server over OAuth. Run:
claude mcp add --transport http --scope user sandtime https://mcp.sandtime.io/mcp
Then run:
claude mcp login sandtime
Open the browser URL it prints and wait for me to approve access in Sandtime.io. Verify with claude mcp list and confirm sandtime shows as connected. If OAuth is unavailable, ask me for a Sandtime.io API key and add the server with the header Authorization set to "Bearer <key>" instead.Check your plan. Access to MCP can depend on the assistant and the plan you are on, which is outside Sandtime.io. If nothing connects even though the setup looks right, start by checking what your plan allows.
Prefer your editor? Add the server with one click, then sign in to Sandtime.io when it opens. The link carries no key.
Works with more clients
- Codex CLI
- Add the server URL with a Bearer API key header. Current Codex releases do not finish browser sign-in.
- Gemini CLI
- Add the server URL as an HTTP MCP server in Gemini CLI's settings. Sign in where supported, otherwise send a Bearer API key header.
- GitHub Copilot
- Add the server URL to VS Code's MCP config and use it from Copilot Chat agent mode. Sign in where supported, otherwise send a Bearer API key header.
- Cursor
- Use the Add to Cursor button above, or add the server URL as an MCP server manually. Sign in where supported, otherwise send a Bearer API key header.
- Any MCP client
- Any client that speaks MCP over Streamable HTTP works the same way. Sign in where supported, otherwise send a Bearer API key header.
Rather not connect anything?
Sandbot is the assistant built into Sandtime.io, so there is no connector, no server URL, and no client to configure. Ask it to log time, summarize your week, or pull a report from inside the app. AI time tracking covers what it does and how to switch it on.
Building an agent of your own? Many agentic systems work happily against the plain Sandtime.io REST API, authenticated with an API key you create in Settings > Integrations > API.
For developers: API keys and config files
Some clients need a config file or a header instead of browser sign-in - the Codex CLI in particular. For those, create an API key and follow the per-client setup below. Replace YOUR_API_KEY with your own key.
Keys come from Settings > Integrations > API in the app, or from Settings > Integrations > MCP. A key is shown once, at creation, and can be revoked any time from the API page. For step-by-step instructions, see Create and manage API keys and MCP tokens.
Claude Desktop
Claude Desktop connects to Sandtime.io through mcp-remote, which npx fetches on demand, so Node has to be on the machine. Everything else is one JSON file.
Open the config file
Claude Desktop opens it for you from Settings > Developer > Edit Config. If that menu is not there, or the file will not open, the direct path to the file is below.
- macOS
- ~/Library/Application Support/Claude/claude_desktop_config.json
- Windows
- %APPDATA%\Claude\claude_desktop_config.json
Add the server
The file holds the rest of your Claude Desktop settings, so add to it rather than replacing it. Which snippet you need depends on whether the file already has an mcpServers block.
If there is no mcpServers block yet, add this as a new key next to your other settings, with a comma in between.
"mcpServers": {
"sandtime": {
"command": "npx",
"args": [
"mcp-remote",
"https://mcp.sandtime.io/mcp",
"--header",
"Authorization:${AUTH}"
],
"env": { "AUTH": "Bearer YOUR_API_KEY" }
}
}If mcpServers exists already, paste this inside it, with a comma before any server currently listed.
"sandtime": {
"command": "npx",
"args": [
"mcp-remote",
"https://mcp.sandtime.io/mcp",
"--header",
"Authorization:${AUTH}"
],
"env": { "AUTH": "Bearer YOUR_API_KEY" }
}A Windows gotcha
On Windows, check the Authorization:${AUTH} line above for a stray space. A space after the colon breaks the connection, and Claude Desktop returns a 401 authentication error that gives no clue why.
Restart, then check
MCP servers only load at startup and are never checked again, so the new one will not work until you quit the app completely and reopen it, not just close the window. Then ask it something simple about the app, like your projects or tracked hours. A sensible answer back means the key, the URL and the header are all fine.
A Claude Code session started inside the desktop app reads this same file, so one entry covers both the chat and the Code tab. The standalone CLI in your terminal does not read it and has its own section below.
Claude Code
For the CLI in your terminal. A Claude Code session started from inside the desktop app reads the desktop config instead, so use the Claude Desktop section above for that one. What separates the options below is their scope.
A project file that gets committed should reference an environment variable instead of a literal key. Set SANDTIME_API_KEY locally and use Bearer ${SANDTIME_API_KEY} for Authorization. Real keys should never live in a repository, so revoke and replace one if it ever ends up there.
Per user
Writes the configuration to ~/.claude.json (~ is %USERPROFILE% on Windows), so the server is waiting for you in every project you open on this machine.
claude mcp add --transport http --scope user sandtime https://mcp.sandtime.io/mcp --header "Authorization: Bearer YOUR_API_KEY"Per project
The same command with --scope project, which writes .mcp.json in the current directory, so Claude Code only finds it in this one project. That file is meant to be committed. Prefer the per-user scope if you want the server available everywhere instead.
claude mcp add --transport http --scope project sandtime https://mcp.sandtime.io/mcp --header "Authorization: Bearer YOUR_API_KEY"Manual installation
The entry is the same wherever it goes, only the file decides how far it reaches. Each of these files holds other settings too, so add to it rather than replacing it.
- Per user (macOS, Linux)
- ~/.claude.json
- Per user (Windows)
- %USERPROFILE%\.claude.json
- Per project
- .mcp.json
If there is no mcpServers block yet, add this as a new key next to your other settings, with a comma in between.
"mcpServers": {
"sandtime": {
"type": "http",
"url": "https://mcp.sandtime.io/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}If mcpServers exists already, paste this inside it, with a comma before any server currently listed.
"sandtime": {
"type": "http",
"url": "https://mcp.sandtime.io/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}If something does not work, claude mcp list shows every server and whether it connected, which is the quickest way to tell a rejected key from a wrong URL. claude mcp remove sandtime takes the entry back out.
ChatGPT / Codex
For the ChatGPT desktop app, the Codex CLI, and the IDE extension, which share one configuration. ChatGPT on the web reads none of it, so nothing set up here reaches a browser conversation.
Or send this to your AI agent and it will set up the connection for you:
Set up the Sandtime.io MCP server for Codex. First run codex mcp get sandtime to check whether it already exists. If it does not, add it as a Streamable HTTP server at https://mcp.sandtime.io/mcp with the header Authorization set to "Bearer ${SANDTIME_API_KEY}". If SANDTIME_API_KEY is not set, ask me to create a Sandtime.io API key in Settings > Integrations > API and export it. Current Codex releases can reject OAuth, so use this API key path rather than browser sign-in.Committing the project file? Use bearer_token_env_var with SANDTIME_API_KEY instead of a literal header. Real keys should never live in a repository, so revoke and replace one if it ever ends up there.
Connect a custom MCP
Open Settings > Plugins > MCPs, click Add, then Add MCP server to reach the connect screen. Pick Streamable HTTP over STDIO. The URL below goes in the address field, and the header name and value together under Headers. The screen also has Bearer token env var and Headers from environment variables fields, but those pass secrets a different way, so leave them empty.
- URL
- https://mcp.sandtime.io/mcp
- Header name
- Authorization
- Header value
- Bearer YOUR_API_KEY
Save and switch it on
Save, then switch the entry on in the list. Adding a server does not enable it. There is no scope to choose on this screen, so this always lands in the per-user file. A chat or task already open before you added the server will not see it either - start a new one. If the server still does not show up, restarting the app usually helps.
In config.toml, per user or per project
The same entry added by hand, appended to whatever the file already holds. The per-user file works the same way in the desktop app, the CLI, and the IDE extension. The per-project file is narrower: it only works in the CLI and the IDE extension, only in a project you trust.
- Per user (macOS, Linux)
- ~/.codex/config.toml
- Per user (Windows)
- %USERPROFILE%\.codex\config.toml
- Per project
- .codex/config.toml
[mcp_servers.sandtime]
url = "https://mcp.sandtime.io/mcp"
[mcp_servers.sandtime.http_headers]
Authorization = "Bearer YOUR_API_KEY"How the files layer
Project files are read from the repository root down to your current directory, with the closest one winning, and the per-user file underneath them all. If CODEX_HOME is set, the per-user file lives there instead of in your home directory.
The trust catch
Codex reads project files only in a project you have marked as trusted; in an untrusted one it skips them without saying anything. If a server never shows up, check trust before checking the config itself.
The codex mcp add command is no help for a key like this. It writes only to the per-user file, and it cannot set a static header at all, just the name of an environment variable to read later. That leaves the app screen and the file as the two ways in.
If the server still will not connect after this, turning on Developer mode in ChatGPT settings might fix it.
Any other client that speaks MCP over Streamable HTTP works the same way, as long as it can send a custom header. Ask your assistant to list your projects: if real project names come back, the connection is working.
Where it runs
One HTTP server, every AI surface you use. Connect once and work from wherever you already are.
Claude.ai (Web)
Add the connector in your browser and track time from any Claude.ai chat.
Claude Desktop
Add the same remote connector in the desktop app and ask it to track and report your time.
ChatGPT (Web)
Add the connector once and log time from any ChatGPT conversation.
ChatGPT Desktop
The same connector, already waiting when you open the desktop app with the same account.
Claude Code
Add the server from your terminal, sign in once, and log time where you ship code.
Codex CLI
Add the server URL with an API key header and turn coding sessions into clean time records.
Gemini CLI
Add the server in Gemini CLI's settings and track your time without leaving the terminal.
GitHub Copilot
Add the server to VS Code and ask Copilot Chat in agent mode what you worked on.
Cursor
Add the server with one click and turn what you just built into a time entry.
Any MCP client
Any client that speaks the Model Context Protocol over Streamable HTTP can connect, with browser sign-in or an API key.
Available tools
The server exposes 37 tools across your whole workspace. Assistants chain them together - for example, resolving the current user, checking the calendar, then filling empty days.
Activities
list_activitiesList time entries, filtered by user, project, or a whole week. Returns formatted durations and local times.get_activityGet the full details of a single time entry by its ID.create_activityLog a new time entry on a project, with automatic overlap detection against existing entries.update_activityEdit a time entry’s name, times, project, or billable status, or stop and resume a running timer.delete_activityPermanently remove a time entry. Requires ownership or administrator permissions.stop_activityStop a running timer by setting its end time to now.
Projects
list_projectsList the projects in your organization, optionally including archived ones.get_projectGet detailed information about a specific project.create_projectCreate a new project. Requires administrator permissions.update_projectRename a project, change its billable default, archive it, or edit its notes.delete_projectReturns a deep link to the project settings, where a human confirms the deletion.
Project members
list_project_membersList the members assigned to a specific project.add_project_memberReturns a deep link to the project members section, where a human adds the member.remove_project_memberReturns a deep link to the project members section, where a human removes the member.
Users
list_usersList the users in your organization.get_userGet detailed information about a specific user.get_current_userGet the caller’s ID, timezone, and the server-resolved current date and week. Usually the first call in a workflow.create_userReturns a deep link to the member invite page.update_userReturns a deep link to the user profile page.delete_userReturns a deep link to the delete account section. Removing a user is destructive, so the assistant hands it back to a human.
Organization
get_organizationGet information about your organization, including its settings.update_organizationReturns a deep link to the organization settings page.delete_organizationReturns a deep link to the organization settings page. This is the most destructive action in the product, so the assistant never performs it.
Calendar
get_calendarGet a server-computed calendar with workdays, expected hours, weekends, and public holidays. The source of truth before logging time across days.
Reports
list_reportsList the saved reports in your organization.get_reportGet the details of a specific report.create_reportBuild a saved report with custom dimensions, metrics, periods, and project or member filters.update_reportChange a saved report by ID. Only the fields you pass are touched. Requires being its creator or an administrator.delete_reportDelete a saved report by ID. It removes the report configuration only and leaves tracked time untouched.
Timesheets
get_timesheet_statusCheck the lock status of timesheets for a specific week.lock_timesheetLock a week’s timesheet for a user. Requires administrator permissions.unlock_timesheetRemove an existing timesheet lock. Requires administrator permissions.
Requests
list_requestsList approval requests such as timesheet unlocks and role changes. Defaults to pending requests.request_timesheet_unlockAsk an administrator to unlock a locked week so the timesheet can be edited.approve_unlock_requestApprove a pending unlock request, giving the user a short window to edit. Requires administrator permissions.reject_unlock_requestReject a pending unlock request. The user is notified.
Summary and analytics
get_time_summarySummarize tracked time over a period, grouped by day, week, month, project, or user.
Try the AI features free
The Sandtime.io MCP server is free and available now - just connect your assistant to get started.
Connect your assistant