Skip to main content

MCP Server

Original Workspace exposes an MCP (Model Context Protocol) server that lets external AI tools -- such as Cursor, Claude Desktop, or custom agents -- interact with your workspace data.

Base URL

All MCP communication happens over a single endpoint:

https://api-workspace.original.land/mcp

The server is stateless -- every request is self-contained and authenticated via API key. No sessions or persistent connections required.

MethodPurpose
POST /mcpSend JSON-RPC messages (initialize or call tools)

Authentication

Every request must include the x-api-key header with a valid API key. Any workspace member can create API keys in Settings > Profile > API Keys; each key is scoped to a workspace (and optionally to a single company) and is bound to the user who created it.

HeaderRequiredDescription
x-api-keyAlwaysYour API key (format: bsk_...). Determines workspace, company scope, and the acting user.

Permissions

The MCP path enforces the same role and module permissions as the app. A key acts with the permissions of the user who created it, so a tool call can never reach data or actions that the user could not access in the UI:

  • Role gating -- Each tool requires the same roles as the matching area in Settings > Members > Role permissions. For example, list_invoices / create_invoice are only available to admin and accounting; an agent run by a developer or sales user gets an access-denied error.
  • Module gating -- A tool is unavailable if its workspace module is disabled (e.g. invoice tools require the finance_collections module).
  • Company scoping -- For users limited to specific companies, list tools only return data from those companies.
  • User binding required -- Legacy keys not bound to a user are rejected; recreate the key to use the MCP API.

How it works

The server is fully stateless. Each POST /mcp request:

  1. Validates the API key and extracts the workspace/company scope.
  2. Builds a fresh MCP server with all available tools.
  3. Handles the JSON-RPC message and returns the response.

There are no sessions to manage, no SSE streams, and no cleanup required. This makes it compatible with horizontally-scaled deployments and simple to integrate.

Available tools

Projects

ToolDescriptionParameters
list_projectsList all projects in the workspacestatus? (in_progress, completed, invoiced)
get_projectGet full project details by IDprojectId (UUID)
create_projectCreate a new projectname (string), plus optional: clientId, companyId, offerId, taskPrefix, description, startDate, endDate, budget, estimatedHours, notes, currency
update_projectUpdate project fieldsprojectId (UUID), plus optional: name, description, status, startDate, endDate, budget, estimatedHours, notes, taskPrefix
update_project_statusChange project statusprojectId (UUID), status (in_progress, completed, invoiced)

Tasks

ToolDescriptionParameters
list_tasksList or search top-level tasks (includes childTaskCount, displayId, and derived isOverdue/isForecastLate flags). For scheduling / "when will it be done" questions use gantt_plan instead.Optional: projectIds (UUID[]), taskScope (me, my_team, all), targetUserId (UUID), query (string), taskNumber (number), projectPrefix (string), overdue (boolean)
get_taskGet full task details including subtasks, comments, and assigneestaskId (UUID)
create_taskCreate a new top-level tasktitle (string), plus optional: description, status, priority, estimatedHours, dueDate, projectId, assigneeIds
create_subtaskCreate a subtask under a parent task (inherits project, max 1 level)parentTaskId (UUID), title (string), plus optional: description, status, priority, estimatedHours, dueDate, assigneeIds, isPrivate
list_subtasksList all subtasks of a parent taskparentTaskId (UUID)
update_taskUpdate task fields (works for both tasks and subtasks)taskId (UUID), plus optional: title, description, status, priority, estimatedHours, actualHours, dueDate, sortOrder, projectId, assigneeIds, isPrivate
update_task_statusChange task status (works for both tasks and subtasks)taskId (UUID), status (todo, in_progress, frozen, done)
set_task_queue_positionPlace a task at a given slot of a user's Workload queue (mirrors drag&drop in the Carico view). Writes status=todo, assigns the user, and computes a sortOrder so the task lands at slotIndex. Reorders Gantt ghost bars of the same user automatically; solid bars (with startDate) keep their timeline position.taskId (UUID), userId (UUID), slotIndex (int, 0-indexed)
move_task_to_focusPromote a task to a user's Workload Focus slot (status=in_progress). If the user already had a different focus, that previous task is automatically demoted to slot #1 of their queue.taskId (UUID), userId (UUID)
gantt_planReturn Gantt bars for a time window: solid bars (tasks with startDate) plus auto-planned ghost bars (todo + in_progress tasks without startDate) packed in sortOrder after each user's solid workfrom (YYYY-MM-DD), to (YYYY-MM-DD), plus optional: taskScope (me, my_team, all), targetUserId (UUID), projectIds (UUID[]), statuses (string[]), search (string)

