{"openapi":"3.1.0","info":{"title":"Michael C. Hurley site API","version":"1.0.0","description":"Read-only site data plus booking for https://www.michaelchurley.com. Agent guide: https://www.michaelchurley.com/agents.md. The same operations are exposed as MCP tools at https://www.michaelchurley.com/mcp.","contact":{"name":"Michael C. Hurley","email":"michaelmonetized@gmail.com","url":"https://www.michaelchurley.com"}},"servers":[{"url":"https://www.michaelchurley.com"}],"paths":{"/resume.json":{"get":{"operationId":"getResume","summary":"Resume in JSON Resume v1.0.0 format","responses":{"200":{"description":"JSON Resume","content":{"application/json":{"schema":{"$ref":"https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json"}}}}}}},"/portfolio.json":{"get":{"operationId":"listPortfolio","summary":"Portfolio pieces","responses":{"200":{"description":"Portfolio","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Portfolio"}}}}}}},"/blog.json":{"get":{"operationId":"listBlogPosts","summary":"Published blog posts, newest first","responses":{"200":{"description":"Blog index","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogIndex"}}}}}}},"/feed.json":{"get":{"operationId":"blogJsonFeed","summary":"Blog as JSON Feed 1.1","responses":{"200":{"description":"JSON Feed","content":{"application/feed+json":{"schema":{"type":"object"}}}}}}},"/feed.xml":{"get":{"operationId":"blogRss","summary":"Blog as RSS 2.0","responses":{"200":{"description":"RSS feed","content":{"application/rss+xml":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"Resume in llms.txt format","responses":{"200":{"description":"llms.txt","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"operationId":"getLlmsFullTxt","summary":"Whole site as Markdown","responses":{"200":{"description":"Full site Markdown","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/agents.md":{"get":{"operationId":"getAgentGuide","summary":"Usage guide for AI agents","responses":{"200":{"description":"Agent guide","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/{path}.md":{"get":{"operationId":"getPageMarkdown","summary":"Markdown version of any page (use index.md for the home page)","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"},"example":"blog"}],"responses":{"200":{"description":"Page as Markdown","content":{"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"No such page","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/api/booking":{"post":{"operationId":"sendBookingConfirmation","summary":"Send booking confirmation emails (second step of the /book widget, after the booking is stored)","description":"Rate limited to 5 requests per hour per IP. Agents should prefer the book_meeting MCP or WebMCP tool, which stores the booking and sends the emails in one call.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingRequest"}}}},"responses":{"200":{"description":"Emails sent","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"Missing required fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Email service not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mcp":{"post":{"operationId":"mcp","summary":"Remote MCP server (Streamable HTTP, JSON-RPC 2.0)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"JSON-RPC response","content":{"application/json":{"schema":{"type":"object"}}}},"202":{"description":"Notification accepted"}}}}},"components":{"schemas":{"Portfolio":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"markdown":{"type":"string","format":"uri"},"items":{"type":"array","items":{"type":"object","required":["id","title","category","media"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string","enum":["sites","interfaces","marks"]},"media":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"}}}}}},"BlogIndex":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"markdown":{"type":"string","format":"uri"},"count":{"type":"integer"},"posts":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"markdown":{"type":"string","format":"uri"},"date":{"type":["string","null"],"format":"date"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"BookingRequest":{"type":"object","required":["name","email","date","timeSlot"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"message":{"type":"string"},"date":{"type":"string","format":"date","description":"YYYY-MM-DD, Eastern Time"},"timeSlot":{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"HH:MM, Eastern Time, 07:30-20:30 on the half hour"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}}}}}