#!/usr/bin/env -S uv run --script --quiet # /// script # requires-python = ">=3.12" # dependencies = ["marvin@git+https://github.com/prefecthq/marvin.git"] # /// """ Make some change to my phillips hue network of lights via agent + MCP server. Usage: ```bash ./update-lights -m "turn on sahara in the living room and nightlight in the kitchen" ``` Details: - uses a [`marvin`](https://github.com/prefecthq/marvin) (built on [`pydantic-ai`](https://github.com/pydantic/pydantic-ai)) agent - the agent spins up a [`fastmcp`](https://github.com/jlowin/fastmcp) MCP server that talks to my [`phue`](https://github.com/studioimaginaire/phue) bridge - set `HUE_BRIDGE_IP` and `HUE_BRIDGE_USERNAME` in `.env` or otherwise in environment - uses `OPENAI_API_KEY` by default, but you can set `AI_MODEL` in `.env` or otherwise in environment to use a different model """ import marvin import argparse from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import Field from pydantic_ai.mcp import MCPServerStdio from pydantic_ai.models import KnownModelName from rich.console import Console from rich.panel import Panel from rich.prompt import Prompt class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", extra="ignore") hue_bridge_ip: str = Field(default=...) hue_bridge_username: str = Field(default=...) anthropic_api_key: str | None = Field(default=None) ai_model: KnownModelName = Field(default="anthropic:claude-opus-4-5") settings = Settings() console = Console() hub_mcp = MCPServerStdio( command="uvx", args=[ "smart-home@git+https://github.com/jlowin/fastmcp.git#subdirectory=examples/smart_home" ], env={ "HUE_BRIDGE_IP": settings.hue_bridge_ip, "HUE_BRIDGE_USERNAME": settings.hue_bridge_username, }, ) if __name__ == "__main__": import os if settings.anthropic_api_key: os.environ["ANTHROPIC_API_KEY"] = settings.anthropic_api_key parser = argparse.ArgumentParser(description="Send a command to the Marvin agent.") parser.add_argument( "--message", "-m", type=str, default="soft and dim - Jessica Pratt energy, all areas", help="The message to send to the agent (defaults to 'soft and dim - Jessica Pratt energy, all areas').", ) parser.add_argument( "--once", action="store_true", help="Run once and exit instead of entering interactive mode.", ) args = parser.parse_args() agent = marvin.Agent( model=settings.ai_model, mcp_servers=[hub_mcp], ) console.print( Panel.fit( f"[bold cyan]🏠 lights agent[/bold cyan]\n" f"[dim]model: {settings.ai_model}[/dim]", border_style="blue", ) ) with marvin.Thread(): console.print(f"\n[bold yellow]→[/bold yellow] {args.message}") agent.run(str(args.message)) if not args.once: while True: try: user_input = Prompt.ask( "\n[bold green]enter a message[/bold green]" ) console.print(f"[bold yellow]→[/bold yellow] {user_input}") agent.run(str(user_input)) except KeyboardInterrupt: console.print("\n[dim red]exiting...[/dim red]") break