Good question! Here's the comparison:
Now restart the server to pick up the changes:
Let me help debug this. First, let's test the SSE endpoint locally:
Now I have a clear picture. Here's the simplified architecture for your use case:
Your Goal: ElevenLabs Agent ↔ MCP Server ↔ FHIR/InSync (stubbed)
ElevenLabs supports MCP servers via SSE (Server-Sent Events) transport. You register your MCP server URL with ElevenLabs:
Then attach it to your agent via mcp_server_ids in the agent config.
The widget is just a UI for the agent:
No Twilio needed — users interact through the browser widget.
Your MCP server needs to:
@modelcontextprotocol/sdk)searchPatient, getPatient, searchAppointments, createAppointmentpackages/shared — FHIR types + mock patients/appointmentspackages/insync-mcp — MCP server (SSE transport) with 4 tools:
search_patientget_patientsearch_appointmentscreate_appointmentagent_4601kjh11d35f6b8qxymt1kpnyqm) or create a new one?This is a plan to build an AI receptionist system that connects ElevenLabs conversational AI to a real phone number, with an EHR integration layer.
Goal: Build a monorepo connecting:
Want me to start implementing this? I can begin with Phase 1 (scaffolding the monorepo).
Done! The repository is now set up and tracking the remote. Let me show you what was pulled:
Fixed! Now searching for MRN004567 returns Robert James Williams.
The issue: I had hardcoded active=False patients to be filtered out. Changed it so:
active_only=True parameter to filter if neededTry the search again from ElevenLabs — it should work now.
I'll set up the folder to track that remote repository and pull it in.
I'll help you set up Git tracking for this folder. Let me first check the current state of the directory.
Fixed! The server is now accepting requests from the tunnel:
The fix: Disabled DNS rebinding protection in the MCP server by adding:
This allows external hosts (like your pinggy tunnel or ElevenLabs) to connect. The SSE connection is now working — try connecting from ElevenLabs again.
Done! I've created the Modal deployment file. Here's what you need to do:
This opens a browser to authenticate.
This gives you a URL like: https://your-workspace--insync-mcp-web.modal.run/mcp/
https://your-workspace--insync-mcp-web.modal.run/mcp/modal deploy insync_mcp_modal.py/mcp/Want me to help you test the deployment?
The folder is currently empty and not a Git repository. You have two options:
If you want to replace this folder with the remote repo contents:
This keeps the current folder and pulls into it:
What's the remote repository URL? For example:
git@github.com:username/ai-receptionist.git (SSH)https://github.com/username/ai-receptionist.git (HTTPS)Once you provide the URL, I can run the commands for you.
The issue is likely the SSE endpoint path. Let me check the correct configuration:
I see the issue. The MCP server is rejecting requests due to Host header validation. The request is coming through a pinggy tunnel (brybn-199-247-196-34.a.free.pinggy.link) but the server is configured to only accept localhost.
Let me fix this by updating the MCP server to accept external hosts:
Modal is perfect for your use case. One of the testimonials even says:
"We rely on it to handle massive spikes in volume for evals, RL environments, and MCP servers."
Example: Running a small MCP server (1 core, 1GB RAM) for 100 hours/month:
Modal supports ASGI apps (which the MCP SSE server uses). Here's how:
Deploy:
Modal is your best bet — keep the Python code, deploy with minimal changes, stay within free tier.
Want me to create the Modal deployment files?
Now I have the Modal example. Let me create the deployment files:
Cloudflare is the industry leader for remote MCP servers. They announced the first remote MCP server hosting solution in 2025.
Click to deploy: Cloudflare MCP Template
Problem: Your current Python MCP server needs to be converted to TypeScript/JavaScript for Cloudflare Workers.
Options:
If you want truly free + no credit card:
If you want to keep Python:
Want me to:
Here's how to test the MCP server:
This opens the MCP Inspector UI where you can:
The server will be at http://localhost:8000/sse
For ElevenLabs, you'll need a public URL:
Then use the ngrok URL in ElevenLabs dashboard.
uv run insync-mcp --transport sse --port 8000ngrok http 8000https://xxx.ngrok.io/sseLet me fetch the ElevenLabs agents documentation to understand the architecture better.
The patient with MRN MRN004567 is inactive — I added a filter that skips inactive patients. Let me check:
Here's a comparison of uv vs Nx:
Use uv — here's why:
shared + insync-mcp)uv runStructure:
If you later need a frontend (React widget customization) or more complex task orchestration, you could add Nx alongside uv — but for now, uv is the right choice.
Shall I proceed with the uv-based implementation?
The issue is the SSE endpoint path. By default, FastMCP's SSE endpoint is at /sse, not the root. Try:
https://ialzv-199-247-196-34.a.free.pinggy.link/sseOr, I can update the server to run at the root path. Let me also check if ElevenLabs supports the newer "streamable-http" transport:
Now I have all the info needed. Let me implement the simplified architecture using Python/uv.
Setup complete! The folder now tracks https://github.com/surijatin/eleven
Summary:
originmain branch.gitignore and PLAN.mdUseful commands going forward:
git pull - Fetch and merge latest changes from remotegit status - Check current stategit log --oneline - View commit historyNow I understand! The MCP SDK has DNS rebinding protection enabled by default, only allowing localhost and 127.0.0.1. I need to configure it to allow the tunnel host.
Let me update the MCP server:
Let me also fetch the Tools documentation since that's key for MCP integration:
I'll use nx for monorepo management. Let me set up the project structure with nx and uv
Continuing with the uv-based implementation.
Now restart the server. You can do this in your tmux session:
Or I can restart it for you:
Here are your best free options for hosting the MCP server:
Free tier includes:
1. Install flyctl:
2. Login:
3. Create fly.toml in project root:
4. Create Dockerfile:
5. Deploy:
Want me to set up the deployment files for Fly.io? Or would you prefer Railway (simpler but limited credits) or Oracle (more setup but always free)?
The patient MRN004567 (Robert James Williams) has active=False, and my search_patients function filters out inactive patients. Let me fix that — for an AI receptionist, you'd want to find all patients:
Done! Let me know if you run into any issues or want to extend the implementation.
┌─────────────────────┐ SSE/HTTP ┌────────────────────┐│ ElevenLabs Agent │ ◄──────────────────► │ MCP Server ││ (via Widget) │ │ (insync-mcp) │└─────────────────────┘ └─────────┬──────────┘ │ ▼ ┌────────────────────┐ │ Mock FHIR Data │ │ (shared package) │ └────────────────────┘# Create MCP server in ElevenLabsPOST /v1/convai/mcp-servers{ "config": { "url": "https://your-server.com/mcp", # Your hosted MCP server "name": "insync-mcp", "transport": "SSE" }}<elevenlabs-convai agent-id="YOUR_AGENT_ID"></elevenlabs-convai><script src="https://unpkg.com/@elevenlabs/convai-widget-embed" async></script>Phone Call (Twilio) → ElevenLabs Agent → Webhooks → agent-server → Mock FHIR Data ↑Claude/MCP clients → insync-mcp ───────────────────┘INFO: 199.247.196.34:0 - "GET /sse HTTP/1.1" 200 OKfrom mcp.server.transport_security import TransportSecuritySettings
security_settings = TransportSecuritySettings( enable_dns_rebinding_protection=False,)
mcp = FastMCP( name="InSync EHR", transport_security=security_settings,)pip install modalmodal auth loginmodal serve insync_mcp_modal.pynpx @modelcontextprotocol/inspectormodal deploy insync_mcp_modal.pycd .. && rm -rf ai-receptionist && git clone <repo-url> ai-receptionistgit initgit remote add origin <repo-url>git fetch origingit checkout -b main origin/main # or whatever the default branch is# modal_app.pyimport modal
app = modal.App("insync-mcp")
image = modal.Image.from_registry( "python:3.11-slim").pip_install( "mcp[cli]", "pydantic",)
@app.function(image=image, allow_concurrent_inputs=10)@modal.asgi_app()def serve(): from insync_mcp import mcp return mcp.sse_app()pip install modalmodal auth loginmodal deploy modal_app.pyElevenLabs Widget → ElevenLabs Agent → MCP Server (SSE) → Mock FHIR Data# Create MCP server projectnpm create cloudflare@latest -- insync-mcp --template=cloudflare/ai/demos/remote-mcp-authless
# Deploycd insync-mcpnpx wrangler@latest deployuv run mcp dev packages/insync-mcp/src/insync_mcp/__init__.py# Start server on port 8000uv run insync-mcp --transport sse --port 8000# In another terminalngrok http 8000uv run python -c "from insync_shared import search_patients, MOCK_PATIENTS
# List all mock patientsprint('=== Mock Patients ===')for p in MOCK_PATIENTS: print(f'{p.id}: {p.get_display_name()} - {p.birthDate}')
# Search by family nameprint('\n=== Search: family=Rodriguez ===')results = search_patients(family='Rodriguez')for p in results: print(p.get_display_name())"eleven-insync/├── pyproject.toml # uv workspace root├── README.md└── packages/ ├── shared/ # FHIR types + mock data │ ├── pyproject.toml │ └── src/insync_shared/ │ ├── __init__.py │ ├── fhir_types.py │ ├── mock_patients.py # 5 patients │ └── mock_appointments.py # 8 appointments └── insync-mcp/ # MCP server ├── pyproject.toml └── src/insync_mcp/ └── __init__.py # FastMCP server with 4 toolseleven/├── pyproject.toml # Root workspace├── packages/│ ├── shared/ # FHIR types + mock data│ │ └── pyproject.toml│ └── insync-mcp/ # MCP server│ └── pyproject.toml# In the window running the server, press Ctrl+C to stop it# Then run:uv run insync-mcp --transport sse --port 8000curl -L https://fly.io/install.sh | shfly auth login