full-ai-customer-service-handling
Provides SMS integration for sending technician notifications and receiving their replies via signed webhooks, enabling the async technician confirmation workflow.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@full-ai-customer-service-handlingCreate a service request for a water heater leak, find a technician for tomorrow after 4 PM."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Full AI Customer Service Handling
An AI receptionist for service businesses that actually books the job. Website chat → safety check → live technician calendars → SMS to the technician → customer confirms → appointment lands in Outlook. Fully asynchronous, fully audited, zero customer sign-in.
Why this exists
Every plumber, electrician and HVAC company loses jobs the same way: the phone rings while the technician is under a sink, the website form goes to an inbox nobody checks, and the customer books the next company that answers. This project turns a website chat widget into a 24/7 receptionist that dispatches real technicians — reading their real calendars, texting them, and confirming with the customer — while the business owner does nothing but keep their Outlook calendar up to date.
Built for Nexroza Plumbing (Toronto); designed so any field-service business can fork it.
Related MCP server: Microsoft MCP
What a customer sees (real transcript from the end-to-end test)
Customer: My gas water heater is leaking in Scarborough. I need someone today after 4 PM. Assistant: Thanks — a few safety questions first. 1) Do you smell gas or hear hissing near the water heater? If yes, leave the building, don't operate switches, call your gas utility emergency line or 911 from outside… 2) Any active flooding or water near electrical outlets? … Customer: No gas smell, no flooding — just dripping from the bottom of the tank. Tomorrow after 4 PM works. Customer: My name is Sam Tester, phone 416‑555‑0177, 25 Test Road, Scarborough, M1B 2K3. Yes, text me updates. Assistant: Request submitted. A technician (Michael) is being contacted by SMS to confirm an appointment on 2026‑09‑14 between 4:00 PM and 8:00 PM. Tracking reference: NX‑QWL6A99EPNOR. Confirmation will follow once he replies.
(Michael texts back "I can do 5:30 PM". Later…)
Customer: Any update on NX‑QWL6A99EPNOR? My phone ends in 0000. Assistant: Sorry — I couldn't find a request with that reference + phone. Customer: Sorry, my number is 416‑555‑0177. Assistant: Michael proposed Monday September 14 at 5:30 PM. Do you confirm? Customer: Yes, 5:30 works. Assistant: Done — your booking is confirmed. Technician: Michael · Monday September 14 at 5:30 PM.
Behind that last line an Outlook event was created in Michael's calendar and the request moved to confirmed — and only then did the assistant say "confirmed".
How it works
flowchart LR
W[🌐 Website chat widget<br/>no login] -->|HTTPS| B[Website backend<br/>session · rate limit]
B -->|Entra identity| A[🤖 Foundry Agent<br/>gpt‑5‑mini · safety check · intake]
A -->|MCP + system key| F[⚡ Azure Functions MCP server<br/>8 tools]
F --> T[(Table Storage<br/>requests · audit · idempotency)]
F -->|calendarView / create event| O[📅 Outlook calendars<br/>owner token, silent refresh]
F -->|queue sms‑outbound| S[📱 SMS provider<br/>Twilio · ACS · mock]
S -->|signed webhook| F
F -->|queue sms‑inbound| T
E[⏱ expiry timer<br/>timeout → next technician] --> TsequenceDiagram
autonumber
participant C as Customer
participant AG as Foundry Agent
participant MCP as MCP server
participant Q as Queues
participant TECH as Technician (SMS)
participant CAL as Outlook
C->>AG: "Water heater leaking, after 4 PM"
AG->>C: Safety check, collect name / phone / address
AG->>MCP: create_service_request → NX‑ref
AG->>MCP: find_matching_technicians (skill · area · schedule · live calendar)
AG->>MCP: send_technician_request (returns immediately)
MCP->>Q: sms‑outbound
Q->>TECH: "Nexroza job ABCD: Water heaters in M1B, Mon 4–8 PM. Reply YES / a time / NO"
AG->>C: "Submitted — reference NX‑…, confirmation follows"
TECH-->>MCP: "I can do 5:30 PM" (signed webhook → sms‑inbound)
C->>AG: "Status of NX‑…? phone ends 0177"
AG->>MCP: get_service_request_status → proposed 5:30 PM
C->>AG: "Yes"
AG->>MCP: confirm_booking (ETag lock → re‑check calendar → create event)
MCP->>CAL: event created
AG->>C: "Confirmed: Michael, Mon 5:30 PM"stateDiagram-v2
[*] --> new
new --> matching
matching --> awaiting_technician: SMS queued
awaiting_technician --> technician_proposed_time: reply "YES" / "5:30 PM"
awaiting_technician --> technician_declined: reply "NO"
awaiting_technician --> expired: no reply in 30 min
technician_declined --> awaiting_technician: next technician
expired --> awaiting_technician: next technician
expired --> failed: nobody left
technician_proposed_time --> awaiting_customer_confirmation: shown to customer
awaiting_customer_confirmation --> confirmed: customer accepts → Outlook event
awaiting_customer_confirmation --> awaiting_technician: customer declines → ask again
confirmed --> [*]The MCP tools
Tool | What it does |
| weekly schedule ∧ live Outlook status per technician for a date/window |
|
|
| validates input, returns a high‑entropy tracking reference ( |
| skill · active · service area (postal FSA) · schedule · calendar · pending load · on‑call fallback |
| queues the SMS and returns at once — the agent never waits |
| reference + callback phone → customer‑safe status and any proposed time |
| ETag‑locked, calendar re‑checked, Outlook event created, then — and only then — |
| technicians, skills, calendar presence |
What makes it production‑grade
Asynchronous by design — no HTTP request or agent run ever waits for a human. Storage queues, signed webhooks, 5‑minute expiry sweeps, automatic fallback to the next technician, poison‑queue handling.
Never invents availability — the agent must call a tool before any availability claim; a tool failure is reported honestly ("live availability couldn't be checked"), never guessed.
Says "confirmed" only after Outlook says so — the booking is created with an ETag lock (4 concurrent confirmations → exactly one event) and re‑checks the calendar first.
Security first — MCP endpoint behind a system key held in a Foundry connection (never in the browser), customers never sign in to Microsoft, tracking references are ~72‑bit random and stored hashed, second factor = callback phone, internal IDs never leave the server, provider webhooks validated (
X‑Twilio‑Signature/ HMAC), phone numbers and message IDs redacted in logs, no PII in alerts or SMS bodies, prompt‑injection hardened (plus Azure prompt shields).Owner authorizes once — a PKCE public‑client flow (no client secret) stores a refresh token in a private blob; the server refreshes it silently. A 30‑minute heartbeat and Azure Monitor alerts tell you before the customer does.
Observable — status history per request, Application Insights markers (
SERVICE_REQUEST_FAILED,SMS_DELIVERY_FAILURE,POISON_MESSAGE,BOOKING_FAILED, …), 4 alert rules for ≈ US$2/month.Cheap to run — Flex Consumption Functions + Table Storage + queues ≈ a few dollars a month; the model is pay‑per‑token.
Quick start
git clone https://github.com/Ray-Khosravi/full-ai-customer-service-handling
cd full-ai-customer-service-handling
cp deploy.env.example deploy.env # your resource names (git-ignored)
# 1) infrastructure + function app (Azure Developer CLI)
cd src/FunctionsMcpTool && azd up
# 2) one-time Outlook authorization by the business owner (opens a private browser window)
python ../../tools/authorize_outlook.py
# 3) Foundry: store the MCP key in a project connection and publish the agent
python ../../foundry/create_connection.py
az rest --method post --resource https://ai.azure.com \
--url "https://<foundry-account>.services.ai.azure.com/api/projects/<project>/agents/Plumbing-Service-Coordinator/versions?api-version=2025-11-15-preview" \
--headers Content-Type=application/json --body @../../foundry/agent-version.json
# 4) talk to it
python ../../web/test_client/server.py # http://localhost:8787Full runbook — calendar naming rules, database schema, SMS providers (Twilio / Azure Communication Services / mock), monitoring, troubleshooting, costs: docs/OPERATIONS.md. Website integration contract: web/INTEGRATION.md.
Testing
Layer | Command | Covers |
Unit (43) |
| validation, state machine, matching, OFF/SICK/VACATION exclusion, ON_CALL fallback, Toronto DST, duplicate webhooks, decline / timeout / fallback, confirmation, Graph failure, concurrency, secure lookup, injection, provider signatures |
Deployed workflow |
| MCP → queues → signed webhook → status → Outlook event |
Full conversation |
| the transcript above, through the real agent |
Live SMS (hybrid) |
| one real Twilio SMS + real delivery callback; simulated carrier step; 403 on bad signature; idempotent duplicates |
Repository layout
src/FunctionsMcpTool/ Azure Functions app — function_app.py (triggers) + nexroza/ (workflow, store, graph, sms, matching, replies)
foundry/ agent instructions & version, connection script, operator scripts, end-to-end tests
tools/ one-time Outlook owner authorization
web/ website integration contract + standalone chat widget/test backend
infra/ Bicep for azd (Function App, storage, identity, monitoring & alerts)
docs/ operations runbook, hero animationRoadmap
Customer‑side SMS OTP as the second factor (after a real SMS number is live)
Customer self‑service cancel / reschedule tool
Key Vault references for provider secrets
RAG over pricing, warranty and FAQ policies
Multi‑tenant onboarding (one deployment, many businesses)
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted MCP server for Cliniko — patients, appointments, availability, and invoices for AI agents.
- AstrocalOAuthdev.astrocal
AI-native scheduling: check availability, book meetings, cancel and reschedule via MCP
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA simple MCP server that enables meeting room booking through an AI assistant, supporting room availability checks and booking operations with React Agent pattern for tool calling.2-
- FlicenseCqualityDmaintenanceA powerful MCP server that enables AI assistants to interact with Microsoft Graph API for managing Outlook emails, Calendar events, OneDrive files, and Contacts through natural language commands.3556-
- FlicenseBqualityBmaintenanceMCP server providing AI assistants with full access to Microsoft Outlook email and calendar via the Microsoft Graph API, featuring 26 tools for mail, calendar, contacts, and scheduling with delegated authentication.29-
- FlicenseNot gradedqualityBmaintenanceOutlook Calendar MCP Server built using FastMCP and Microsoft Graph API. This MCP server allows AI agents to manage Outlook Calendar events through Microsoft Graph.-