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:
@@ -0,0 +1,46 @@
|
||||
"""Contracts owned by the optional authenticated MCP integration."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr
|
||||
|
||||
|
||||
class ConversationRequest(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
phoneNumber: str = Field(min_length=8, max_length=40)
|
||||
|
||||
|
||||
class CallerIdentity(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str
|
||||
|
||||
|
||||
class BackendLogin(BaseModel):
|
||||
sessionToken: SecretStr = Field(min_length=1)
|
||||
user: CallerIdentity
|
||||
|
||||
|
||||
class ConversationResponse(BaseModel):
|
||||
conversationId: str
|
||||
expiresIn: int
|
||||
profile: CallerIdentity
|
||||
|
||||
|
||||
class McpToolDefinition(BaseModel):
|
||||
name: str
|
||||
description: str = ""
|
||||
parameters: dict[str, Any]
|
||||
requires_auth: bool = True
|
||||
|
||||
|
||||
class McpCatalogResponse(BaseModel):
|
||||
tools: list[McpToolDefinition]
|
||||
|
||||
|
||||
class IntegrationError(Exception):
|
||||
"""Safe public errors, never containing upstream credentials or bodies."""
|
||||
|
||||
def __init__(self, status: int, message: str) -> None:
|
||||
super().__init__(message)
|
||||
self.status = status
|
||||
self.message = message
|
||||
@@ -16,6 +16,7 @@ class OpenResponse(BaseModel):
|
||||
|
||||
|
||||
class ConfigResponse(OpenResponse):
|
||||
mcp: bool = False
|
||||
search: bool
|
||||
lb: bool
|
||||
allowDirect: bool
|
||||
|
||||
Reference in New Issue
Block a user