Server details
MCP clients use the same URL as the server endpoint and the OAuth resource.
https://doubletime.io/mcpPaste this URL when your MCP client asks for the DoubleTime server.
https://doubletime.io/mcpMCP clients request this resource and must include the mcp scope before tool calls are accepted.
Connection flow
- Add the server
Add the MCP endpoint to an OAuth-capable MCP client such as Codex, Claude Code, Gemini CLI, OpenCode, Cursor, or ChatGPT.
- Approve OAuth access
DoubleTime opens an approval screen where the user can review the client name, access target, and requested scopes.
- Use tools through the client
The MCP client calls DoubleTime tools with the approved bearer token. Each tool still checks its required scopes.
- Review or revoke later
Connected MCP clients appear in DoubleTime Connected Apps, where access can be reviewed or revoked.
Connect from CLI tools
These clients connect to the same DoubleTime MCP endpoint and complete access through OAuth. Approve only the scopes the agent needs for the work it will perform.
Codex CLI
Codex authenticates MCP servers from the shell, separate to an interactive Codex session.
- Add the server
codex mcp add doubletime --url https://doubletime.io/mcp - Start OAuth
codex mcp login doubletimeCodex opens the browser approval flow and stores the approved grant for this MCP server.
Claude Code
Add the remote HTTP server. Claude Code will use OAuth discovery when the server requires authentication.
- Add the server
claude mcp add --transport http doubletime https://doubletime.io/mcp - Authenticate in Claude Code
claude /mcpClaude opens the MCP panel. Select DoubleTime, then start the authentication flow.
Gemini CLI
Add the streamable HTTP server. Gemini CLI handles OAuth discovery for remote MCP servers.
- Add the server
gemini mcp add --transport http doubletime https://doubletime.io/mcp - Authenticate in Gemini CLI
gemini /mcp auth doubletimeGemini starts OAuth for the named server and opens the browser approval flow.
OpenCode
Add DoubleTime as a remote MCP server. OpenCode handles OAuth for authenticated remote MCP servers.
- Add the server
opencode mcp addChoose remote, then enter these details when prompted.
Server namedoubletimeServer URLhttps://doubletime.io/mcp - Authenticate in OpenCode
opencode mcp auth doubletimeOpenCode starts OAuth for the named server and opens the browser approval flow.
Bearer token access
OAuth is preferred for interactive AI tools because each client can request access through the approval screen. Headless agents can also connect with a static bearer token when the MCP client supports custom HTTP headers.
Token requirements
- Use a fine-grained API token, not a legacy dt_ token.
- Select the MCP resource and include the mcp scope.
- Add only the tool scopes the agent needs, such as tasks:read or invoices:write.
- Store the token as a secret and rotate it when the agent host changes.
Header format
Authorization: Bearer <dtfg_token>Configure the token on the MCP client or agent host that calls https://doubletime.io/mcp. Each tool call still checks the scopes on that token.
Available MCP tools
Tool availability depends on the approved scopes and the account's subscription. Detailed payload rules are available inside the MCP server at doubletime://docs/tools.
Permissions and availability
Every MCP connection needs the mcp scope. Write tools also require the matching read scope; settings scopes are not available on the MCP resource. Subscription-only tools appear when the account has access.
Tool responses are scope-aware. A tool can succeed while omitting nested related records when the approved client does not have the related read scope.
| Area | Tools | Scopes |
|---|---|---|
| Profile | profile.get | profile:read |
| Tasks | tasks.listtasks.gettasks.notestasks.invoice_import_candidatestasks.createtasks.updatetasks.deletetasks.reorder | tasks:readtasks:write |
| Time entries | time_entries.listtime_entries.gettime_entries.createtime_entries.updatetime_entries.delete | time:readtime:write |
| Clients and projects | clients.listclients.getclients.createclients.updateclients.deleteprojects.listprojects.getprojects.createprojects.updateprojects.delete | clients:readclients:writeprojects:readprojects:write |
| Tags and rules | tags.listtags.createtags.updatetags.deleterules.listrules.getrules.createrules.updaterules.toggle_enabledrules.delete | tags:readtags:writerules:readrules:write |
| Invoices | invoices.listinvoices.getinvoices.createinvoices.updateinvoices.deleteinvoices.previewinvoices.send | invoices:readinvoices:writeinvoices:send |
| Invoice deposit candidates | invoices.deposit_candidates | invoices:read |
| Invoice import | invoices.import_candidates | invoices:readtasks:readtime:read |
| Invoice details | invoice_payments.listinvoice_payments.recordinvoice_payments.deleteinvoice_payment_receipts.sendinvoice_adjustments.listinvoice_adjustments.createinvoice_adjustments.deleteinvoice_artifacts.listinvoice_artifacts.deleteinvoice_dispatches.listinvoice_dispatches.resend | invoices:readinvoices:writeinvoices:send |
| Invoice expense candidates | invoices.expense_candidates | invoices:readexpenses:read |
| Link selected expense attachments to an invoice | invoice_artifacts.copy_from_expense | invoices:readinvoices:writeexpenses:read |
| Expenses | expenses.listexpenses.getexpenses.createexpenses.updateexpenses.deleteexpense_categories.listexpense_artifacts.listexpense_artifacts.delete | expenses:readexpenses:write |
| Reports | reports.summaryreports.task_timereports.daily_timereports.incomereports.taxreports.receivablesreports.unbilled_wipreports.collectionsreports.client_healthreports.billing_pipelinereports.billing_coveragereports.unpaid_invoicesreports.billed_vs_collectedreports.tax_liabilityreports.timesheetreports.project_time_breakdownreports.tag_time_breakdownreports.expensesreports.profit_loss | reports:read |
| Billing Hub | billing_hub.summarybilling_hub.invoice_selection | billing:read |
Invoice and expense workflows
Recording expenses
Reading expenses and deleting draft expenses remain available on every plan with the required scopes. Creating or updating expense financial records requires an active subscription.
Adding expenses to invoices
Listing invoice expense candidates requires an active subscription, invoices:read and expenses:read. Adding, removing, or reassigning expense links requires expenses:write and expenses:read alongside invoices:write and invoices:read, plus an active subscription. Updates that preserve existing expense links keep the base invoice access requirements.
Sharing supporting receipts is a separate step, described in Working with attachments.
Importing tasks
For task imports into an existing invoice, prefer invoices.import_candidates. Use tasks.invoice_import_candidates before a draft exists.
Reading expense reports
reports.expenses and reports.profit_loss require reports:read and an active subscription. They use finalised documents by expense or invoice date, regardless of payment timing. Profit and loss values exclude tax; mixed currencies are not automatically converted.
Deposit invoices
Create and collect a deposit
Use workflows.get with workflow invoice.create_draft before creating a deposit, then call invoices.create with payload.type set to deposit. Creating or finalising one requires an active Pro subscription and invoices:read plus invoices:write. Omit type or use standard for an ordinary invoice; an invoice cannot change type after creation.
{
"name": "invoices.create",
"arguments": {
"payload": {
"type": "deposit",
"clientId": 77,
"invoiceDate": "2026-09-28",
"dueDate": "2026-10-28",
"finalize": false,
"items": [
{
"description": "Website project deposit",
"quantity": 1,
"quantityUnit": "unit",
"unitPrice": 300,
"taxRateId": 3
}
]
}
}
}Example tools/call parameters. Replace clientId and taxRateId with account records.
This creates a draft for 300 before tax. Use taxRateId null for an untaxed deposit. Finalise using invoices.update with payload.finalize true, preserving the existing items, then send through invoices.send when requested. Record money actually received using invoice_payments.record; paidTotal includes tax. invoice_payment_receipts.send issues the payment receipt. Sending invoices or receipts also requires invoices:send.
Apply a paid deposit
Call workflows.get with workflow invoice.apply_deposit, then invoices.get for the work invoice and invoices.deposit_candidates with its id. The candidate tool needs only invoices:read and returns { count, items } without pagination. Only choose a candidate with unavailableReason null: it must be finalised, paid in full and match the contact and currency. The reasons unpaid and currency explain why a candidate cannot be used.
availableAmount is before tax, excludes other invoices' reservations and includes the current invoice's existing draw. taxRateId identifies the rate to retain; taxTotal and availableTaxTotal describe the original and remaining tax. Ask which deposit and amount to use if the user has not specified them.
Use invoices.update with the full desired items array, preserving every existing item ID and link field that should remain. Add a line with depositInvoiceId, quantity 1, quantityUnit unit, the candidate taxRateId and a negative unitPrice for the amount before tax. This example assumes invoice 456 contains only work item 789 and draws 300 from paid deposit 123. Replace the IDs, description and tax rate with the actual records.
{
"name": "invoices.update",
"arguments": {
"id": 456,
"payload": {
"items": [
{
"id": 789,
"description": "Website work",
"quantity": 1,
"quantityUnit": "unit",
"unitPrice": 1000,
"taxRateId": 3
},
{
"depositInvoiceId": 123,
"description": "Deposit paid, invoice 336",
"quantity": 1,
"quantityUnit": "unit",
"unitPrice": -300,
"taxRateId": 3
}
]
}
}
}Example tools/call parameters. Read the invoice first and preserve its other items.
Applying a paid deposit remains available on every plan with invoices:read and invoices:write. The amount must have at most two decimal places, fit within availableAmount and leave both the invoice subtotal and total nonnegative. The server calculates the tax credit, including rounding. Use the saved totals; do not record a second payment for the deduction. Re-read candidates if another update changes what is available.
Track remaining deposits
Use invoices.list with type deposit to list deposits. Invoice responses include type and a deposit summary with amount, usedAmount, availableAmount and draws, using amounts before tax. A deposit can cover several invoices. Draft items reserve their amounts, and removing a deposit item releases its amount. Retained items must keep their depositInvoiceId.
Deposit invoice items must share one tax rate and cannot link tracked time, expenses or other deposits. Deposit invoices cannot have adjustments. Once drawn on, the source deposit's contact, tax and item amounts are locked. Refunds of unused deposits are not supported. The MCP server also publishes these rules in doubletime://docs/tools and its invoicing workflow resource.
Working with attachments
Add new Google Drive files in the DoubleTime app, then use MCP to manage existing attachments or share selected expense receipts. Invoice recipients can download invoice attachments; expense attachments remain private until explicitly shared. Confirm the exact attachments and destination first.
Adding Google Drive files in the app
New Google Drive file linking through MCP is suspended. Open the saved expense or invoice and use Google Picker in the DoubleTime app for first-time file selection and authorisation. The Google connection uses per-file access through drive.file; access granted to a separate Drive connector does not grant DoubleTime access.
MCP cannot open Picker, grant Google permissions or upload files. Existing attachment listing, removal and explicit receipt sharing remain available.
Sharing expense receipts
Use expense_artifacts.list to list receipts and obtain the user's exact selection, then call invoice_artifacts.copy_from_expense. It requires invoiceId, expenseId and an explicit, nonempty expenseArtifactIds array; omission never means all receipts.
Sharing requires an active subscription and invoices:read, invoices:write and expenses:read. Each selection creates an independent invoice link to the same file, not a copy of its contents.
{
"name": "invoice_artifacts.copy_from_expense",
"arguments": {
"invoiceId": 456,
"expenseId": 123,
"expenseArtifactIds": [
789
]
}
}Use attachment IDs from expense_artifacts.list, not Google Drive file IDs.
Results and retries
Sharing selected expense receipts returns { count, items } with attachment metadata. Failed batches create no links; repeating a selection returns existing links without duplicates. If the invoice was created but receipt sharing failed, keep its ID and retry sharing rather than creating another invoice.
Availability and removal
Removing an attachment link does not delete its Google file or another document's link. Existing downloads depend on Google authorisation and file availability, not an active subscription. Attachment-link removal remains available on every plan with the required scopes.
Built-in guidance
The MCP server publishes its own documentation resources and prompts, so an agent can read the rules before it acts.
Docs resources
| Resource | Covers |
|---|---|
doubletime://docs/overview | High-level MCP behavior and permission guidance. |
doubletime://docs/tools | Tool-by-tool scopes, payload expectations, and usage rules. |
doubletime://docs/workflows/time-tracking | Workflow guidance for creating tasks and managing timers. |
doubletime://docs/workflows/invoicing | Workflow guidance for drafting, importing time, adding expenses, creating and applying deposits, previewing, sending, and recording invoice payments. |
doubletime://docs/workflows/expenses | Workflow guidance for recording supplier bills, categorising lines, and finalising expenses. |
Prompts
| Prompt | Covers |
|---|---|
doubletime.tool_usage | Explains how an agent should choose tools and read DoubleTime MCP documentation. |
doubletime.time_tracking_workflow | Guides a time tracking workflow. |
doubletime.invoice_workflow | Guides an invoicing workflow. |
doubletime.expense_workflow | Guides an expense recording and finalisation workflow. |
Safe use
- Approve only the scopes needed for the task, and keep bearer tokens out of prompts and shared configuration.
- Confirm the intended records and changes before using tools that write to the account.
- Treat send, resend, receipt, preview and delete tools as deliberate user actions.
- Treat Access denied and Resource not found as permission or ownership boundaries, not errors to work around.
Related docs
Read the OAuth guide for consent details, or review DoubleTime's privacy policy and terms before connecting a client.