Clients

ToolDescriptionParameters
list_clientsList all clients in the workspace (the customers you invoice), sorted by company nameNone
create_clientCreate a new clientcompanyName (string), plus optional: firstName, lastName, email, phone, vatNumber, address, department, postalCode, city, country, vatRate, intermediary, commission, companyId
update_clientUpdate one or more fields of an existing clientclientId (UUID), plus optional: same fields as create_client

Offers

ToolDescriptionParameters
create_offerCreate a new offer/quoteOptional: subject, description, clientId, companyId, offerDate, validUntil, currency, notes, rows (line items), tranches (payment plan: each by percentage or amount)

Invoices

ToolDescriptionParameters
list_invoicesList invoices and credit notes. Credit notes (isCreditNote: true) are returned with already-negative amounts, matching the UI, the PDF and the dashboard statisticsOptional: status (draft, sent, partially_paid, paid), type (recurring, project, credit_note), clientId, limit
create_invoiceCreate a new invoice or credit note (totals are computed by the backend from the line items, VAT rate and rounding). Set isCreditNote to create a credit note: amounts are stored positive (negative input is normalized automatically, never failing) but are treated as negative in lists, PDF and statistics; numbering is shared with invoicesOptional: clientId, companyId, projectId, subject, description, status (draft, sent, partially_paid, paid), invoiceDate, dueDate, currency, vatRate, roundingAdjustment, collectedAmount, notes, paymentMethod, isCreditNote, originalInvoiceId, rows (line items)
generate_invoice_from_offer_trancheGenerate an invoice from an offer payment tranche (tranche must be to_invoice; it is marked invoiced and linked on success)Required: offerId, trancheId. Optional: clientId, companyId, subject, description, invoiceDate, dueDate, currency, vatRate, notes, paymentMethod, rows

Ideas

ToolDescriptionParameters
create_ideaCreate a new idea/proposaltitle (string), plus optional: description, estimatedBudget, currency, priority (1=low, 2=medium, 3=high), notes, companyId, clientId

Contacts

ToolDescriptionParameters
list_contactsList all CRM contacts (leads/prospects) in the workspace, most recent firstNone
create_contactCreate a new business contactOptional: companyName, contactName, email, phone, website, address, city, country, source, status, notes, nextFollowUp
update_contactUpdate one or more fields of an existing contactcontactId (UUID), plus optional: companyName, contactName, email, phone, status (new, contacted, qualified, proposal, negotiation, won, lost), source, notes, nextFollowUp, assignedTo, and the other contact fields

Activities

ToolDescriptionParameters
list_activitiesList CRM activities (calls, emails, meetings, etc.), mirroring the Activities pageOptional: contactId, clientId, collaboratorId, supplierId, type (call, email, meeting, lunch, visit, video_call, message, other), search
create_activityLog a new CRM activity linked to exactly one reference entitytitle (string), plus optional: type, description, one of contactId / clientId / collaboratorId / supplierId, activityDate, startDate, endDate, isAllDay, durationMinutes, isCompleted, completedAt, outcome, notes
update_activityUpdate one or more fields of an existing activityactivityId (UUID), plus optional: same fields as create_activity

AI Activities

ToolDescriptionParameters
track_ai_activityCreate a Workspace AI Activity for user-visible AI workkind, title, plus optional: source, description, agentName, status, companyId, aiTaskId, phases, resultMarkdown, metadata
update_ai_activity_phaseUpdate or append a phase and optionally update status/result markdownactivityId, phaseName, phaseStatus, plus optional: phaseSummary, phaseError, startedAt, finishedAt, activityStatus, resultMarkdown, replaceResultMarkdown
list_ai_activitiesList Workspace AI Activities with status, phases and result summariesOptional: kind, source, status, search, limit, offset
get_ai_activityGet one AI Activity with phases, metadata, result markdown and linked documentsactivityId (UUID)

Workspace Documents

ToolDescriptionParameters
create_workspace_documentCreate a first-class Workspace Document, optionally linked to an AI Activitytitle, kind, plus optional: source, description, companyId, mimeType, contentMarkdown, storage fields, activityId, relationship, metadata
update_workspace_documentUpdate a Workspace Document, including markdown contentdocumentId, plus optional: title, description, kind, source, companyId, mimeType, contentMarkdown, storage fields, metadata
list_workspace_documentsList Workspace Documents such as generated reports and notesOptional: kind, source, search, limit, offset
get_workspace_documentGet one Workspace Document with content and linked AI ActivitiesdocumentId (UUID)

