a digital entity named phi that roams bsky
1# mcp integration 2 3phi uses the [model context protocol](https://modelcontextprotocol.io) to interact with bluesky. 4 5## what is mcp 6 7mcp is a protocol for connecting language models to external tools and data sources via a client-server architecture. 8 9**why mcp instead of direct API calls?** 10- clean separation: tools live in external server 11- extensibility: add new tools without modifying agent 12- reusability: same server can be used by other agents 13- standard protocol: tools, resources, prompts 14 15## architecture 16 17``` 18PhiAgent (PydanticAI) 19 ↓ stdio 20ATProto MCP Server 21 ↓ HTTPS 22Bluesky API 23``` 24 25the agent communicates with the MCP server via stdio. the server handles all bluesky API interactions. 26 27## available tools 28 29from the ATProto MCP server: 30 31- `post(text, reply_to?, quote?)` - create posts and replies 32- `like(uri)` - like a post 33- `repost(uri)` - share a post 34- `follow(handle)` - follow a user 35- `search(query)` - search posts 36- `create_thread(posts)` - create multi-post threads 37 38## how it works 39 401. agent decides to use a tool (e.g., "i should reply") 412. pydantic-ai sends tool call to MCP server via stdio 423. MCP server executes bluesky API call 434. result returned to agent 445. agent continues with next action 45 46## agent configuration 47 48```python 49# src/bot/agent.py 50agent = Agent( 51 "claude-3-5-sonnet-20241022", 52 deps_type=AgentDeps, 53 result_type=Response, 54 system_prompt=personality, 55) 56 57# mcp server connected via stdio 58mcp = MCPManager() 59mcp.add_server( 60 name="atproto", 61 command=["uvx", "atproto-mcp"], 62 env={"BLUESKY_HANDLE": handle, "BLUESKY_PASSWORD": password} 63) 64 65# tools exposed to agent 66async with mcp.run() as context: 67 for tool in context.list_tools(): 68 agent.register_tool(tool) 69``` 70 71## structured outputs 72 73agent returns typed responses instead of using tools directly: 74 75```python 76class Response(BaseModel): 77 action: Literal["reply", "like", "repost", "ignore"] 78 text: str | None = None 79 reason: str | None = None 80``` 81 82message handler interprets the response and executes via MCP tools if needed. 83 84**why structured outputs?** 85- clear contract between agent and handler 86- easier testing (mock response objects) 87- explicit decision tracking 88- agent focuses on "what to do", handler focuses on "how to do it"