AutomationFlowsGeneral › Handle Clinic Appointments via Mcp Tools for Vapi and Retell Voice Agents

Handle Clinic Appointments via Mcp Tools for Vapi and Retell Voice Agents

ByMD Faizan Uzzaman @buildwithfaizan on n8n.io

This workflow exposes appointment management tools through an n8n MCP Server webhook so an external AI voice agent (for example, Vapi or Retell) can check availability, book appointments, suggest alternate slots, and cancel or reschedule existing bookings. Receives an MCP tool…

Event trigger★★★☆☆ complexityAI-powered9 nodesMcp TriggerTool Workflow
General Trigger: Event Nodes: 9 Complexity: ★★★☆☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16638 — we link there as the canonical source.

This workflow follows the Mcptrigger → Toolworkflow recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "LYdbya7WJhn4fHMV",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "VAPI Voice Receptionist MCP open-source-01",
  "tags": [
    {
      "id": "oufe6ROEtWIl02g4",
      "name": "open-source-01",
      "createdAt": "2026-06-25T18:55:08.441Z",
      "updatedAt": "2026-06-25T18:55:08.441Z"
    }
  ],
  "nodes": [
    {
      "id": "64ab9d66-f4fc-4fe1-a206-1fedf80efe5e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 528,
        "content": "## Appointment MCP tools\n\nA single MCP server trigger exposes appointment-management tool workflows for a voice receptionist, including checking availability, booking, finding alternate slots, canceling, and rescheduling appointments."
      },
      "typeVersion": 1
    },
    {
      "id": "878ba5df-5dca-43f7-8925-0ea91a5cd73f",
      "name": "MCP Voice Reception Trigger",
      "type": "@n8n/n8n-nodes-langchain.mcpTrigger",
      "position": [
        1064,
        272
      ],
      "parameters": {
        "path": "c2685cd7-a84e-4957-a670-75b88c2f7156"
      },
      "typeVersion": 2
    },
    {
      "id": "8b70e084-1430-45f3-a4e6-f57d90356d2e",
      "name": "Execute Slot Availability Check",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1392,
        496
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "AQhWv6s3ouxoTLPI",
          "cachedResultUrl": "/workflow/AQhWv6s3ouxoTLPI",
          "cachedResultName": "Check Slot Availability"
        },
        "description": "Call this workflow only after the patient's name, service, date, and time have been confirmed. It checks whether the requested appointment slot is available.",
        "workflowInputs": {
          "value": {
            "preferred_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_date', `Requested appointment date in YYYY-MM-DD format.`, 'string') }}",
            "preferred_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_time', `Requested appointment start time in HH:mm 24-hour format.`, 'string') }}"
          },
          "schema": [
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b3a236d5-05c5-4614-a66d-ea2092508c2c",
      "name": "Initiate Book Appointment Process",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        880,
        496
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "VgfmPnWBGh1obX6b",
          "cachedResultUrl": "/workflow/VgfmPnWBGh1obX6b",
          "cachedResultName": "Book Appointment"
        },
        "description": "Call this workflow only after the requested appointment slot has been confirmed as available. It creates a new appointment and returns the booking status.",
        "workflowInputs": {
          "value": {
            "name": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('name', `Patient's full name exactly as confirmed during the call.`, 'string') }}",
            "phone": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('phone', `Patient phone number in E.164 format.`, 'string') }}",
            "service_type": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('service_type', `Service to book. Use the exact clinic service name.`, 'string') }}",
            "preferred_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_date', `Appointment date to book in YYYY-MM-DD format.`, 'string') }}",
            "preferred_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_time', `Appointment start time to book in HH:mm 24-hour format.`, 'string') }}"
          },
          "schema": [
            {
              "id": "name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "service_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "service_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c43fc71f-1a93-4541-8a4c-3e5f9b89023d",
      "name": "Find Alternate Appointment Slot",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1136,
        496
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "21731VZVNsbyWyfV",
          "cachedResultUrl": "/workflow/21731VZVNsbyWyfV",
          "cachedResultName": "GET Alternate Slot"
        },
        "description": "Call this workflow only when the requested appointment slot is unavailable. Provide the requested date and time. The workflow will return alternative available appointment slots.",
        "workflowInputs": {
          "value": {
            "preferred_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_date', `Requested appointment date that is unavailable, in YYYY-MM-DD format.`, 'string') }}",
            "preferred_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_time', `Requested appointment start time that is unavailable, in HH:mm 24-hour format.`, 'string') }}"
          },
          "schema": [
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0249db3d-abb9-4877-9093-c1ca872231c6",
      "name": "Execute Appointment Cancellation",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1008,
        496
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "zyKX7olrdrOq1sem",
          "cachedResultUrl": "/workflow/zyKX7olrdrOq1sem",
          "cachedResultName": "Cancel Appointment"
        },
        "description": "Call this workflow ONLY to cancel an existing booked appointment. Do not use for new bookings or rescheduling.",
        "workflowInputs": {
          "value": {
            "phone": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('phone', `Caller phone number in E.164 format. Use to identify and verify the booking.`, 'string') }}",
            "preferred_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_date', `Date of the appointment to cancel in YYYY-MM-DD format.`, 'string') }}",
            "preferred_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_time', `Start time of the appointment to cancel in HH:mm 24-hour format.`, 'string') }}"
          },
          "schema": [
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2659826c-7262-4576-9a25-f24144e30ed0",
      "name": "Perform Appointment Rescheduling",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1264,
        496
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "fMCbwqe9G1TpUJva",
          "cachedResultUrl": "/workflow/fMCbwqe9G1TpUJva",
          "cachedResultName": "Reschedule Appointment"
        },
        "description": "Use this workflow ONLY to reschedule an existing appointment to a new date and/or time. Do not use for new bookings or cancellations.",
        "workflowInputs": {
          "value": {
            "phone": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('phone', `Caller\u2019s phone number in E.164 format. Use to identify and verify the existing booking.`, 'string') }}",
            "new_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('new_date', `New requested appointment date in YYYY-MM-DD format.`, 'string') }}",
            "new_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('new_time', `New requested appointment start time in HH:mm 24-hour format.`, 'string') }}",
            "preferred_date": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_date', `Existing booked appointment date in YYYY-MM-DD format.`, 'string') }}",
            "preferred_time": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('preferred_time', `Existing booked appointment start time in HH:mm 24-hour format.`, 'string') }}",
            "new_service_type": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('new_service_type', `Final service to be booked after rescheduling. Use the exact clinic service name. If no service change is requested, send the currently booked service.`, 'string') }}"
          },
          "schema": [
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "new_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "new_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "new_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "new_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "new_service_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "new_service_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4c753f75-13bb-4295-b803-a7470dbd34b0",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        112
      ],
      "parameters": {
        "color": 5,
        "width": 480,
        "height": 528,
        "content": "## VAPI Voice Receptionist MCP\n\n### How it works\n\nThis workflow acts as an MCP server endpoint for a VAPI voice receptionist. When the MCP server is called, it makes several appointment-related workflow tools available so the assistant can check slot availability, book, cancel, reschedule, or request alternate appointment slots.\n\n### Setup steps\n\n- Configure the MCP Server Trigger so it is reachable by the VAPI assistant or other MCP client.\n- Connect each tool workflow node to the correct underlying n8n workflow for booking, canceling, checking availability, finding alternate slots, and rescheduling appointments.\n- Ensure any credentials required by the called appointment workflows, such as calendar, CRM, or database credentials, are configured in n8n.\n- Update the VAPI assistant tool configuration to point to this MCP server and test each appointment action end to end.\n\n### Customization\n\nYou can add or remove tool workflow nodes to match the appointment actions your receptionist should support, or rename the tools to align with the prompts used by your VAPI assistant."
      },
      "typeVersion": 1
    },
    {
      "id": "771df42c-29b6-4d25-a44a-189d2945a2da",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        112
      ],
      "parameters": {
        "color": 4,
        "width": 528,
        "height": 528,
        "content": "## See it in action\n\nThis MCP server powers Aria, a live AI voice receptionist that \nbooks, reschedules, and cancels real appointments by phone. \nWatch the full call below.\n\n@[youtube](OF-5d0pQ7Zo)\n\nNote: the 5 tool nodes above each call a separate workflow for \nbooking, canceling, rescheduling, checking availability, and \nfinding alternate slots. Build each one to match your own \ncalendar/CRM setup \u2014 or watch the video to see the full \npattern working end to end."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "timezone": "America/Chicago",
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "74fde6d1-9b90-4fe1-bc53-2c87ab778a84",
  "connections": {
    "Execute Slot Availability Check": {
      "ai_tool": [
        [
          {
            "node": "MCP Voice Reception Trigger",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Find Alternate Appointment Slot": {
      "ai_tool": [
        [
          {
            "node": "MCP Voice Reception Trigger",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Execute Appointment Cancellation": {
      "ai_tool": [
        [
          {
            "node": "MCP Voice Reception Trigger",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Perform Appointment Rescheduling": {
      "ai_tool": [
        [
          {
            "node": "MCP Voice Reception Trigger",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Initiate Book Appointment Process": {
      "ai_tool": [
        [
          {
            "node": "MCP Voice Reception Trigger",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow exposes appointment management tools through an n8n MCP Server webhook so an external AI voice agent (for example, Vapi or Retell) can check availability, book appointments, suggest alternate slots, and cancel or reschedule existing bookings. Receives an MCP tool…

Source: https://n8n.io/workflows/16638/ — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

This n8n template implements an MCP (Model Context Protocol)-compliant module for managing Google Calendar events in a context-aware, conflict-free manner.

Mcp Trigger, Execute Workflow Trigger, Tool Workflow +2
General

Googledrivetool Extractfromfile. Uses stickyNote, executeWorkflowTrigger, mcpTrigger, googleDrive. Event-driven trigger; 17 nodes.

Execute Workflow Trigger, Mcp Trigger, Google Drive +3
General

Stickynote Executeworkflow. Uses executeWorkflowTrigger, stickyNote, mcpTrigger, toolCode. Event-driven trigger; 16 nodes.

Execute Workflow Trigger, Mcp Trigger, Tool Code +1
General

Executeworkflow Executecommandtool. Uses stickyNote, mcpTrigger, executeCommandTool, executeWorkflowTrigger. Event-driven trigger; 14 nodes.

Mcp Trigger, Execute Command Tool, Execute Workflow Trigger +2
General

Workflow 3630. Uses mcpTrigger, executeCommandTool, executeWorkflowTrigger, executeCommand. Event-driven trigger; 14 nodes.

Mcp Trigger, Execute Command Tool, Execute Workflow Trigger +2