feat(mcp): connect authenticated AquaPortal tools to Vocero (#1)
Vocero needs to query AquaPortal on behalf of the caller selected by the existing phone link. This adds server-owned conversations and MCP tool execution for voice and HTTP reasoning while leaving the speech pipeline unchanged. Release notes: - Added browser-bound conversations that keep backend credentials server-side and isolate callers. - Connected the eight-tool AquaPortal catalog through authenticated Streamable HTTP with full input schemas and structured results. - Added bounded multi-step tool execution with cancellation, expiry, and stale-result protection. - Updated browser bootstrap, tool progress, reasoning headers, and conversation cleanup. - Disabled legacy unscoped content preloads in MCP mode and documented configuration and deployment constraints. - Preserved disabled-mode contracts and added local SDK, WebSocket, and browser regression coverage. Reviewed-on: AquaPortal/s2s#1
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
"""Assemble the client API and retain its existing documentation URLs."""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from collections.abc import AsyncIterator
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import RedirectResponse
|
||||
@@ -8,8 +11,28 @@ from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from vocero_api.api.router import router
|
||||
from vocero_api.core import config, diagnostics # noqa: F401 - retain the startup banner
|
||||
from vocero_api.services.conversations import store
|
||||
|
||||
app = FastAPI(title="s2s-demo")
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
async def expire_conversations() -> None:
|
||||
while True:
|
||||
await asyncio.sleep(30)
|
||||
store.prune()
|
||||
|
||||
cleanup = asyncio.create_task(expire_conversations()) if config.S2S_MCP_URL else None
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if cleanup is not None:
|
||||
cleanup.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await cleanup
|
||||
store.clear()
|
||||
|
||||
|
||||
app = FastAPI(title="s2s-demo", lifespan=lifespan)
|
||||
app.include_router(router)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user