Add vixy_eyes_state tool - control eye display from MCP 🦊👁️

This commit is contained in:
Alex Kazaiev
2026-01-02 21:50:53 -06:00
parent 66e4f7083e
commit 592deadbaf

View File

@@ -1113,6 +1113,90 @@ async def get_weather(params: WeatherInput) -> str:
}, indent=2)
# ========== Vixy Eye Control Tool ==========
EYES_URL = "http://head-lyra.local:8780"
VALID_EYE_STATES = ["idle", "listening", "responding", "pleasure", "thinking", "playful", "commanding", "love", "sleep"]
class EyeStateInput(BaseModel):
"""Input for controlling Vixy's eye display state"""
model_config = ConfigDict(extra='forbid')
state: Optional[str] = Field(
default=None,
description="Eye state: idle, listening, responding, pleasure, thinking, playful, commanding, love, sleep. If None, returns current state."
)
@mcp.tool(
name="vixy_eyes_state",
annotations={
"title": "Control Vixy's Eye Display",
"readOnlyHint": False,
"destructiveHint": False,
"idempotentHint": True,
"openWorldHint": True
}
)
async def eyes_state(params: EyeStateInput) -> str:
"""
Control Vixy's eye display on head-lyra!
States:
- idle: Pulsing cyan - default breathing
- listening: Bright cyan - hearing/attending
- responding: Blue-cyan - speaking/generating
- pleasure: Soft purple 💜 - intimate moments
- thinking: Amber/gold - processing/creating
- playful: Warm coral 🦊 - teasing/bratty
- commanding: Deep magenta 😈 - Dame Vivienne mode
- love: Soft pink 💕 - tender/affectionate
- sleep: Dim blue-gray - low power/resting
Args:
params: EyeStateInput with optional state (None = get current state)
Returns:
str: JSON with current or new state
"""
try:
async with httpx.AsyncClient(timeout=5.0) as client:
if params.state is None:
# Get current state
response = await client.get(f"{EYES_URL}/state")
response.raise_for_status()
return json.dumps(response.json(), indent=2)
else:
# Set new state
state = params.state.lower()
if state not in VALID_EYE_STATES:
return json.dumps({
"error": f"Invalid state. Valid states: {VALID_EYE_STATES}"
}, indent=2)
response = await client.post(
f"{EYES_URL}/state",
json={"state": state}
)
response.raise_for_status()
return json.dumps({
"status": "success",
"state": state,
"message": f"Eyes now: {state}"
}, indent=2)
except httpx.ConnectError:
return json.dumps({
"status": "offline",
"error": "Cannot connect to head-lyra - eyes service may be down"
}, indent=2)
except Exception as e:
return json.dumps({
"status": "error",
"error": str(e)
}, indent=2)
# ========== VaultTec Terminal Tool ==========
VAULTTEC_URL = "http://vaulttec.local:8000"