ワンクリックで
productive-mcp
MCP server for Productive.io - use with Claude Desktop or MCP-compatible clients for time tracking, projects, and tasks
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
MCP server for Productive.io - use with Claude Desktop or MCP-compatible clients for time tracking, projects, and tasks
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | productive-mcp |
| description | MCP server for Productive.io - use with Claude Desktop or MCP-compatible clients for time tracking, projects, and tasks |
MCP (Model Context Protocol) server for Productive.io. Provides a single unified tool for all operations.
Before your first interaction with any resource, call action=help with that resource to discover valid filters, required fields, includes, and examples.
There are several ways to find docs — use whichever fits:
search_docs — the global front door. No query returns a table of contents across all domains; a query (e.g. "invoices", "billing") returns ranked matches across resources, raw API endpoints, and the run_script scripting API, each pointing at the tool to drill in. Best when you don't know where to look.productive action=help — per resource (filters, fields, includes, examples), or with a query to search across all resources. action=schema for a compact spec.api_read search="<term>" — find documented raw endpoints by keyword; then describe=true with a path for its full spec.search_docs too — it appears in the table of contents and a matching query (e.g. "output", "productive") returns the full section.This server exposes one high-level tool, two low-level raw API tools, a sandboxed scripting tool (run_script), and a documentation-discovery tool (search_docs).
productiveSingle unified tool with this signature:
productive(resource, action, [parameters...])
| Resource | Actions | Description |
|---|---|---|
projects | list, get, resolve, context, help | Project management |
time | list, get, create, update, resolve, help | Time tracking |
tasks | list, get, create, update, resolve, context, help | Task management |
services | list, get, resolve, help | Budget line items |
people | list, get, me, resolve, help | Team members |
companies | list, get, create, update, resolve, help | Client companies |
comments | list, get, create, update, help | Comments on tasks/deals |
attachments | list, get, delete, help | File attachments |
timers | list, get, start, stop, help | Active timers |
deals | list, get, create, update, resolve, context, help | Sales deals & budgets (use filter[type]=2 for budgets) |
bookings | list, get, create, update, help | Resource scheduling |
pages | list, get, create, update, delete, help | Wiki/docs pages |
discussions | list, get, create, update, delete, resolve, reopen, help | Discussions on pages |
activities | list, help | Activity feed (audit log of create/update/delete events) |
custom_fields | list, get, help | Custom field definitions and option values |
reports | get, help | Generate reports |
workflows | complete_task, log_day, weekly_standup, help | Compound workflows chaining multiple operations |
Use action: "help" to get detailed documentation for any resource:
{
"resource": "time",
"action": "help"
}
Returns filters, fields, includes, and examples for that resource.
run_script)For advanced multi-step logic — fetching across resources, filtering, aggregating, or
conditional flows — use run_script instead of many individual calls. It runs a
JavaScript/TypeScript script in a sandbox and returns the value the script returns plus any
buffered output, all in a single tool call.
The sandbox has no direct network or filesystem access — scripts cannot open sockets, call
fetch, reach arbitrary URLs, or read files. Productive API access is available: calls made
through the injected productive/api client are executed on the host (which performs the real
HTTP request) and go through the same validated, rate-limited pipeline as normal tool calls. This
keeps credentials out of the sandbox and constrains egress to the Productive API.
Disabled by default — the server operator must set PRODUCTIVE_MCP_ENABLE_RUN=true.
Discover the scripting API through search_docs — it lists the run_script topics in its table of contents, and a matching query (e.g. "output", "productive", "dry_run") returns the full section (globals, resources, output rendering, limits, examples).
| Parameter | Type | Description |
|---|---|---|
code | string | Required. JavaScript/TypeScript source to run. |
args | array | Positional strings exposed to the script as args. |
flags | object | Named values exposed to the script as flags. |
dry_run | boolean | Record mutating calls (create/update/delete/…) instead of executing. |
productive(resource, action, params) — low-level call, mirrors the productive tool.productive.<resource>.list(filter?, opts?), .get(id, opts?), .create(params), .update(id, params) — convenience accessors for data resources.api.read(path, opts?) / api.write(method, path, body) — raw API access.output.json(data), output.table(rows), output.csv(rows), output.log(...), output.info/warn/error/success(msg) — buffered output returned alongside the result.args (string[]) and flags (object) — the inputs above.return <value> to surface a result. await is supported.Imports/require are not available — use the injected globals only.
{
"name": "run_script",
"arguments": {
"code": "const projects = await productive.projects.list();\nconst tasks = await productive.tasks.list({ status: 'open' });\noutput.json({ projects: projects.length, openTasks: tasks.length });\nreturn 'summary ready';"
}
}
The response carries both forms (per the MCP structured-output convention): machine-readable
structuredContent as { result, output, _run: { apiCalls, dryRun } }, and a human-readable
Markdown rendering in the text block — output.table(rows) becomes a Markdown table,
output.csv/output.json become fenced code blocks, log lines are labelled, and the returned
value appears under Result. With dry_run: true, mutating calls are not executed and are
listed under _run.recorded.
PRODUCTIVE_MCP_RUN_TIMEOUT_MS (5000), PRODUCTIVE_MCP_RUN_MEMORY_MB (64),
PRODUCTIVE_MCP_RUN_MAX_API_CALLS (50), PRODUCTIVE_MCP_RUN_MAX_OUTPUT_KB (256),
PRODUCTIVE_MCP_RUN_MAX_CODE_KB (128).
To isolate script execution (memory/CPU/OOM) from the main server, the front can
delegate run_script to a separate runner over one stateless HTTP POST — agents see no
difference. Set on the front: PRODUCTIVE_MCP_RUN_RUNNER_URL (the runner's /run
endpoint; its presence enables run_script without the local ENABLE_RUN flag),
PRODUCTIVE_MCP_RUN_RUNNER_TOKEN (shared secret), and optionally
PRODUCTIVE_MCP_RUN_RUNNER_TIMEOUT_MS (30000). On the runner (HTTP transport): set
PRODUCTIVE_MCP_RUN_RUNNER_TOKEN (activates the /run endpoint) and
PRODUCTIVE_MCP_ENABLE_RUN=true. The /run contract is stateless and must not be retried
at the proxy layer (a non-dry-run script may mutate), so any load balancer works in front
of a runner pool.
| Parameter | Type | Description |
|---|---|---|
resource | string | Required. Resource type (see table above) |
action | string | Required. Action to perform |
id | string | Resource ID (for get, update, stop) |
filter | object | Filter criteria for list actions |
page | number | Page number (default: 1) |
per_page | number | Items per page (default: 20, max: 200) |
compact | boolean | Compact output (default: true for list, false for get) |
include | array | Related resources to include |
query | string | Text search (behavior varies by resource - may search related fields like project names) |
no_hints | boolean | Disable contextual hints in responses (default: false) |
Use human-friendly identifiers instead of numeric IDs. The server automatically resolves:
user@example.com → 500521PRJ-123 or P-123 → 777332D-456 or DEAL-456 → 888123Filters automatically resolve human-friendly values:
// Email resolved to person ID
{
"resource": "tasks",
"action": "list",
"filter": { "assignee_id": "user@example.com" }
}
// Project number resolved
{
"resource": "time",
"action": "list",
"filter": { "project_id": "PRJ-123" }
}
Response includes _resolved metadata showing what was resolved:
{
"data": [...],
"_resolved": {
"assignee_id": {
"input": "user@example.com",
"id": "500521",
"label": "John Doe"
}
}
}
Use human-friendly IDs directly in get actions:
{ "resource": "projects", "action": "get", "id": "PRJ-123" }
{ "resource": "people", "action": "get", "id": "user@example.com" }
{ "resource": "deals", "action": "get", "id": "D-456" }
resolve ActionLook up resources by human-friendly identifiers:
// Resolve email to person
{ "resource": "people", "action": "resolve", "query": "user@example.com" }
// Resolve project number
{ "resource": "projects", "action": "resolve", "query": "PRJ-123" }
// Resolve with type hint (when pattern is ambiguous)
{ "resource": "time", "action": "resolve", "query": "Development", "type": "service", "project_id": "777332" }
Response:
{
"matches": [
{
"id": "500521",
"label": "John Doe",
"type": "person",
"exact": true
}
],
"query": "user@example.com",
"detected_type": "person"
}
// List projects
{ "resource": "projects", "action": "list" }
// Search projects
{ "resource": "projects", "action": "list", "query": "website" }
// Get project details
{ "resource": "projects", "action": "get", "id": "12345" }
// Filter active projects
{ "resource": "projects", "action": "list", "filter": { "archived": "false" } }
// List my time entries for a date range
{
"resource": "time",
"action": "list",
"filter": {
"person_id": "me",
"after": "2024-01-15",
"before": "2024-01-21"
}
}
// Create time entry (time in MINUTES)
{
"resource": "time",
"action": "create",
"service_id": "12345",
"date": "2024-01-16",
"time": 480,
"note": "Development work"
}
// Update time entry
{
"resource": "time",
"action": "update",
"id": "67890",
"time": 240,
"note": "Updated note"
}
// List open tasks for a project
{
"resource": "tasks",
"action": "list",
"filter": { "project_id": "12345", "status": "open" }
}
// Get task with comments
{
"resource": "tasks",
"action": "get",
"id": "67890",
"include": ["comments", "assignee"]
}
// Search tasks by title or project name
{ "resource": "tasks", "action": "list", "query": "bug fix" }
{ "resource": "tasks", "action": "list", "query": "crosscall" } // Also matches project names
// Create task
{
"resource": "tasks",
"action": "create",
"title": "New task",
"project_id": "12345",
"task_list_id": "111"
}
// Get current user
{ "resource": "people", "action": "me" }
// List people
{ "resource": "people", "action": "list" }
// Search by name
{ "resource": "people", "action": "list", "query": "john" }
// List services for a deal (budget line items) — prefer this over project_id when you have a deal
{
"resource": "services",
"action": "list",
"filter": { "deal_id": "12345" }
}
// List services for a project
{
"resource": "services",
"action": "list",
"filter": { "project_id": "12345" }
}
// List comments on a task
{
"resource": "comments",
"action": "list",
"filter": { "task_id": "12345" }
}
// Add comment
{
"resource": "comments",
"action": "create",
"task_id": "12345",
"body": "Looking good!"
}
// Add hidden comment (hidden from client)
{
"resource": "comments",
"action": "create",
"task_id": "12345",
"body": "Internal note",
"hidden": true
}
// Toggle comment visibility
{
"resource": "comments",
"action": "update",
"id": "67890",
"hidden": false
}
// List active timers
{ "resource": "timers", "action": "list" }
// Start timer on a service
{ "resource": "timers", "action": "start", "service_id": "12345" }
// Stop timer
{ "resource": "timers", "action": "stop", "id": "67890" }
// Time report by person
{
"resource": "reports",
"action": "get",
"report_type": "time_reports",
"group": "person",
"from": "2024-01-01",
"to": "2024-01-31"
}
// Budget report for a project
{
"resource": "reports",
"action": "get",
"report_type": "budget_reports",
"filter": { "project_id": "12345" }
}
// List pages for a project
{ "resource": "pages", "action": "list", "filter": { "project_id": "12345" } }
// Get page details
{ "resource": "pages", "action": "get", "id": "67890" }
// Create a page
{
"resource": "pages",
"action": "create",
"title": "Getting Started",
"project_id": "12345"
}
// Create a sub-page
{
"resource": "pages",
"action": "create",
"title": "Installation",
"project_id": "12345",
"parent_page_id": "67890"
}
// Delete a page
{ "resource": "pages", "action": "delete", "id": "67890" }
// List discussions on a page
{
"resource": "discussions",
"action": "list",
"filter": { "page_id": "12345" }
}
// List active discussions
{ "resource": "discussions", "action": "list", "status": "active" }
// Create a discussion
{
"resource": "discussions",
"action": "create",
"page_id": "12345",
"body": "This section needs review"
}
// Resolve a discussion
{ "resource": "discussions", "action": "resolve", "id": "67890" }
// Reopen a resolved discussion
{ "resource": "discussions", "action": "reopen", "id": "67890" }
Compound workflows that chain multiple operations into a single tool call.
// Complete a task (marks closed, posts comment, stops timers)
{
"resource": "workflows",
"action": "complete_task",
"task_id": "12345",
"comment": "All done! Tests passing.",
"stop_timer": true
}
// Complete a task without stopping timers
{
"resource": "workflows",
"action": "complete_task",
"task_id": "12345",
"stop_timer": false
}
// Log a full day across multiple services (time in minutes)
{
"resource": "workflows",
"action": "log_day",
"date": "2024-01-16",
"entries": [
{ "project_id": "100", "service_id": "111", "duration_minutes": 240, "note": "Frontend development" },
{ "project_id": "100", "service_id": "222", "duration_minutes": 120, "note": "Code review" },
{ "project_id": "200", "service_id": "333", "duration_minutes": 60, "note": "Client meeting" }
]
}
// Get weekly standup (this week)
{ "resource": "workflows", "action": "weekly_standup" }
// Get standup for a specific week (provide the Monday date)
{
"resource": "workflows",
"action": "weekly_standup",
"week_start": "2024-01-15"
}
// Get standup for a specific person
{
"resource": "workflows",
"action": "weekly_standup",
"person_id": "12345"
}
task — Updated task info (id, title, closed status)comment_posted — Whether the comment was successfully postedcomment_id — ID of the created comment (if posted)timers_stopped — Number of timers that were stoppederrors — Array of sub-step errors (partial results still returned)entries — Per-entry results with success, time_entry (on success), or error (on failure)succeeded / failed — Counts of successful and failed entriestotal_minutes_logged — Sum of minutes for successful entriescompleted_tasks — Tasks closed this week with project namestime_logged — Total minutes and breakdown by project (sorted by most time first)upcoming_deadlines — Open tasks due in the next 7 days with days_until_dueTip: Use
action: "help"on any resource to see the full, up-to-date list of filters, fields, and examples. Useaction: "schema"for a compact machine-readable spec.{ "resource": "tasks", "action": "help" } { "resource": "tasks", "action": "schema" }
queryMany resources support a query filter for full-text search. You can pass it either as a top-level shorthand or via the filter object (passthrough pattern):
// Shorthand (top-level)
{ "resource": "projects", "action": "list", "query": "website" }
// Filter passthrough (explicit)
{ "resource": "projects", "action": "list", "filter": { "query": "website" } }
Resources that support query: projects, tasks, people, companies, deals
person_id - Filter by person (use "me" for current user) (array)project_id - Filter by project (array)service_id - Filter by service (array)task_id - Filter by task (array)company_id - Filter by company (array)deal_id / budget_id - Filter by deal/budget (array)after / before - Date range (YYYY-MM-DD)date - Exact date (YYYY-MM-DD)status - Approval status: 1=approved, 2=unapproved, 3=rejectedbilling_type_id - Billing type: 1=fixed, 2=actuals, 3=non_billableinvoicing_status - Invoicing: 1=not_invoiced, 2=drafted, 3=finalizedinvoiced - Invoiced status (boolean)creator_id / approver_id - Filter by creator or approver (array)booking_id - Filter by booking (array)autotracked - Auto-tracked entries (boolean)query - Text search on task titleproject_id - Filter by project (array)company_id - Filter by company (array)assignee_id - Filter by assigned person (array)creator_id - Filter by task creator (array)status - Status: 1=open, 2=closed (or "open", "closed", "all")task_list_id - Filter by task list (array)task_list_status - Task list status: 1=open, 2=closedboard_id - Filter by board (array)workflow_status_id - Filter by workflow status/kanban column (array)workflow_status_category_id - Workflow category: 1=not started, 2=started, 3=closedworkflow_id - Filter by workflow (array)parent_task_id - Filter by parent task (for subtasks) (array)task_type - Task type: 1=parent task, 2=subtaskoverdue_status - Overdue: 1=not overdue, 2=overduedue_date_on / due_date_before / due_date_after - Due date filtersstart_date_before / start_date_after - Start date filtersafter / before - Created date rangeclosed_after / closed_before - Closed date rangeproject_manager_id - Filter by project manager (array)subscriber_id - Filter by subscriber/watcher (array)tags - Filter by tagsquery - Text search on project namecompany_id - Filter by company (array)project_type - Type: 1=internal, 2=clientresponsible_id - Filter by project manager (array)person_id - Filter by team member (array)status - Status: 1=active, 2=archivedproject_id - Filter by project (array)deal_id - Filter by deal (array)task_id - Filter by task (array)person_id - Filter by person/trackable by (array)name - Filter by service name (text match)budget_status - Status: 1=open, 2=deliveredstage_status_id - Stage: 1=open, 2=won, 3=lost, 4=delivered (array)billing_type - Type: 1=fixed, 2=actuals, 3=noneunit - Unit: 1=hour, 2=piece, 3=daytime_tracking_enabled / expense_tracking_enabled - Booleantrackable_by_person_id - Services trackable by a specific personafter / before - Date rangequery - Text search on name or emailemail - Filter by exact email addressstatus - Status: 1=active, 2=deactivatedperson_type - Type: 1=user, 2=contact, 3=placeholdercompany_id - Filter by company (array)project_id - Filter by projectrole_id - Filter by role (array)team - Filter by team namemanager_id - Filter by managercustom_role_id - Filter by custom roletags - Filter by tagsquery - Text search on company namename - Exact name matchcompany_code / billing_name / vat - Filter by specific fieldsstatus - Status (integer)archived - Archived status (boolean)project_id - Filter by project (array)subsidiary_id - Filter by subsidiary (array)default_currency - Filter by currency code (e.g. USD, EUR)query - Text search on deal namenumber - Filter by deal numbercompany_id - Filter by company (array)project_id - Filter by project (array)responsible_id - Filter by responsible person (array)creator_id - Filter by creator (array)pipeline_id - Filter by pipeline (array)stage_status_id - Stage: 1=open, 2=won, 3=lost (array)status_id - Filter by deal status (array)type - Type: 1=deal, 2=budgetdeal_type_id - Deal type: 1=internal, 2=clientbudget_status - Budget status: 1=open, 2=closedproject_type - Project type: 1=internal, 2=clientsubsidiary_id - Filter by subsidiary (array)tags - Filter by tagsrecurring - Recurring deals (boolean)needs_invoicing / time_approval - Boolean filtersNote: Budgets are deals with
budget=true. There is no separate/budgetsendpoint. Usefilter[type]=2to list only budgets.
person_id - Filter by person (array)service_id - Filter by serviceproject_id - Filter by project (array)company_id - Filter by company (array)event_id - Filter by event/absence (array)task_id - Filter by task (array)approver_id - Filter by approver (array)after / before - Date range (YYYY-MM-DD)started_on / ended_on - Exact start/end datebooking_type - Type: event (absence) or service (budget)draft - Tentative bookings only: true/falsewith_draft - Include tentative bookings: true/falsestatus / approval_status - Approval status (array)billing_type_id - Billing type: 1=fixed, 2=actuals, 3=none (array)person_type - Person type: 1=user, 2=contact, 3=placeholdercanceled - Canceled bookings (boolean)project_id - Filter by project (array)creator_id - Filter by creatorparent_page_id - Filter by parent page (for sub-pages)edited_at - Filter by last edited date (ISO 8601)page_id - Filter by pagestatus - Status: 1=active, 2=resolved (or "active", "resolved")task_id - Filter by taskproject_id - Filter by project (array)page_id - Filter by page (array)discussion_id - Filter by discussiondraft - Draft comments: true/falseworkflow_status_category_id - Filter by workflow status category (array)event - Event type: create, copy, update, delete, etc.type - Activity type: 1=Comment, 2=Changeset, 3=Emailafter / before - ISO 8601 timestamp rangeperson_id - Filter by person (array)project_id - Filter by project (array)company_id / task_id / deal_id / discussion_id - Filter by resource (array)item_type - Resource type (e.g. Task, Page, Deal, Workspace)parent_type / root_type - Parent/root resource typehas_attachments / pinned - Boolean filterscustomizable_type - Resource type: Task, Deal, Company, Project, Booking, Service, etc.archived - Archived status: true/falsename - Filter by field nameproject_id - Filter by projectglobal - Global custom fields: true/falseWorkflow to resolve custom field values:
custom_fields attribute (raw {field_id: value} hash)resource=custom_fields, action=list, filter={customizable_type: "Task"}resource=custom_fields, action=get, id=<field_id>, include=["options"]Data types: 1=Text, 2=Number, 3=Select, 4=Date, 5=Multi-select, 6=Person, 7=Attachment
person_id - Filter by persontime_entry_id - Filter by time entrystarted_at / stopped_at - Filter by start/stop time (ISO 8601)Fetch related data in a single request:
{
"resource": "tasks",
"action": "get",
"id": "12345",
"include": ["project", "project.company", "assignee", "comments"]
}
Common includes:
project, assignee, workflow_status, comments, subtasksperson, service, projectcompany, deal_status, responsiblecompact: true (default for list) - Returns minimal fieldscompact: false (default for get) - Returns full detailsForce full details on list:
{ "resource": "projects", "action": "list", "compact": false }
When fetching a single resource with action: "get", the response includes a _hints field with suggestions for related resources and common actions. This helps discover how to fetch additional context.
Certain responses include a _suggestions field with data-aware warnings and recommendations. Unlike _hints (which point to related resources), _suggestions draw attention to things that need action based on the data returned.
| Resource | Action | Suggestions generated |
|---|---|---|
tasks | list | ⚠️ overdue tasks count, ℹ️ unassigned tasks count |
tasks | get | ⚠️ task is N days overdue, ℹ️ no time entries |
time | list | 📊 total hours logged (or X/8h if filtered by today) |
summaries | my_day | ⚠️ no time logged today, ⏱️ timer running too long |
Example:
{
"data": [{ "id": "1", "title": "Fix bug", "due_date": "2024-01-01" }],
"_suggestions": ["⚠️ 1 task(s) are overdue", "ℹ️ 1 task(s) have no assignee"]
}
Suggestions are suppressed when no_hints: true is set.
Example response for a task:
{
"id": "16097010",
"title": "Fix login bug",
"_hints": {
"related_resources": [
{
"resource": "comments",
"description": "Get comments on this task",
"example": {
"resource": "comments",
"action": "list",
"filter": { "task_id": "16097010" }
}
},
{
"resource": "time",
"description": "Get time entries logged on this task",
"example": {
"resource": "time",
"action": "list",
"filter": { "task_id": "16097010" }
}
}
],
"common_actions": [
{
"action": "Add a comment",
"example": {
"resource": "comments",
"action": "create",
"task_id": "16097010",
"body": "<your comment>"
}
}
]
}
}
To disable hints, use no_hints: true:
{ "resource": "tasks", "action": "get", "id": "16097010", "no_hints": true }
To get full context for a task, follow these steps:
{ "resource": "tasks", "action": "get", "id": "16097010" }
The response includes _hints showing how to fetch related resources.
{
"resource": "comments",
"action": "list",
"filter": { "task_id": "16097010" }
}
{
"resource": "tasks",
"action": "get",
"id": "16097010",
"include": ["attachments"]
}
{
"resource": "time",
"action": "list",
"filter": { "task_id": "16097010" }
}
❌ Wrong: Trying non-existent endpoints like /activities, /notes, /task_comments
✅ Right: Use resource: "comments" with filter: { task_id: "..." }
❌ Wrong: Using include: ["comments"] on tasks (not supported)
✅ Right: Fetch comments separately with resource: "comments", action: "list"
Use action=context to fetch a resource along with all its related data in a single call. This replaces the multi-step approach described above.
Available for: tasks, projects, deals
{ "resource": "tasks", "action": "context", "id": "16097010" }
Returns: task details + comments + time entries + subtasks
{ "resource": "projects", "action": "context", "id": "12345" }
Returns: project details + open tasks + services + recent time entries
{ "resource": "deals", "action": "context", "id": "12345" }
Returns: deal details + services + comments + time entries
Note: Related data is limited to 20 items per type. For full listings, use separate
listcalls with appropriate filters.
Time is always in MINUTES:
Use raw API tools only as escape hatches when the unified productive tool does not support the documented endpoint you need.
api_readRead-only access to documented Productive GET endpoints.
Use it for: unsupported read endpoints, inspecting endpoint capabilities, or fetching raw shapes.
Parameters
path — required relative API path starting with /describe — return endpoint documentation instead of executingfilter — validated against the endpoint specinclude — related resources to includesort — validated sort valuespage, per_page — page number and size (per_page max 200)paginate, max_pages — safe auto-pagination (max_pages default 20, max 50)Safety model
GET onlyRecommended workflow
api_read with describe=trueExamples
{ "path": "/invoices", "describe": true }
{
"path": "/projects/123/tasks",
"filter": { "status": "open" },
"sort": ["due_date"],
"per_page": 50
}
api_writeRaw write access to documented Productive endpoints.
Use it only when: the user explicitly wants a mutation and the higher-level productive tool cannot perform it.
Parameters
method — required, one of POST, PATCH, PUT, DELETEpath — required relative API pathbody — request payloadconfirm — required, must be truedry_run — preview the normalized request without executing itSafety model
PRODUCTIVE_MCP_ENABLE_API_WRITE=trueconfirm=true on every calldry_run=true before the real writeAgent rules
api_write for routine mutations already covered by productiveapi_writedry_run=true first, then execute only after approvalExamples
{
"method": "PATCH",
"path": "/tasks/123",
"body": {
"data": {
"type": "tasks",
"id": "123",
"attributes": { "name": "Updated title" }
}
},
"confirm": true,
"dry_run": true
}
{
"method": "DELETE",
"path": "/attachments/456",
"confirm": true
}
In local/stdio mode, additional configuration tools are available:
// Configure credentials
productive_configure({
"organizationId": "...",
"apiToken": "...",
"userId": "..."
})
// View current config (token masked)
productive_get_config()
For data handling best practices, confirmation workflows, and error handling patterns, see the CLI skill documentation:
→ @studiometa/productive-cli/skills/SKILL.md
Key points:
action: "help" - Get resource documentation before using unfamiliar resourcescompact: false for detailed single-item viewsinclude to reduce round-trips when you need related dataquery for text search - behavior varies by resource but may include related fields (e.g., tasks query may match project names)people.me first to get the current user's ID for filters_hints - When getting a resource, check the _hints field for suggestions on fetching related context_suggestions - When present, _suggestions highlight data issues (overdue tasks, no time logged, etc.) that may need attention or should be surfaced to the userapi_read over api_write when a raw endpoint is neededapi_read.describe=true first before making raw API callsapi_write as break-glass access - confirm, dry-run, then executeThe server provides prompt templates (MCP prompts) that serve as guided conversation starters. Each prompt instructs the LLM which productive tool calls to make and how to format the output.
| Prompt | Arguments | Description |
|---|---|---|
end-of-day | format? (slack/email/plain) | Compose an end-of-day standup message |
project-review | project (required) | Analyze project health and status |
plan-sprint | project (required) | Prioritize tasks for next sprint |
weekly-report | person?, format? | Generate a weekly progress report |
invoice-prep | project, from, to (all required) | Prepare billing summary for a project |
End of day standup (Slack format):
Use the end-of-day prompt with format=slack. The LLM will call summaries.my_day and compose a Slack-formatted standup with what you did, what's next, and any blockers.
Project health review:
Use the project-review prompt with project=PRJ-123. The LLM will call projects.context and tasks.list to produce a RAG-status health report with budget burn, open tasks, and recommendations.
Sprint planning:
Use the plan-sprint prompt with project=PRJ-123. The LLM will fetch open tasks and budget services, then suggest a prioritized sprint scope with risk flags.
Weekly report (email format):
Use the weekly-report prompt with optional person=user@example.com and format=email. The LLM will call workflows.weekly_standup and format a polished report grouped by project.
Invoice preparation:
Use the invoice-prep prompt with project=PRJ-123, from=2025-01-01, to=2025-01-31. The LLM will fetch time entries, services, and deals for the period and produce invoice-ready line items.