MCP Server
Bob Studio 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-bobstudio.original.land/mcp
The server is stateless -- every request is self-contained and authenticated via API key. No sessions or persistent connections required.
| Method | Purpose |
|---|---|
POST /mcp | Send JSON-RPC messages (initialize or call tools) |
Authentication
Every request must include the x-api-key header with a valid API key. API keys are created in Settings > API Keys and are scoped to a workspace (and optionally to a single company).
| Header | Required | Description |
|---|---|---|
x-api-key | Always | Your API key (format: bsk_...). Determines workspace and company scope. |
How it works
The server is fully stateless. Each POST /mcp request:
- Validates the API key and extracts the workspace/company scope.
- Builds a fresh MCP server with all available tools.
- 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
| Tool | Description | Parameters |
|---|---|---|
list_projects | List all projects in the workspace | status? (in_progress, completed, invoiced) |
get_project | Get full project details by ID | projectId (UUID) |
create_project | Create a new project | name (string), plus optional: clientId, companyId, description, startDate, endDate, budget, estimatedHours, notes, currency |
update_project | Update project fields | projectId (UUID), plus optional: name, description, status, startDate, endDate, budget, estimatedHours, notes, taskPrefix |
update_project_status | Change project status | projectId (UUID), status (in_progress, completed, invoiced) |
Tasks
| Tool | Description | Parameters |
|---|---|---|
list_tasks | List top-level tasks (includes childTaskCount for each) | projectId? (UUID, filter by project) |
get_task | Get full task details including subtasks, comments, and assignees | taskId (UUID) |
create_task | Create a new top-level task | title (string), plus optional: description, status, priority, estimatedHours, dueDate, projectId, assigneeIds |
create_subtask | Create 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_subtasks | List all subtasks of a parent task | parentTaskId (UUID) |
update_task | Update 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_status | Change task status (works for both tasks and subtasks) | taskId (UUID), status (todo, in_progress, frozen, done) |
Clients
| Tool | Description | Parameters |
|---|---|---|
create_client | Create a new client | companyName (string), plus optional: firstName, lastName, email, phone, vatNumber, address, postalCode, city, country, companyId |
Offers
| Tool | Description | Parameters |
|---|---|---|
create_offer | Create a new offer/quote | Optional: subject, description, clientId, companyId, offerDate, validUntil, currency, notes |
Invoices
| Tool | Description | Parameters |
|---|---|---|
create_invoice | Create a new invoice | Optional: clientId, companyId, projectId, subject, description, invoiceDate, dueDate, currency, notes, paymentMethod |
Ideas
| Tool | Description | Parameters |
|---|---|---|
create_idea | Create a new idea/proposal | title (string), plus optional: description, estimatedBudget, currency, priority, notes, companyId, clientId |
Contacts
| Tool | Description | Parameters |
|---|---|---|
create_contact | Create a new business contact | Optional: companyName, contactName, email, phone, website, address, city, country, source, status, notes, nextFollowUp |
Recordings
| Tool | Description | Parameters |
|---|---|---|
list_recordings | List the most recent audio recordings for the current user | limit? (number, default 10, max 10) |
get_recording | Get one recording with summary, action items, notes, and transcription | recordingId (UUID) |
Time Logs
| Tool | Description | Parameters |
|---|---|---|
list_time_logs | List the current user's time logs | startDate? (YYYY-MM-DD), endDate? (YYYY-MM-DD) |
list_time_categories | List 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_log | Create 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_log | Update 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_log | Delete an existing time log | timeLogId (UUID) |
Appointments
| Tool | Description | Parameters |
|---|---|---|
list_calendars | List calendars available to the current user | None |
list_appointments | List the current user's appointments | startDate? (YYYY-MM-DD), endDate? (YYYY-MM-DD) |
create_appointment | Create a new appointment in the current workspace | date (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_appointment | Update an existing appointment | appointmentId (UUID), plus optional: title, clientName, clientEmail, date, startTime, endTime, isAllDay, location, address, onlinePlatform, onlineLink, notes, status, projectId |
Online Booking
| Tool | Description | Parameters |
|---|---|---|
get_booking_settings | Get the current user's online booking page configuration (slug, active status, weekly hours, slot duration, destination calendar, etc.) | None |
update_booking_settings | Create or update the online booking page configuration | All 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 |
The create_task, create_subtask, create_offer, create_idea, list_recordings, get_recording, list_time_logs, 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 and are only available when called internally by the AI Copilot. They are not available via external API keys.
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.
- 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.
- Key rotation -- API keys can be revoked at any time from Settings. Create new keys and revoke old ones to rotate credentials.