refactor: use MCPToolset instead of deprecated mcp_servers param

- Switch from Agent(mcp_servers=[...]) to Agent(tools=[MCPToolset(...)])
- Add WEB_MCP_ENABLED + FIRECRAWL_BASE to supervisord agent env
- Fixes deprecation warning in livekit-agents 1.7
This commit is contained in:
Shane
2026-08-22 12:40:07 -04:00
parent 045ddabac7
commit b55e6ed39a
2 changed files with 34 additions and 21 deletions
+24 -13
View File
@@ -70,48 +70,54 @@ SYSTEM_PROMPT = textwrap.dedent("""\
""") """)
# ── MCP servers (web access + any extra configured servers) ──────────────── # ── MCP toolsets (web access + any extra configured servers) ────────────────
def build_mcp_servers() -> list[mcp.MCPServer]: def build_mcp_toolsets() -> list[mcp.MCPToolset]:
"""Build the list of MCP servers to attach to the agent. """Build the list of MCP toolsets to attach to the agent.
Always includes the local web-access server (Firecrawl-backed search/scrape) Always includes the local web-access server (Firecrawl-backed search/scrape)
when WEB_MCP_ENABLED is true. Additional servers can be configured via the when WEB_MCP_ENABLED is true. Additional servers can be configured via the
EXTRA_MCP_SERVERS env var (JSON list of {url, transport} objects). EXTRA_MCP_SERVERS env var (JSON list of {url, transport} objects).
""" """
servers: list[mcp.MCPServer] = [] toolsets: list[mcp.MCPToolset] = []
if WEB_MCP_ENABLED: if WEB_MCP_ENABLED:
python_bin = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".venv", "bin", "python") python_bin = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".venv", "bin", "python")
web_mcp_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "web_mcp.py") web_mcp_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "web_mcp.py")
servers.append( toolsets.append(
mcp.MCPServerStdio( mcp.MCPToolset(
id="web-access",
mcp_server=mcp.MCPServerStdio(
command=python_bin, command=python_bin,
args=[web_mcp_script], args=[web_mcp_script],
env={**os.environ, "FIRECRAWL_BASE": FIRECRAWL_BASE}, env={**os.environ, "FIRECRAWL_BASE": FIRECRAWL_BASE},
client_session_timeout_seconds=120, client_session_timeout_seconds=120,
),
) )
) )
logger.info("Web-access MCP server enabled (Firecrawl at %s)", FIRECRAWL_BASE) logger.info("Web-access MCP toolset enabled (Firecrawl at %s)", FIRECRAWL_BASE)
extra = os.environ.get("EXTRA_MCP_SERVERS", "") extra = os.environ.get("EXTRA_MCP_SERVERS", "")
if extra: if extra:
try: try:
for entry in json.loads(extra): for i, entry in enumerate(json.loads(extra)):
url = entry.get("url", "") url = entry.get("url", "")
transport = entry.get("transport") # "sse" | "streamable_http" | None (auto) transport = entry.get("transport") # "sse" | "streamable_http" | None (auto)
servers.append( toolsets.append(
mcp.MCPServerHTTP( mcp.MCPToolset(
id=f"extra-{i}",
mcp_server=mcp.MCPServerHTTP(
url=url, url=url,
transport_type=transport, transport_type=transport,
client_session_timeout_seconds=120, client_session_timeout_seconds=120,
),
) )
) )
logger.info("Extra MCP server: %s (%s)", url, transport or "auto") logger.info("Extra MCP toolset: %s (%s)", url, transport or "auto")
except (json.JSONDecodeError, TypeError) as e: except (json.JSONDecodeError, TypeError) as e:
logger.error("Failed to parse EXTRA_MCP_SERVERS: %s", e) logger.error("Failed to parse EXTRA_MCP_SERVERS: %s", e)
return servers return toolsets
class VoiceAssistant(Agent): class VoiceAssistant(Agent):
@@ -125,7 +131,7 @@ class VoiceAssistant(Agent):
api_key=GEMMA_API_KEY, api_key=GEMMA_API_KEY,
), ),
instructions=SYSTEM_PROMPT, instructions=SYSTEM_PROMPT,
mcp_servers=build_mcp_servers(), tools=build_mcp_toolsets(),
) )
@@ -219,6 +225,11 @@ async def handle_job(ctx: JobContext) -> None:
agent=VoiceAssistant(), agent=VoiceAssistant(),
room=ctx.room, room=ctx.room,
room_options=room_io.RoomOptions( room_options=room_io.RoomOptions(
# Keep the agent in the room when a participant leaves; it must
# survive page reloads/reconnects, otherwise the next join lands
# in an agent-less room (LiveKit does not reliably re-dispatch
# into an existing room).
close_on_disconnect=False,
audio_input=room_io.AudioInputOptions( audio_input=room_io.AudioInputOptions(
# No noise cancellation plugin (self-hosted, no ai-coustics) # No noise cancellation plugin (self-hosted, no ai-coustics)
), ),
+3 -1
View File
@@ -27,7 +27,9 @@ environment=
AZURE_TTS_VOICE="%(ENV_AZURE_TTS_VOICE)s", AZURE_TTS_VOICE="%(ENV_AZURE_TTS_VOICE)s",
GEMMA_BASE_URL="%(ENV_GEMMA_BASE_URL)s", GEMMA_BASE_URL="%(ENV_GEMMA_BASE_URL)s",
GEMMA_MODEL="%(ENV_GEMMA_MODEL)s", GEMMA_MODEL="%(ENV_GEMMA_MODEL)s",
GEMMA_API_KEY="%(ENV_GEMMA_API_KEY)s" GEMMA_API_KEY="%(ENV_GEMMA_API_KEY)s",
WEB_MCP_ENABLED="%(ENV_WEB_MCP_ENABLED)s",
FIRECRAWL_BASE="%(ENV_FIRECRAWL_BASE)s"
[program:web] [program:web]
command=/usr/sbin/nginx -g "daemon off;" command=/usr/sbin/nginx -g "daemon off;"