Labsco
scheduleonce logo

OnceHub

from scheduleonce

The OnceHub MCP Server provides a standardized way for AI models and agents to interact directly with your OnceHub scheduling API.

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedAccount requiredAdvanced setup

OnceHub MCP Server

The OnceHub MCP Server provides a standardized way for AI models and agents to interact directly with your OnceHub scheduling API. Rather than sending users a booking link and asking them to schedule manually, an AI Agent can retrieve availability and schedule meetings on the user’s behalf using MCP tools, through a natural language flow. This solution enables external AI Agents to access OnceHub scheduling APIs within AI-driven workflows using the standardized Model Context Protocol (MCP) remote server.

Compatible with: VS Code Copilot, OpenAI, and any MCP-compatible AI client.

Table of Contents

Features

  • πŸ”Œ MCP Protocol Support - Works with any MCP-compatible AI client
  • πŸ“… Time Slot Retrieval - Fetch available booking slots from OnceHub booking calendars
  • πŸ—“οΈ Meeting Scheduling - Automatically schedule meetings with guest information
  • πŸ” Secure Authentication - API key-based authentication via headers
  • πŸ§ͺ Well Tested - 92% code coverage with comprehensive unit tests
  • 🐳 Docker Ready - Containerized for easy deployment
  • πŸ“ AI-Friendly Prompts - Built-in workflow guidance for AI assistants

Architecture

Architecture

Project Structure

mcp-server/
β”œβ”€β”€ main.py              # MCP server with tool definitions
β”œβ”€β”€ models.py            # Pydantic data schemas for BookingForm and Location
β”œβ”€β”€ pyproject.toml       # Project dependencies and configuration
β”œβ”€β”€ Dockerfile           # Docker image configuration
β”œβ”€β”€ .dockerignore        # Files to exclude from Docker build
└── README.md            # This file

Tools

1. get_booking_time_slots

Retrieves available time slots from a booking calendar.

Parameters:

  • calendar_id (str, required): The booking calendar ID (e.g., 'BKC-XXXXXXXXXX')
  • start_time (str, optional): Filter slots from this datetime in ISO 8601 format (e.g., '2026-02-15T09:00:00Z')
  • end_time (str, optional): Filter slots until this datetime in ISO 8601 format (e.g., '2026-02-28T17:00:00Z')
  • timeout (int, default: 30): Request timeout in seconds

Example Response:

{
  "success": true,
  "status_code": 200,
  "calendar_id": "BKC-XXXXXXXXXX",
  "total_slots": 5,
  "data": [
    {"start_time": "2026-02-10T10:00:00Z", "end_time": "2026-02-10T11:00:00Z"},
    {"start_time": "2026-02-10T14:00:00Z", "end_time": "2026-02-10T15:00:00Z"}
  ]
}

2. schedule_meeting

Schedules a meeting in a specified time slot. Always call get_booking_time_slots first to ensure the time slot is available.

Parameters:

  • calendar_id (str, required): ID of the booking calendar (e.g., 'BKC-XXXXXXXXXX')
  • start_time (str, required): The exact start time from an available slot in ISO 8601 format
  • guest_time_zone (str, required): Guest's timezone in IANA format (e.g., 'America/New_York', 'Europe/London')
  • guest_name (str, required): Guest's full name
  • guest_email (str, required): Guest's email address for confirmation
  • guest_phone (str, optional): Guest's phone number in E.164 format (e.g., '+15551234567')
  • location_type (str, optional): Meeting mode - 'virtual', 'virtual_static', 'physical', or 'guest_phone'
  • location_value (str, optional): Location details based on type:
    • virtual: Provider name (e.g., 'zoom', 'google_meet', 'microsoft_teams')
    • virtual_static: Use null
    • physical: Address ID (e.g., 'ADD-XXXXXXXXXX')
    • guest_phone: Phone number in E.164 format
  • custom_fields (dict, optional): Custom form fields as key-value pairs (e.g., {"company": "Acme", "interests": ["Demo"]})
  • timeout (int, default: 30): Request timeout in seconds

Example Response:

{
  "success": true,
  "status_code": 200,
  "booking_id": "BKG-123456789",
  "confirmation": {
    "guest_name": "John Doe",
    "guest_email": "john@example.com",
    "scheduled_time": "2026-02-10T10:00:00Z",
    "timezone": "America/New_York"
  }
}

Environment Variables

Create a .env file or set these environment variables:

# Required: Your OnceHub API endpoint
ONCEHUB_API_URL=https://api.oncehub.com

# Note: API key is passed via Authorization header from MCP clients
# Do NOT commit API keys to version control

Data Schemas

Location

Represents meeting location details.

Fields:

  • type (str): Location type ("physical", "virtual", "phone")
  • value (str): Location details (address, URL, phone number)

Logging

The server includes comprehensive logging for HTTP requests to OnceHub:

  • Outgoing requests (β†’)
  • Response status codes (←)
  • Request/response bodies

Logs are output to the console with timestamps and log levels.

API Endpoints

  • GET /health - Health check endpoint
  • GET /healthy - Alternate health check endpoint
  • GET /sse - Server-Sent Events endpoint for MCP protocol communication
  • GET /tools - Returns the registered MCP tools with their descriptions, required parameters, and input field details

Development

Install dependencies manually

uv pip install fastmcp pydantic httpx

Install test dependencies

uv pip install -e ".[test]"

Run with different log levels

Edit main.py and change log_level parameter:

asyncio.run(mcp.run_sse_async(host="0.0.0.0", port=8000, log_level="debug"))

Available log levels: "debug", "info", "warning", "error", "critical"

Testing

The project includes comprehensive unit tests for all tools and functions.

Install Test Dependencies

# Install test dependencies
uv pip install pytest pytest-asyncio pytest-cov pytest-mock

Run Tests

Run all tests:

uv run pytest

Run tests with coverage report:

uv run pytest --cov=. --cov-report=html --cov-report=term

Run specific test file:

uv run pytest test_tools.py

Run specific test class:

uv run pytest test_tools.py::TestGetBookingTimeSlots

Run specific test:

uv run pytest test_tools.py::TestGetBookingTimeSlots::test_get_time_slots_success

Run with verbose output:

uv run pytest -v

Run and stop on first failure:

uv run pytest -x

Test Coverage

After running tests with coverage, open the HTML report:

# Windows
start htmlcov/index.html

# macOS
open htmlcov/index.html

# Linux
xdg-open htmlcov/index.html

Test Structure

  • test_tools.py - Unit tests for all tool functions
    • TestGetApiKeyFromContext - Tests for API key extraction
    • TestGetBookingTimeSlots - Tests for time slot retrieval
    • TestScheduleMeeting - Tests for meeting scheduling

All tests use mocking to avoid actual API calls and ensure fast, reliable test execution.

Support