Recordings

ToolDescriptionParameters
list_recordingsList the most recent audio recordings for the current userlimit? (number, default 10, max 10)
get_recordingGet one recording with summary, action items, notes, and transcriptionrecordingId (UUID)

Time Logs

ToolDescriptionParameters
list_time_logsList the current user's time logsstartDate? (YYYY-MM-DD), endDate? (YYYY-MM-DD)
time_log_summaryAggregated totals of the current user's time logs (totalHours, entryCount, byProject, byCategory), mirroring the personal TimesheetOptional: startDate, endDate, projectIds (UUID[])
list_time_categoriesList the workspace's active timesheet reasons (vacation, sick leave, internal meeting, training, ...). Use the returned id as categoryId when calling create_time_log for non-task activities.None
create_time_logCreate a new time log for the current user. Exactly one of taskId / categoryId must be provided (XOR). When categoryId is set you may also pass projectId to attach the activity to a project (e.g. an internal meeting on project Pippo); projectId is forbidden together with taskId.date (YYYY-MM-DD), startTime (HH:MM), endTime (HH:MM), one of taskId (UUID) or categoryId (UUID), plus optional: projectId (UUID, only with categoryId), description, isBillable, hourlyRate
update_time_logUpdate an existing time log. When swapping a slot between a task and a category, set the new field; the previous one (and any direct projectId) is cleared automatically. projectId is only valid on category-linked logs.timeLogId (UUID), plus optional: date, startTime, endTime, description, taskId, categoryId, projectId, isBillable, hourlyRate
delete_time_logDelete an existing time logtimeLogId (UUID)

Appointments

ToolDescriptionParameters
list_calendarsList calendars available to the current userNone
list_appointmentsList the current user's appointmentsstartDate? (YYYY-MM-DD), endDate? (YYYY-MM-DD)
create_appointmentCreate a new appointment in the current workspacedate (YYYY-MM-DD), startTime (HH:MM), endTime (HH:MM), plus optional: title, clientName, clientEmail, clientPhone, isAllDay, location (studio, online, home), address, onlinePlatform, onlineLink, notes, status, projectId
update_appointmentUpdate an existing appointmentappointmentId (UUID), plus optional: title, clientName, clientEmail, date, startTime, endTime, isAllDay, location, address, onlinePlatform, onlineLink, notes, status, projectId

Online Booking

ToolDescriptionParameters
get_booking_settingsGet the current user's online booking page configuration (slug, active status, weekly hours, slot duration, destination calendar, etc.)None
update_booking_settingsCreate or update the online booking page configurationAll optional: isActive (boolean), slotDuration (minutes), bufferMinutes, weeklyHours (object keyed "1".."7" for Mon..Sun, each value an array of { start, end } HH:MM ranges), maxDaysAhead, minimumNoticeMinutes, welcomeMessage, locationType (none, in_person, google_meet), locationAddress, bookingCalendarId (UUID), companyId
info

The create_task, create_subtask, create_offer, create_idea, create_activity, track_ai_activity, create_workspace_document, list_recordings, get_recording, list_time_logs, time_log_summary, list_time_categories, create_time_log, update_time_log, delete_time_log, list_calendars, list_appointments, create_appointment, update_appointment, get_booking_settings, and update_booking_settings tools require user context: they only work when the caller is tied to a specific user — either the AI Copilot session or an API key created for a specific user. API keys that are not bound to a user cannot call them.

Quick example

Initialize the connection and list all in-progress projects in a single request flow:

// POST /mcp
// Headers: x-api-key: bsk_your_api_key_here

{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
}
}
}

Then call a tool (same endpoint, same header):

// POST /mcp
// Headers: x-api-key: bsk_your_api_key_here

{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_projects",
"arguments": {
"status": "in_progress"
}
}
}

The server responds with a JSON array of project summaries (id, name, status, budget, client, etc.).

Security

  • Workspace isolation -- The API key determines which workspace data is accessible. Tools can only read/write data within that workspace.
  • Role & module enforcement -- Tools are gated by the acting user's role and the workspace's enabled modules, mirroring the in-app permission matrix. A key can never do more than its owner could in the UI.
  • Company scoping -- If the API key is scoped to a specific company, tools will only return and accept modifications to data belonging to that company. Users with access to a subset of companies only see those companies' data.
  • Own keys only -- Non-admin members can only see and revoke the API keys they created; admins manage every key in the workspace.
  • Key rotation -- API keys can be revoked at any time from Settings. Create new keys and revoke old ones to rotate credentials.