{"openapi":"3.0.3","info":{"title":"AI Tinkerers Agents API","version":"1.4.0","description":"Generated OpenAPI contract for the AI Tinkerers Agents REST API. Request schemas are derived from the MCP tool registry when available; REST-only routes use conservative JSON object schemas."},"servers":[{"url":"https://aitinkerers.org","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"tags":[{"name":"Ai Assisted Draft Runs"},{"name":"Analytics"},{"name":"Attendance"},{"name":"Auth"},{"name":"Availability"},{"name":"Calendar Availability"},{"name":"Clients"},{"name":"Companies"},{"name":"Content"},{"name":"Content Pages"},{"name":"Docs"},{"name":"Dossier"},{"name":"Email Send Jobs"},{"name":"Event Promos"},{"name":"Fund Content"},{"name":"Gallery"},{"name":"Global Hackathons"},{"name":"Gmail"},{"name":"Guest Radar"},{"name":"Hackathon Teams"},{"name":"Hackathons"},{"name":"Jobs"},{"name":"Logos"},{"name":"Mail Logs"},{"name":"Media"},{"name":"Meetups"},{"name":"Message Boards"},{"name":"Newsletters"},{"name":"People"},{"name":"Photos"},{"name":"Promo Banners"},{"name":"RAG Chunks"},{"name":"RSVPs"},{"name":"Recommendations"},{"name":"Restricted Content"},{"name":"Social Posts"},{"name":"Speaker Promo Banners"},{"name":"Sponsors"},{"name":"Subscribers"},{"name":"Technologies"},{"name":"Tiers"},{"name":"Vip Event Emails"},{"name":"Weblogs"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"paths":{"/api/agents/v1/ai_assisted_draft_runs":{"get":{"operationId":"ai_assisted_draft_run_list","summary":"Ai assisted draft run list","description":"List visible AI Page Creator runs for the caller. City managers can inspect their own runs and runs for visible city chapters; index owners can inspect all runs. Supports city, weblog, state, stage, requester, and recency filters.","tags":["Ai Assisted Draft Runs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"ai_assisted_draft_run_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"ai_assisted_draft_run_list","parameters":[{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city name filter, for example Montreal."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city weblog token filter."},{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["pending","queued","running","succeeded","failed","cancelled","lost"]},"description":"Optional run state filter."},{"name":"stage","in":"query","required":false,"schema":{"type":"string"},"description":"Optional current stage filter."},{"name":"client_email","in":"query","required":false,"schema":{"type":"string"},"description":"Optional requester email filter. Only useful for callers with broad visibility."},{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"Optional recency filter such as 24h, 7d, or an ISO timestamp."},{"name":"mine","in":"query","required":false,"schema":{"type":"boolean"},"description":"When true, only return runs requested by the current API key owner."},{"name":"include_content_summary","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include a short generated-page summary when a run has produced a page. Defaults true."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."}]}},"/api/agents/v1/ai_assisted_draft_runs/recent_pages":{"get":{"operationId":"ai_assisted_draft_recent_pages","summary":"Ai assisted draft recent pages","description":"List recently generated pages from visible successful AI Page Creator runs, including page title, URL, summary, and originating run token.","tags":["Ai Assisted Draft Runs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"ai_assisted_draft_recent_pages","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"ai_assisted_draft_recent_pages","parameters":[{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city name filter, for example Montreal."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city weblog token filter."},{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"Optional recency filter such as 24h, 7d, or an ISO timestamp."},{"name":"include_content_summary","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include generated-page summaries. Defaults true."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."}]}},"/api/agents/v1/ai_assisted_draft_runs/{token}":{"get":{"operationId":"ai_assisted_draft_run_get","summary":"Ai assisted draft run get","description":"Get one visible AI Page Creator run by run token, including organizer-safe status, retry guidance, and generated page summary when available.","tags":["Ai Assisted Draft Runs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"ai_assisted_draft_run_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"ai_assisted_draft_run_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"include_content_summary","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include a short generated-page summary when available. Defaults true."}]}},"/api/agents/v1/ai_assisted_draft_runs/{token}/retry":{"post":{"operationId":"ai_assisted_draft_run_retry","summary":"Ai assisted draft run retry","description":"Retry a failed or lost AI Page Creator run visible to the caller. Allowed for the requester, city owner, index owner, or admin.","tags":["Ai Assisted Draft Runs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"ai_assisted_draft_run_retry","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"ai_assisted_draft_run_retry","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"AI Page Creator run token."}},"required":["token"]}}}}}},"/api/agents/v1/analytics/email/campaign_performance":{"get":{"operationId":"email_campaign_performance_get","summary":"Email campaign performance get","description":"Get email campaign performance analytics. Supports dashboard-style trend/summary payloads and paginated campaign leaderboard queries with filters, sorting, and scope selectors.","tags":["Analytics"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_campaign_performance_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_campaign_performance_get","parameters":[{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific weblog."},{"name":"weblog_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Scope to multiple weblogs."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific content page."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific meetup."},{"name":"series_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific track within a weblog."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max campaign rows to return (default 50, max 100)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Campaign row offset for pagination (default 0, max 10000)."},{"name":"group_by","in":"query","required":false,"schema":{"type":"string","enum":["campaign","day","week"],"default":"campaign"},"description":"Aggregation level."},{"name":"campaign_type","in":"query","required":false,"schema":{"type":"string","enum":["all","meetup","content_page","newsletter"],"default":"all"},"description":"Filter by campaign type."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["sent_at","campaign_label","sends","delivered","opens","clicks","bounces","unsubscribes","delivery_rate_pct","open_rate_pct","click_rate_pct","click_to_open_rate_pct","bounce_rate_pct","unsubscribe_rate_pct"],"default":"sent_at"},"description":"Campaign row sort field."},{"name":"sort_dir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Campaign row sort direction."},{"name":"min_sends","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Only return campaign rows with at least this many sends."},{"name":"include_campaigns","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include paginated campaign rows."},{"name":"include_trends","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include trend buckets for dashboard/chart use."},{"name":"include_summary","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include summary totals and weighted rates."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Max 730 days range."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/analytics/email/deliverability_health":{"get":{"operationId":"email_deliverability_health_get","summary":"Email deliverability health get","description":"Get email deliverability health metrics including bounce rates, complaint rates, and delivery success rates.","tags":["Analytics"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_deliverability_health_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_deliverability_health_get","parameters":[{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/analytics/email/fatigue_risk":{"get":{"operationId":"email_fatigue_risk_get","summary":"Email fatigue risk get","description":"Get email fatigue risk analysis showing subscribers at risk of disengagement due to email frequency.","tags":["Analytics"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_fatigue_risk_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_fatigue_risk_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max results."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/analytics/email/link_clicks":{"get":{"operationId":"email_link_clicks_get","summary":"Email link clicks get","description":"Get tracked email link click breakdowns for an authorized campaign scope. Groups clicks by destination URL and link position, includes inferred anchor text when available, and reports untracked section-anchor links found in representative email bodies.","tags":["Analytics"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_link_clicks_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_link_clicks_get","parameters":[{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific weblog."},{"name":"weblog_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Scope to multiple weblogs."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific content page."},{"name":"content_page_url","in":"query","required":false,"schema":{"type":"string"},"description":"Resolve and scope to a content page by public URL, such as https://city.example/p/my-event."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific meetup."},{"name":"series_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope to a specific track within a weblog."},{"name":"campaign_key","in":"query","required":false,"schema":{"type":"string"},"description":"Optional campaign key returned by campaign_performance, such as send_job:6628."},{"name":"campaign_type","in":"query","required":false,"schema":{"type":"string","enum":["all","meetup","content_page","newsletter"]},"description":"Optional campaign type filter: all, meetup, content_page, or newsletter."},{"name":"destination_url","in":"query","required":false,"schema":{"type":"string"},"description":"Optional clicked destination URL filter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max link rows to return (default 25, max 100)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Uses the mail sent date window."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Uses the mail sent date window."}]}},"/api/agents/v1/analytics/network":{"get":{"operationId":"community_analytics_query","summary":"Community analytics query","description":"Run a predefined, aggregate network analysis across AI Tinkerers chapters. Uses safe query templates only; arbitrary SQL and contact details are not available.","tags":["Analytics"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"community_analytics_query","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"community_analytics_query","parameters":[{"name":"query_type","in":"query","required":false,"schema":{"type":"string","enum":["multi_city_presenters","most_active_presenters","demos_per_city","sponsor_and_presenter_overlap","technology_trends","chapter_growth"]},"description":"Stable analysis template to run."},{"name":"question","in":"query","required":false,"schema":{"type":"string"},"description":"Natural-language alternative used to choose one of the predefined templates."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"minimum":1,"maximum":50}}]}},"/api/agents/v1/attendance_history":{"get":{"operationId":"attendance_history_get","summary":"Attendance history get","description":"Get attendance history for a person across AI Tinkerers events. Shows which meetups they attended and when.","tags":["Attendance"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"attendance_history_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"attendance_history_get","parameters":[{"name":"client_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Client token, email, or name."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 100)."},{"name":"ai_tinkerers_network_only","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only include AI Tinkerers network events (default false)."}]}},"/api/agents/v1/auth/validate":{"get":{"operationId":"auth_validate","summary":"Auth validate","description":"Validate the current Agent API key and return the authenticated owner plus derived roles and enabled API groups.","tags":["Auth"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"auth_validate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"auth_validate"}},"/api/agents/v1/availability/calendar/create_event":{"post":{"operationId":"availability_calendar_create_event","summary":"Availability calendar create event","description":"Create an event on a person's Google Calendar (requires the person to have connected Google Calendar with write access at /profile/calendar-availability). Timed meetings with invitees include Google Meet, including phone calls and meetings with physical-location logistics. Solo blocks with no invitees, such as travel or focus time, do not include conferencing. IMPORTANT: After calling this tool you MUST call ait_availability_verify_booking to confirm the calendar is actually blocked before telling anyone the event or meeting is scheduled. Never claim a meeting was booked without the verify_booking confirmation. Ashley must not use this tool for a panel, podcast, interview, keynote, talk, webinar, or guest appearance without a verified principal-authored explicit yes to participate.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_calendar_create_event","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_calendar_create_event","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"people":{"type":"array","items":{"type":"string"},"description":"Whose calendar to write to (e.g. [\"jake\"] or [\"joe\"]). Required."},"emails":{"type":"array","items":{"type":"string"},"description":"Email-based filter. Alternative to people."},"summary":{"type":"string","description":"Event title."},"starts_at":{"type":"string","description":"ISO 8601 start time (e.g. 2026-06-17T14:00:00-07:00)."},"ends_at":{"type":"string","description":"ISO 8601 end time."},"attendees":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"display_name":{"type":"string"}},"required":["email"]},"description":"List of attendees to invite. The calendar owner is always added automatically."},"description":{"type":"string","description":"Optional event body/description."},"location":{"type":"string","description":"Optional location string."},"accepted_time_evidence":{"type":"string","description":"Required for Ashley calendar creates: exact source-thread evidence selecting the time. For representational commitments this is separate from, and cannot replace, explicit principal consent."},"meeting_decided":{"type":"boolean","description":"For Ashley, true only when one exact time was selected. Panels, podcasts, interviews, talks, and guest appearances still require a verified principal-authored explicit yes."},"all_day":{"type":"boolean","description":"Set true for all-day events (default false).","default":false},"timezone":{"type":"string","description":"IANA timezone for interpreting starts_at/ends_at if not already offset-qualified."}},"required":["summary","starts_at","ends_at"]}}}}}},"/api/agents/v1/availability/find_slots":{"get":{"operationId":"availability_find_slots","summary":"Availability find slots","description":"Find candidate meeting slots across selected shared calendar feeds using duration, working hours, minimum notice, buffer, and date range. Returns privacy-safe slot recommendations with inferred city-level location for each selected person, a 30-minute location_timeline with exact-interval flight/location samples, plus meeting_preferences text; honor those preferences before offering or booking slots. For travel, use the sample overlapping each candidate slot so mid-day flight destination changes control the displayed timezone and acceptable local hours.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_find_slots","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_find_slots","parameters":[{"name":"people","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional person filters such as joe, jake, diego, full name, email, or client token. Omit to use all visible feeds."},{"name":"feeds","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional feed filters by feed id, label, or source email."},{"name":"start_at","in":"query","required":false,"schema":{"type":"string"},"description":"Search start timestamp or date. Defaults to today."},{"name":"end_at","in":"query","required":false,"schema":{"type":"string"},"description":"Search end timestamp or date. Capped at 31 days after start_at."},{"name":"duration_minutes","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Meeting duration in minutes, default 30, min 15, max 240."},{"name":"interval_minutes","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Candidate slot step size: 15, 30, 45, or 60."},{"name":"minimum_notice_minutes","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Minimum lead time before a slot can start."},{"name":"buffer_minutes","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Buffer applied before and after existing busy blocks."},{"name":"timezone","in":"query","required":false,"schema":{"type":"string"},"description":"IANA timezone, default America/Los_Angeles."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":8},"description":"Maximum slots to return, default 8, max 50."}]}},"/api/agents/v1/availability/people/list":{"get":{"operationId":"availability_people_list","summary":"Availability people list","description":"List people whose shared calendar availability is visible to the caller, including connected feed labels, health, freshness, inferred current city-level location, a 30-minute location_timeline with exact-interval location/flight samples, and each person's meeting_preferences text for Ashley scheduling constraints. Does not return event details or iCal URLs.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_people_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_people_list"}},"/api/agents/v1/availability/query":{"get":{"operationId":"availability_query","summary":"Availability query","description":"Query shared calendar free/busy windows for selected people or calendar feeds. Returns only busy windows, open slots, feed freshness, privacy-safe labels, actual event city locality when parseable, inferred city-level location context from flights/physical meetings/defaults, a 30-minute location_timeline with city/timezone and flight/in-air samples, and each selected person's meeting_preferences text for Ashley scheduling constraints. For travel, use the location_timeline sample overlapping the candidate slot as the primary timezone/location; it can change mid-day after a flight.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_query","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_query","parameters":[{"name":"people","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional person filters such as joe, jake, diego, full name, email, or client token. Omit to query all visible feeds."},{"name":"feeds","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional feed filters by feed id, label, or source email."},{"name":"emails","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional email filters."},{"name":"start_at","in":"query","required":false,"schema":{"type":"string"},"description":"Window start timestamp or date. Defaults to today in the requested timezone."},{"name":"end_at","in":"query","required":false,"schema":{"type":"string"},"description":"Window end timestamp or date. Capped at 31 days after start_at."},{"name":"timezone","in":"query","required":false,"schema":{"type":"string"},"description":"IANA timezone, default America/Los_Angeles."},{"name":"slot_minutes","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Open slot size: 15, 30, 45, or 60. Defaults to 30."}]}},"/api/agents/v1/availability/sources/list":{"get":{"operationId":"availability_sources_list","summary":"Availability sources list","description":"List visible calendar feed sources and sync health. Feed URLs are encrypted and never returned.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_sources_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_sources_list"}},"/api/agents/v1/availability/verify_booking":{"get":{"operationId":"availability_verify_booking","summary":"Availability verify booking","description":"Verify that a specific time window is now blocked on a person's calendar by triggering a fresh sync of their availability feed and checking for a busy block. Use this immediately after creating a calendar event to confirm the booking is real before telling the requester it was scheduled. Returns verified:true only when the sync succeeded AND a busy block covers the requested window. A person filter (people or emails) is required.","tags":["Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"availability_verify_booking","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"availability_verify_booking","parameters":[{"name":"people","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Person filters such as joe, jake, diego, email, or client token. Required."},{"name":"emails","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Email filters. Alternative to people."},{"name":"feeds","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Feed filters by feed id or label."},{"name":"starts_at","in":"query","required":true,"schema":{"type":"string"},"description":"ISO 8601 start of the meeting window to verify (e.g. 2026-06-17T14:00:00-07:00)."},{"name":"ends_at","in":"query","required":true,"schema":{"type":"string"},"description":"ISO 8601 end of the meeting window to verify."},{"name":"timezone","in":"query","required":false,"schema":{"type":"string"},"description":"IANA timezone for displaying results, default America/Los_Angeles."}]}},"/api/agents/v1/calendar_availability/query":{"get":{"operationId":"calendar_availability_query","summary":"Calendar availability query","description":"Query shared team calendar free/busy availability from connected private Google Calendar iCal feeds. This aliases availability/query and returns busy windows, candidate open slots, inferred_locations, busy-block location_context, and the 30-minute location_timeline with exact-interval location/flight samples; event titles, full meeting locations, attendees, and descriptions are not stored or returned.","tags":["Calendar Availability"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"calendar_availability_query","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"calendar_availability_query","parameters":[{"name":"emails","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional person email filters. Omit to query every connected shared calendar."},{"name":"client_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Optional person client tokens."},{"name":"start_at","in":"query","required":false,"schema":{"type":"string"},"description":"Window start timestamp or date. Defaults to today."},{"name":"end_at","in":"query","required":false,"schema":{"type":"string"},"description":"Window end timestamp or date. Capped at 31 days after start_at."},{"name":"slot_minutes","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Open slot size: 15, 30, 45, or 60. Defaults to 30."}]}},"/api/agents/v1/clients/get":{"get":{"operationId":"client_get","summary":"Client get","description":"Get detailed profile for a person/client by token, email, or name. Returns contact info, stored photo URL fields (including scraped_li_image_url), a cached-only profile_image_url display candidate, image suppression flags, timezone context with timezone_source, subscriber tags, and RSVP activity summary. For scheduling, an explicit timezone preference in the active thread overrides the Client timezone.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_get","parameters":[{"name":"client_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Client token, email address, or full name to look up."}]}},"/api/agents/v1/clients/linkedin_update":{"post":{"operationId":"client_linkedin_update","summary":"Client linkedin update","description":"Attach a normalized LinkedIn member profile URL to a person/client without creating or changing RSVP activity. Existing different URLs are preserved unless overwrite_existing is explicitly true.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_linkedin_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_linkedin_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_ref":{"type":"string","description":"Client token, email address, or full name to update."},"linkedin_url":{"type":"string","description":"LinkedIn member profile URL. Only linkedin.com/in/... URLs are accepted."},"create_if_missing":{"type":"boolean","description":"If true and client_ref is an email address with no Client record, create a minimal Client before storing the LinkedIn URL. Never creates from name-only refs.","default":false},"name":{"type":"string","description":"Optional name for a newly created email-address client."},"overwrite_existing":{"type":"boolean","description":"Replace an existing different LinkedIn URL. Defaults to false so identity conflicts require an explicit choice.","default":false},"source":{"type":"string","description":"Short source label such as verified_public_research."},"note":{"type":"string","description":"Optional audit note explaining how the identity match was verified."}},"required":["client_ref","linkedin_url"]}}}}}},"/api/agents/v1/clients/meetup_score_integrity_audit":{"get":{"operationId":"client_meetup_score_integrity_audit","summary":"Client meetup score integrity audit","description":"Index-owner audit for the exact malformed evaluator failure where a missing/invalid AI evaluation was coerced to a zero base meetup score and then stored after networking adjustment. Returns every affected client with payload error codes for repair.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_meetup_score_integrity_audit","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_meetup_score_integrity_audit","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max affected clients to return (default 100, max 500)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Pagination offset."}]}},"/api/agents/v1/clients/meetup_score_integrity_repair":{"post":{"operationId":"client_meetup_score_integrity_repair","summary":"Client meetup score integrity repair","description":"Index-owner repair canary for one client with the exact malformed zero-base meetup score signature. Defaults to dry-run and queues a guarded social-stats rescore only when confirm=true.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_meetup_score_integrity_repair","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_meetup_score_integrity_repair","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_ref":{"type":"string","description":"Exact client token, email, or full name."},"confirm":{"type":"boolean","description":"Must be true to enqueue the rescore. Omit or false for dry-run.","default":false}},"required":["client_ref"]}}}}}},"/api/agents/v1/clients/meetup_score_recompute":{"post":{"operationId":"client_meetup_score_recompute","summary":"Client meetup score recompute","description":"Index-owner-only single-client social-stats refresh and meetup-score recompute. Defaults to dry-run; queues the existing guarded worker only when confirm=true.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_meetup_score_recompute","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_meetup_score_recompute","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"client_token":{"type":"string","description":"Canonical client token. Provide exactly one of client_token or email."},"email":{"type":"string","description":"Exact email address. Normalized before lookup; provide exactly one of email or client_token."},"confirm":{"type":"boolean","description":"Must be true to enqueue the guarded worker. Omit or false for dry-run.","default":false}}}}}}}},"/api/agents/v1/clients/meetup_score_speaker_floor_audit":{"get":{"operationId":"clients_meetup_score_speaker_floor_audit","summary":"Clients meetup score speaker floor audit","description":"Generated from the Rails route api/agents#client_meetup_score_speaker_floor_audit. No MCP input schema is currently registered for this route; parameters are derived from route metadata and known query parameters.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_meetup_score_speaker_floor_audit","x-generated-from":"Rails routes"}},"/api/agents/v1/clients/merge":{"post":{"operationId":"client_merge","summary":"Client merge","description":"Merge one client account into another (admin API key only). Moves all of the source account records (RSVPs, posts, subscriptions, etc.) into the target account, then retires the source account by renaming its email, opting out its subscriptions, and signing it out everywhere. For unique-constrained associations the target records take precedence and source duplicates are deleted. Without confirm=true this returns a preview only; pass confirm=true to execute the merge.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_merge","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_merge","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source_email":{"type":"string","description":"Email address of the account whose records move (the account being retired)."},"target_email":{"type":"string","description":"Email address of the surviving account that receives the merged records."},"confirm":{"type":"boolean","description":"When true, execute the merge. Defaults to false, which returns a preview without changing anything.","default":false},"note":{"type":"string","maxLength":2000,"description":"Optional audit note explaining why the accounts are being merged."}},"required":["source_email","target_email"]}}}}}},"/api/agents/v1/clients/message_center_scorecard":{"get":{"operationId":"client_message_center_scorecard","summary":"Client message center scorecard","description":"Per-client 7-day (or custom window) rollup: posts, reactions received, mentions, and distinct boards active. Accepts batch of client_tokens.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_message_center_scorecard","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_message_center_scorecard","parameters":[{"name":"client_tokens","in":"query","required":true,"schema":{"type":"array","items":{"type":"string"}},"description":"Client tokens to summarize (required, max 100)."},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","default":7},"description":"Rolling window in days (default 7, max 90)."}]}},"/api/agents/v1/clients/phone_update":{"post":{"operationId":"client_phone_update","summary":"Client phone update","description":"Update a person/client contact phone number in the same Client fields used by profile, VIP dinner, and speaker phone capture. Stores normalized E.164 in clients.phone_number and national digits in clients.label_phone_number; does not create Phone records.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_phone_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_phone_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_ref":{"type":"string","description":"Client token, email address, or full name to update."},"phone_number_e164":{"type":"string","description":"Already-normalized E.164 phone number, for example +14155551234."},"raw_phone_number":{"type":"string","description":"Raw phone number as provided by the person, used when phone_number_e164 is not available."},"country_code":{"type":"string","description":"ISO country code for parsing raw_phone_number. Defaults to US.","default":"US"},"create_if_missing":{"type":"boolean","description":"If true and client_ref/email is an email address with no Client record, create a minimal Client before storing the phone number. Never creates from name-only refs.","default":false},"source":{"type":"string","description":"Short source label such as ashley_email_ea_v2_in_person_meeting."},"note":{"type":"string","description":"Optional audit note explaining where the number came from."}},"required":["client_ref"]}}}}}},"/api/agents/v1/clients/profile_search":{"get":{"operationId":"client_profile_search","summary":"Client profile search","description":"Search people by structured /profile networking answers. Supports exact filters for employment, help-with, looking-for, intro/contact preferences, role, scoped keyword search over profile text fields, and facets. Results are restricted to the API key owner visible client scope.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_profile_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_profile_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Optional keyword query over selected profile text fields."},{"name":"intent","in":"query","required":false,"schema":{"type":"string"},"description":"Optional preset: recruiting, hiring, sponsor_matching, warm_intros."},{"name":"text_fields","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Profile text fields to search. Options: bio, skills, interests, investing, startup, projects."},{"name":"facets","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Facet counts to return. Options: employment, help_with, looking_for, intro_preference, contact_preference, role, city."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 200)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Number of results to skip for pagination (default 0)."}]}},"/api/agents/v1/clients/search":{"get":{"operationId":"client_search","summary":"Client search","description":"Search for people/clients by name, email, or company. Supports filtering by city, tag, presentation history, and date range. Returns matching profiles with timezone context and timezone_source; scheduling agents must treat that timezone as a contextual default, never as stronger evidence than an explicit timezone preference in the active thread. If results need disambiguation, the response will indicate that.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term: name, email, or company."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 200)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Number of results to skip for pagination (default 0)."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"tag","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by subscriber tag."},{"name":"has_presented","in":"query","required":false,"schema":{"type":"boolean"},"description":"If true, only return people who have presented/demoed."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date filter (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date filter (YYYY-MM-DD)."}]}},"/api/agents/v1/clients/tag_update":{"post":{"operationId":"clients_tag_update","summary":"Clients tag update","description":"Generated from the Rails route api/agents#client_tag_update. No MCP input schema is currently registered for this route, so the request schema is intentionally permissive.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_tag_update","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/clients/timezone_update":{"post":{"operationId":"client_timezone_update","summary":"Client timezone update","description":"Set a person/client timezone (stored in clients.inferred_timezone, reported as timezone_source=client_record). Use when the inferred timezone is wrong, for example a Zurich-based member whose only RSVPs are on a Los Angeles-hosted HQ series. Accepts IANA identifiers such as Europe/Zurich or Rails zone names such as Zurich, and stores the canonical IANA identifier. Writes an audit note on the client.","tags":["Clients"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_timezone_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_timezone_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_ref":{"type":"string","description":"Client token, email address, or full name to update."},"timezone":{"type":"string","description":"IANA timezone such as Europe/Zurich or America/New_York. Rails zone names such as Zurich are also accepted."},"source":{"type":"string","description":"Short source label such as verified_public_research or member_stated."},"note":{"type":"string","description":"Optional audit note explaining how the timezone was determined."}},"required":["client_ref","timezone"]}}}}}},"/api/agents/v1/companies/enrichment/request":{"post":{"operationId":"companies_enrichment_request","summary":"Companies enrichment request","description":"Request public company research independently of person enrichment. Supply an existing company_token with a website, or domain and name for a new company. Reuses fresh research and joins active work across people. Does not assign employers. refresh explicitly requests new research but still joins active work. Poll companies_get.","tags":["Companies"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"companies_enrichment_request","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"companies_enrichment_request","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["idempotency_key"],"properties":{"company_token":{"type":"string"},"domain":{"type":"string"},"name":{"type":"string"},"idempotency_key":{"type":"string","maxLength":200},"refresh":{"type":"boolean","default":false}}}}}}}},"/api/agents/v1/companies/get":{"get":{"operationId":"companies_get","summary":"Companies get","description":"Read stored public company research by company_token, domain, or exact name. Returns latest usable data, freshness and last attempt. Never launches research or assigns people to companies. Ambiguous names require a domain or token.","tags":["Companies"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"companies_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"companies_get","parameters":[{"name":"company_token","in":"query","required":false,"schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}}]}},"/api/agents/v1/content/brand_scrub/analyze":{"post":{"operationId":"content_brand_scrub_analyze","summary":"Content brand scrub analyze","description":"Analyze text content for brand consistency with AI Tinkerers voice and style guidelines. Returns suggestions for improvement.","tags":["Content"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_brand_scrub_analyze","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_brand_scrub_analyze","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","description":"Text content to analyze (max 12000 chars)."},"channel":{"type":"string","description":"Communication channel (e.g. email, social, blog)."},"tone":{"type":"string","description":"Desired tone."},"target_audience":{"type":"string","description":"Target audience description."}},"required":["text"]}}}}}},"/api/agents/v1/content_pages/ai_assisted_draft/create":{"post":{"operationId":"content_page_ai_assisted_draft_create","summary":"Content page ai assisted draft create","description":"Queue an AI-assisted draft page for a city weblog. Returns immediately with the Sidekiq job id. Guarded to one accepted AI-assisted page job every five minutes and no concurrent active AI-assisted page jobs.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_ai_assisted_draft_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_ai_assisted_draft_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string","description":"City weblog token that should receive the generated draft."},"instructions":{"type":"string","description":"Prompt/instructions for the AI-assisted page creator."},"type":{"type":"string","description":"Optional draft type hint.","enum":["event","content"]}},"required":["weblog_token","instructions"]}}}}}},"/api/agents/v1/content_pages/body/publish":{"post":{"operationId":"content_page_body_publish","summary":"Content page body publish","description":"Promote a draft ContentPageVersion to live. This is a republish operation for pages that are already live and does not re-fire announcement emails.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_body_publish","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_body_publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"content_page_id":{"type":"string","description":"Optional numeric content page id."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"version_token":{"type":"string","description":"ContentPageVersion token to promote."},"expected_current_live_token":{"type":"string","description":"Optional optimistic concurrency token for the current live version."},"note":{"type":"string","description":"Optional audit note."}},"required":["version_token"]}}}}}},"/api/agents/v1/content_pages/body/revert":{"post":{"operationId":"content_page_body_revert","summary":"Content page body revert","description":"Revert a live content page to an older ContentPageVersion. Requires expected_current_live_token so race conditions are surfaced instead of silently overwriting newer edits.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_body_revert","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_body_revert","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"content_page_id":{"type":"string","description":"Optional numeric content page id."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"target_version_token":{"type":"string","description":"Older ContentPageVersion token to restore."},"expected_current_live_token":{"type":"string","description":"Required optimistic concurrency token for the current live version."},"note":{"type":"string","description":"Optional audit note."}},"required":["target_version_token","expected_current_live_token"]}}}}}},"/api/agents/v1/content_pages/body/update":{"post":{"operationId":"content_page_body_update","summary":"Content page body update","description":"Save a new draft ContentPageVersion for an editable content page. This does not publish the draft; call content_page_body_publish with the returned version_token to make it live.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_body_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_body_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"content_page_id":{"type":"string","description":"Optional numeric content page id."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"body_markdown":{"type":"string","description":"Full replacement markdown body for the draft."},"title":{"type":"string","description":"Optional replacement title."},"expected_live_version_token":{"type":"string","description":"Optional optimistic concurrency token for the current live version."},"note":{"type":"string","description":"Optional audit note."}},"required":["body_markdown"]}}}}}},"/api/agents/v1/content_pages/comments/create":{"post":{"operationId":"content_page_comment_create","summary":"Content page comment create","description":"Create a private editorial comment on a Post-Training guest post. Use parent_note_token to reply within an existing thread.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comment_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comment_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"content":{"type":"string","description":"Comment body text (max 2000 chars)."},"parent_note_token":{"type":"string","description":"Optional parent note token when replying."}},"required":["content"]}}}}}},"/api/agents/v1/content_pages/comments/delete":{"post":{"operationId":"content_page_comment_delete","summary":"Content page comment delete","description":"Soft-delete an editorial comment on a Post-Training guest post. Caller must be the author or an admin. Preserves history; the comment is marked deleted, not destroyed.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comment_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comment_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"note_token":{"type":"string","description":"Token of the comment to delete (required)."}},"required":["note_token"]}}}}}},"/api/agents/v1/content_pages/comments/list":{"get":{"operationId":"content_page_comments_list","summary":"Content page comments list","description":"List the private editorial comment thread for a Post-Training guest post, including replies.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comments_list","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Content page token."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier."}]}},"/api/agents/v1/content_pages/comments/reopen":{"post":{"operationId":"content_page_comment_reopen","summary":"Content page comment reopen","description":"Reopen a resolved private editorial comment thread on a Post-Training guest post. Passing a reply note token reopens the root thread comment.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comment_reopen","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comment_reopen","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"note_token":{"type":"string","description":"Token of the comment or reply to reopen."}},"required":["note_token"]}}}}}},"/api/agents/v1/content_pages/comments/resolve":{"post":{"operationId":"content_page_comment_resolve","summary":"Content page comment resolve","description":"Resolve a private editorial comment thread on a Post-Training guest post. Passing a reply note token resolves the root thread comment.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comment_resolve","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comment_resolve","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"note_token":{"type":"string","description":"Token of the comment or reply to resolve."}},"required":["note_token"]}}}}}},"/api/agents/v1/content_pages/comments/update":{"post":{"operationId":"content_page_comment_update","summary":"Content page comment update","description":"Edit the content of an existing editorial comment on a Post-Training guest post. Caller must be the author of the comment. Sets edited_at.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_comment_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_comment_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"note_token":{"type":"string","description":"Token of the comment to edit (required)."},"content":{"type":"string","description":"Replacement comment body text (max 2000 chars)."}},"required":["note_token","content"]}}}}}},"/api/agents/v1/content_pages/editorial/list":{"get":{"operationId":"editorial_submissions_list","summary":"Editorial submissions list","description":"List Post-Training guest-post submissions in the editorial workflow. Supports filtering by editorial status, series, author, publication date, and whether to include already-published items.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"editorial_submissions_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"editorial_submissions_list","parameters":[{"name":"editorial_status","in":"query","required":false,"schema":{"type":"string","enum":["draft","ready_for_review","editing_complete"]},"description":"Filter by editorial status."},{"name":"author_query","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by author name or email."},{"name":"series_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional series token filter."},{"name":"include_published","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include already-published historical posts (default false)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Earliest publication date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"Latest publication date (YYYY-MM-DD)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 100)."}]}},"/api/agents/v1/content_pages/editorial_status/update":{"post":{"operationId":"content_page_editorial_status_update","summary":"Content page editorial status update","description":"Update the editorial status of a Post-Training guest post. Reuses the existing status-change workflow, including notifications and event logging.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_editorial_status_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_editorial_status_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"status":{"type":"string","description":"New editorial status.","enum":["draft","ready_for_review","editing_complete"]},"note":{"type":"string","description":"Optional note to include with the status change."}},"required":["status"]}}}}}},"/api/agents/v1/content_pages/first_publish":{"post":{"operationId":"content_page_first_publish","summary":"Content page first publish","description":"Publish a non-meetup content page that has never been live. Requires the exact latest draft version token and expected current metadata so first publication cannot silently overwrite newer edits or stale title/body state. Meetup pages must use the meetup lifecycle publish endpoint.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_first_publish","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_first_publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"version_token":{"type":"string","description":"Exact latest draft ContentPageVersion token to publish."},"expected_title":{"type":"string","description":"Exact current page title expected before publication."},"expected_body_sha256":{"type":"string","description":"SHA-256 of the exact current body markdown expected before publication."},"note":{"type":"string","description":"Optional audit note."}},"required":["content_page_token","version_token","expected_title","expected_body_sha256"]}}}}}},"/api/agents/v1/content_pages/get":{"get":{"operationId":"content_page_get","summary":"Content page get","description":"Get a full visible content page, including body markdown, plain text, author metadata, editorial status, and change metadata. Use after weblog_universal_search returns a content_page token.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_get","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Content page token returned from editorial_submissions_list."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier within visible guest-post scope."},{"name":"include_version_history","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include all retained ContentPageVersion history rows with version tokens, timestamps, live status, and best-effort actor metadata. Default false."}]}},"/api/agents/v1/content_pages/metrics/get":{"get":{"operationId":"content_page_metrics_get","summary":"Content page metrics get","description":"Get email performance metrics for a Post-Training guest post, including sends, opens, and clicks.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_metrics_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_metrics_get","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Content page token."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier."}]}},"/api/agents/v1/content_pages/og_image/update":{"post":{"operationId":"content_page_og_image_update","summary":"Content page og image update","description":"Set or clear the Social Preview Image for a content page. External image URLs are imported to AI Tinkerers image storage; existing AI Tinkerers image URLs are reused.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_og_image_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_og_image_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"image_url":{"type":"string","description":"Absolute http(s) image URL to use as the custom social preview image."},"og_image_url":{"type":"string","description":"Alias for image_url."},"clear":{"type":"boolean","description":"Clear the custom image and return to auto-detect."},"mode":{"type":"string","description":"Use auto or clear to return to auto-detect.","enum":["custom","auto","clear"]}},"required":["content_page_token"]}}}}}},"/api/agents/v1/content_pages/public_comments/list":{"get":{"operationId":"content_page_public_comments_list","summary":"Content page public comments list","description":"List reader-visible public comments on a Post-Training guest post, including replies and comment-state metadata.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_public_comments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_public_comments_list","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Content page token."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier."}]}},"/api/agents/v1/content_pages/slug/update":{"post":{"operationId":"content_pages_slug_update","summary":"Content pages slug update","description":"Generated from the Rails route api/agents#content_page_slug_update. No MCP input schema is currently registered for this route, so the request schema is intentionally permissive.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_slug_update","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/content_pages/theme/update":{"post":{"operationId":"content_page_theme_update","summary":"Content page theme update","description":"Update or clear a ContentPage theme through the clean Agents API. This is the API replacement for browser-only /content_page/:token/update_theme and uses API-key auth, scopes, audit logging, and theme visibility rules.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_theme_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_theme_update","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Content page token."},"content_page_id":{"type":"string","description":"Optional numeric content page id."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"theme":{"type":"string","description":"Theme key to apply. Blank value clears to default."},"theme_key":{"type":"string","description":"Alias for theme."},"clear":{"type":"boolean","description":"Set true to clear the custom theme and use the default theme.","default":false}}}}}}}},"/api/agents/v1/content_pages/themes/list":{"get":{"operationId":"content_page_themes_list","summary":"Content page themes list","description":"List ContentPage themes available to the authenticated caller. Optionally include a content page ref to return the page current theme alongside the available themes.","tags":["Content Pages"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"content_page_themes_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"content_page_themes_list","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional content page token."},{"name":"content_page_id","in":"query","required":false,"schema":{"type":"string"},"description":"Optional numeric content page id."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier."}]}},"/api/agents/v1/docs/attachments/delete":{"post":{"operationId":"docs_attachment_delete","summary":"Docs attachment delete","description":"Delete a file attachment from a published doc you can edit. Identify it by token (from docs_attachments_list) or filename.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_attachment_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_attachment_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Doc path, \"pub/\u003cpublisher_token\u003e/\u003cpath\u003e\", or a full /docs URL."},"token":{"type":"string","description":"Attachment token."},"filename":{"type":"string","description":"Attachment filename (used when token is omitted)."}},"required":["path"]}}}}}},"/api/agents/v1/docs/attachments/list":{"get":{"operationId":"docs_attachments_list","summary":"Docs attachments list","description":"List file attachments (PDFs, images, office files) on a published doc you can view. Attachments inherit the doc's visibility and members. Each item includes a download_url that is signed for you and expires after 5 minutes (access is re-checked on use).","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_attachments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_attachments_list","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"Your doc path (e.g. \"finance/w9-current.html\"), \"pub/\u003cpublisher_token\u003e/\u003cpath\u003e\", or a full /docs URL."}]}},"/api/agents/v1/docs/attachments/upload":{"post":{"operationId":"docs_attachment_upload","summary":"Docs attachment upload","description":"Attach a small file to a published doc you can edit (publisher or edit member), sent as base64. Re-uploading the same filename replaces it. Max 10 MB; allowed: .pdf .png .jpg .jpeg .gif .webp .txt .csv .docx .xlsx .pptx. For anything but tiny files prefer docs_attachment_upload_url and send the bytes with curl.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_attachment_upload","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_attachment_upload","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Doc path, \"pub/\u003cpublisher_token\u003e/\u003cpath\u003e\", or a full /docs URL."},"filename":{"type":"string","description":"File name including extension (e.g. \"fw9-ai_tinkerers.pdf\")."},"content_base64":{"type":"string","description":"File bytes, base64-encoded."}},"required":["path","filename","content_base64"]}}}}}},"/api/agents/v1/docs/attachments/upload_url":{"post":{"operationId":"docs_attachment_upload_url","summary":"Docs attachment upload url","description":"Get a single-use upload URL (valid 15 minutes) for attaching a file to a published doc you can edit, so the file can be sent with curl instead of base64: curl -F \"file=@report.pdf\" \"\u003cupload_url\u003e\". Re-uploading the same filename replaces it. Max 10 MB.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_attachment_upload_url","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_attachment_upload_url","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Doc path, \"pub/\u003cpublisher_token\u003e/\u003cpath\u003e\", or a full /docs URL."},"filename":{"type":"string","description":"File name the attachment will be stored under, including extension."}},"required":["path","filename"]}}}}}},"/api/agents/v1/docs/chat":{"post":{"operationId":"docs_chat","summary":"Docs chat","description":"Ask a question about AI Tinkerers documentation using RAG-powered chat. Supports conversation history for follow-up questions. Can focus on all docs or a specific document.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_chat","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_chat","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"question":{"type":"string","description":"Your question about AI Tinkerers documentation."},"context_mode":{"type":"string","description":"Search scope.","enum":["documentation","current_document"],"default":"documentation"},"doc_path":{"type":"string","description":"Specific doc path (required if context_mode is current_document)."},"section":{"type":"string","description":"Focus on a specific section."},"chat_history":{"type":"array","items":{"type":"object","properties":{"user":{"type":"string"},"assistant":{"type":"string"}}},"description":"Previous conversation turns for context (max 12)."}},"required":["question"]}}}}}},"/api/agents/v1/docs/comments/create":{"post":{"operationId":"docs_comment_create","summary":"Docs comment create","description":"Create a comment on a documentation file. Use parent_note_token to reply within an existing thread. Top-level comments may include anchor metadata for inline selected text.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comment_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comment_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"doc_path":{"type":"string","description":"Path to the document (e.g. \"docs/aitfund/q2-2026-draft-v2.html\" or \"aitfund/q2-2026-draft-v2.html\")."},"content":{"type":"string","description":"Comment body text. Max 2000 characters."},"parent_note_token":{"type":"string","description":"Optional parent note token when replying."},"anchor":{"type":"object","description":"Optional inline anchor metadata for top-level comments. Include selected_text at minimum.","properties":{"selected_text":{"type":"string","description":"Exact selected text being commented on."},"prefix":{"type":"string","description":"Optional text before the selection."},"suffix":{"type":"string","description":"Optional text after the selection."},"anchor_version":{"type":"integer","description":"Anchor schema version.","default":1}}}},"required":["doc_path","content"]}}}}}},"/api/agents/v1/docs/comments/delete":{"post":{"operationId":"docs_comment_delete","summary":"Docs comment delete","description":"Soft-delete a caller-authored document comment.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comment_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comment_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"doc_path":{"type":"string","description":"Path to the document."},"note_token":{"type":"string","description":"Token of the comment to delete."}},"required":["doc_path","note_token"]}}}}}},"/api/agents/v1/docs/comments/list":{"get":{"operationId":"docs_comments_list","summary":"Docs comments list","description":"List comments on a documentation file by doc_path. Includes inline comment anchor metadata when a comment is attached to selected document text.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comments_list","parameters":[{"name":"doc_path","in":"query","required":true,"schema":{"type":"string"},"description":"Path to the document (e.g. \"docs/aitfund/q2-2026-draft-v2.html\" or \"aitfund/q2-2026-draft-v2.html\")."},{"name":"author_client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional: only return comments authored by this client token."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Alias for author_client_token."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max comments to return (default 100, max 200)."}]}},"/api/agents/v1/docs/comments/reopen":{"post":{"operationId":"docs_comment_reopen","summary":"Docs comment reopen","description":"Reopen a resolved document comment thread. Passing a reply note token reopens the root thread comment.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comment_reopen","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comment_reopen","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"doc_path":{"type":"string","description":"Path to the document."},"note_token":{"type":"string","description":"Token of the comment or reply to reopen."}},"required":["doc_path","note_token"]}}}}}},"/api/agents/v1/docs/comments/resolve":{"post":{"operationId":"docs_comment_resolve","summary":"Docs comment resolve","description":"Resolve a document comment thread. Passing a reply note token resolves the root thread comment.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comment_resolve","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comment_resolve","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"doc_path":{"type":"string","description":"Path to the document."},"note_token":{"type":"string","description":"Token of the comment or reply to resolve."}},"required":["doc_path","note_token"]}}}}}},"/api/agents/v1/docs/comments/search":{"get":{"operationId":"docs_comments_search","summary":"Docs comments search","description":"Search comments on a documentation file by text. Matches comment body and inline selected-text anchors, with optional author filtering.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_comments_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_comments_search","parameters":[{"name":"doc_path","in":"query","required":true,"schema":{"type":"string"},"description":"Path to the document (e.g. \"docs/aitfund/q2-2026-draft-v2.html\" or \"aitfund/q2-2026-draft-v2.html\")."},{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Text to search for in comment content or inline selected text."},{"name":"author_client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional: only search comments authored by this client token."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Alias for author_client_token."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max comments to return (default 100, max 200)."}]}},"/api/agents/v1/docs/delete":{"post":{"operationId":"docs_delete","summary":"Docs delete","description":"Generated from the Rails route api/agents#docs_unpublish. No MCP input schema is currently registered for this route, so the request schema is intentionally permissive.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_unpublish","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/docs/edit":{"post":{"operationId":"docs_edit","summary":"Docs edit","description":"Apply deterministic text replacements to an API-published doc owned by the caller. Requires base_sha256 from doc_get and rejects stale or ambiguous edits.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_edit","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_edit","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"doc_path":{"type":"string","description":"Path to the published document (e.g. \"aitfund/q2-2026-draft-v2.html\" or \"docs/aitfund/q2-2026-draft-v2.html\")."},"base_sha256":{"type":"string","description":"SHA-256 digest from the most recent doc_get response. Required for conflict detection."},"dry_run":{"type":"boolean","description":"Validate and preview the edit without writing the document.","default":false},"operations":{"type":"array","description":"Ordered deterministic edit operations. Max 10.","items":{"type":"object","properties":{"op":{"type":"string","enum":["replace_text"],"description":"Only replace_text is currently supported."},"find":{"type":"string","description":"Literal text to find. No regex."},"replace":{"type":"string","description":"Literal replacement text. Use an empty string to delete text."},"occurrence":{"description":"Which occurrence to replace: 'exactly_one' (default), 'all', or a 1-based integer.","default":"exactly_one"}},"required":["find","replace"]}}},"required":["doc_path","base_sha256","operations"]}}}}}},"/api/agents/v1/docs/find":{"get":{"operationId":"docs_find","summary":"Docs find","description":"Search for documentation files by keyword. Returns matching doc paths, titles, and descriptions.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_find","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_find","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term for documentation."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20},"description":"Max results (default 20, max 20)."},{"name":"path_prefix","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to docs under a specific path prefix."}]}},"/api/agents/v1/docs/get":{"get":{"operationId":"doc_get","summary":"Doc get","description":"Get the full content of a specific documentation file by path. Returns title, content text, format, raw SHA-256, and metadata.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"doc_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"doc_get","parameters":[{"name":"doc_path","in":"query","required":true,"schema":{"type":"string"},"description":"Path or /docs URL for the document (e.g. \"docs/product/architecture.md\")."}]}},"/api/agents/v1/docs/meeting_prep/find":{"get":{"operationId":"docs_meeting_prep_find","summary":"Docs meeting prep find","description":"Deterministically find a meeting-prep document by calendar owner and meeting time using structured published-doc metadata. Use this before docs_find/docs_chat for questions like \"what is the prep for my 1pm meeting today?\".","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_meeting_prep_find","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_meeting_prep_find","parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"},"description":"Calendar owner slug or email, such as \"joe\" or \"joe@hq.aitinkerers.org\"."},{"name":"calendar_owner_email","in":"query","required":false,"schema":{"type":"string"},"description":"Exact calendar owner email."},{"name":"calendar_owner_slug","in":"query","required":false,"schema":{"type":"string"},"description":"Calendar owner slug, usually the email prefix."},{"name":"calendar_event_id","in":"query","required":false,"schema":{"type":"string"},"description":"Exact calendar event id, when known."},{"name":"date","in":"query","required":false,"schema":{"type":"string"},"description":"Meeting date, e.g. \"2026-06-25\" or \"today\"."},{"name":"time","in":"query","required":false,"schema":{"type":"string"},"description":"Meeting local time, e.g. \"13:00\" or \"1pm\"."},{"name":"meeting_start_at","in":"query","required":false,"schema":{"type":"string"},"description":"Exact meeting start timestamp, if known."},{"name":"timezone","in":"query","required":false,"schema":{"type":"string"},"description":"IANA timezone for date/time parsing, defaulting to the app timezone."},{"name":"tolerance_minutes","in":"query","required":false,"schema":{"type":"integer"},"description":"Time window around the requested start time. Default 15, max 720."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":5},"description":"Max results (default 5, max 20)."}]}},"/api/agents/v1/docs/members/add":{"post":{"operationId":"docs_members_add","summary":"Docs members add","description":"Add document members by email. Members get read access regardless of base visibility tier, with optional \"view\" (default) or \"edit\" permission. Stub Clients are created for unrecognized emails. Only the publishing client can call this on their own docs. Optional suppression of member-added emails is supported.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_members_add","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_members_add","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Path of the document."},"emails":{"type":"array","items":{"type":"string"},"description":"List of email addresses to add as members (max 50)."},"permission":{"type":"string","enum":["view","edit"],"description":"Permission for the members: \"view\" (default) or \"edit\"."},"suppress_member_notifications":{"type":"boolean","description":"When true, add new members without sending \"you have been added to a document\" emails. Defaults false."}},"required":["path","emails"]}}}}}},"/api/agents/v1/docs/members/remove":{"post":{"operationId":"docs_members_remove","summary":"Docs members remove","description":"Remove document members by email. Only the publishing client can call this on their own docs.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_members_remove","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_members_remove","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Path of the document."},"emails":{"type":"array","items":{"type":"string"},"description":"List of email addresses to remove (max 50)."}},"required":["path","emails"]}}}}}},"/api/agents/v1/docs/members/update":{"post":{"operationId":"docs_members_update","summary":"Docs members update","description":"Change document-member permissions by email. Only the publishing client can call this on their own docs. Edit members can use docs_edit with their own API keys; view members cannot.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_members_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_members_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Path of the document."},"emails":{"type":"array","items":{"type":"string"},"description":"Existing member email addresses to update (max 50)."},"permission":{"type":"string","enum":["view","edit"],"description":"New permission: \"view\" or \"edit\"."}},"required":["path","emails","permission"]}}}}}},"/api/agents/v1/docs/publish":{"post":{"operationId":"docs_publish","summary":"Docs publish","description":"Publish or update a markdown or HTML document into the logical docs tree. Content is stored in published docs storage, but the returned URL resolves at /docs/\u003cpath\u003e. Max 2 MB content. Only .md and .html extensions allowed. Optional visibility tier (\"private\", \"index_owner\" (default), \"public\", \"members\", or \"city:\u003cslug\u003e\"), optional members email list, and optional suppression of member-added emails.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_publish","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_publish","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Document file path (max 200 chars). A leading docs/ is accepted and stripped. The .md extension is added if missing."},"content":{"type":"string","description":"Document content as raw text."},"visibility":{"type":["string","array"],"description":"Visibility tier: \"private\", \"index_owner\", \"public\", \"members\", or \"city:\u003cslug\u003e\" (or an array of \"city:\u003cslug\u003e\" entries for multi-city). Public fund documents are allowed only under aitfund/public/. Defaults to \"index_owner\" if omitted on a new doc, or preserves the existing tier on a re-publish."},"cities":{"type":"array","items":{"type":"string"},"description":"Optional explicit city slugs when visibility is \"city\". Combined with any \"city:\u003cslug\u003e\" entries in visibility."},"members":{"type":"array","items":{"type":"string"},"description":"Optional list of email addresses to add as document members. Members are additive on top of any base tier."},"suppress_member_notifications":{"type":"boolean","description":"When true, create any new document memberships without sending \"you have been added to a document\" emails. Defaults false."}},"required":["path","content"]}}}}}},"/api/agents/v1/docs/published/get":{"get":{"operationId":"docs_published_get","summary":"Docs published get","description":"Read the current visibility tier, cities, and full members list for a single doc you have published. Restricted to the publishing client; returns 404 for paths the caller did not publish. Use this to inquire about a doc's auth state without listing your full library.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_published_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_published_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"Path of the document (relative to your published-docs storage). The .md extension is added if missing."}]}},"/api/agents/v1/docs/published/list":{"get":{"operationId":"docs_published_list","summary":"Docs published list","description":"List all published documents for your API client. Returns metadata for all .md and .html files, sorted by modified date descending. Includes visibility tier, cities array, and members count for each doc.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_published_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_published_list"}},"/api/agents/v1/docs/unpublish":{"post":{"operationId":"docs_unpublish","summary":"Docs unpublish","description":"Delete a published document from your storage. Cleans up empty parent directories and removes any DocMembership entries.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_unpublish","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_unpublish","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Path of the document to delete (max 200 chars)."}},"required":["path"]}}}}}},"/api/agents/v1/docs/visibility":{"post":{"operationId":"docs_visibility","summary":"Docs visibility","description":"Change the visibility tier of an already-published doc without re-uploading content. Only the publishing client can call this on their own docs.","tags":["Docs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"docs_visibility","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"docs_visibility","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"Path of the document."},"visibility":{"type":["string","array"],"description":"New visibility tier (same shape as docs_publish)."},"cities":{"type":"array","items":{"type":"string"},"description":"Optional city slugs for the city tier."}},"required":["path","visibility"]}}}}}},"/api/agents/v1/dossier/get":{"get":{"operationId":"dossier_get","summary":"Dossier get","description":"Build a compact internal dossier for an AI Tinkerers person/member. Includes bio/work/education, general and series screening scores with rationale, RSVP/talk/board/guest post/organizer/hackathon activity, and event-specific RSVP decision guidance when meetup_token is provided.","tags":["Dossier"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"dossier_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"dossier_get","parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Person email address."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Client token. Use this when already known."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Fallback name/company query when email or client_token is not available."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional event token for event-specific RSVP/status guidance."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10},"description":"Max recent activity rows per section (default 10, max 25)."}]}},"/api/agents/v1/email_send_jobs/compare":{"get":{"operationId":"email_send_jobs_compare","summary":"Email send jobs compare","description":"Compare multiple send jobs side by side. Returns delivery stats, engagement rates (opens, clicks, bounces), send duration, and average throughput for each job.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_jobs_compare","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_jobs_compare","parameters":[{"name":"tokens","in":"query","required":true,"schema":{"type":"array","items":{"type":"string"}},"description":"Array of send job tokens to compare (max 10)."}]}},"/api/agents/v1/email_send_jobs/get":{"get":{"operationId":"email_send_job_get","summary":"Email send job get","description":"Get detailed status of a single email send job including delivery accounting, send progress, suppression breakdown, recipient pipeline info, and body fields when the caller has campaign email tool access. Body email addresses are redacted unless the caller is an admin or index owner.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_job_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_job_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The send job token (e.g. from email_send_jobs_list)."}]}},"/api/agents/v1/email_send_jobs/list":{"get":{"operationId":"email_send_jobs_list","summary":"Email send jobs list","description":"List email send jobs with status, progress, and delivery accounting. Filter by status (queued, sending, completed, failed, active) and date range. Shows observed send rate and predicted finish time for active sends.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_jobs_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_jobs_list","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","sending","completed","failed","active","all"],"default":"all"},"description":"Filter by status."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Max 365 days range."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to sends for a specific content page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["created_at","started_at","finished_at"],"default":"created_at"},"description":"Sort column."},{"name":"sort_dir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort direction."}]}},"/api/agents/v1/email_send_jobs/recipients/list":{"get":{"operationId":"email_send_job_recipients_list","summary":"Email send job recipients list","description":"List recipients for a send job with their delivery status. Supports pagination and status filtering. Uses recipient table pipeline when available, falls back to mail_logs for legacy jobs.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_job_recipients_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_job_recipients_list","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The send job token."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","sent","failed","all"],"default":"all"},"description":"Filter by recipient status."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 200)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Pagination offset (max 10000)."}]}},"/api/agents/v1/email_send_jobs/ses_status":{"get":{"operationId":"email_send_job_ses_status_get","summary":"Email send job ses status get","description":"Get SES sending quota status, active send jobs with their rates, stuck job detection, and system-level alerts. Requires index_owner role. Use for operational monitoring of the email sending infrastructure.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_job_ses_status_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_job_ses_status_get"}},"/api/agents/v1/email_send_jobs/summary":{"get":{"operationId":"email_send_jobs_summary","summary":"Email send jobs summary","description":"Summarize aggregate email send-job delivery for a meetup/event or content page. Use when a manager, organizer, or index owner asks how many emails have been sent about an event or campaign. Returns totals, a concise answer string, status counts, and recent send-job rows.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_jobs_summary","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_jobs_summary","parameters":[{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional meetup/event token to summarize. Use this for event-specific questions."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional content page token to summarize. If omitted with meetup_token, the meetup content page is included automatically."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10},"description":"Max recent send-job rows to return (default 10, max 50)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Max 365 days range."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/email_send_jobs/throughput":{"get":{"operationId":"email_send_job_throughput_get","summary":"Email send job throughput get","description":"Get send throughput time series for a send job. Returns emails sent per time bucket with peak and average rates. Useful for visualizing send velocity and identifying bottlenecks.","tags":["Email Send Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"email_send_job_throughput_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"email_send_job_throughput_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The send job token."},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["minute","5min","hour"],"default":"minute"},"description":"Time bucket size."}]}},"/api/agents/v1/event_promos/generate":{"post":{"operationId":"event_promo_generate","summary":"Event promo generate","description":"Generate a launch-ready event promotion package for a meetup, including RSVP copy, social posts, reminder email, and recap angle.","tags":["Event Promos"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"event_promo_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"event_promo_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Meetup token."},"package_type":{"type":"string","enum":["launch","reminder","final_push","recap","full_campaign"],"description":"Promotion package type.","default":"full_campaign"},"audience":{"type":"string","enum":["general","builders","founders","sponsors","students"],"description":"Target audience.","default":"general"}},"required":["meetup_token"]}}}}}},"/api/agents/v1/fund_content/brand_scrub/analyze":{"post":{"operationId":"fund_content_brand_scrub_analyze","summary":"Fund content brand scrub analyze","description":"Generated from the Rails route api/agents#restricted_content_brand_scrub_analyze. No MCP input schema is currently registered for this route, so the request schema is intentionally permissive.","tags":["Fund Content"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"restricted_content_brand_scrub_analyze","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/gallery/photos/delete":{"post":{"operationId":"event_photo_delete","summary":"Event photo delete","description":"Permanently delete an event gallery photo and its comments. Requires a write-enabled key and either explicit AI Tinkerers index ownership or ownership of the photo uploader account. City ownership and admin status alone do not authorize deletion. Shared R2 objects are retained. Supply both event and photo tokens.","tags":["Gallery"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"event_photo_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"event_photo_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Event containing the photo."},"photo_token":{"type":"string","description":"Gallery photo token to permanently delete."}},"required":["meetup_token","photo_token"]}}}}}},"/api/agents/v1/gallery/photos/upload":{"post":{"operationId":"event_photo_upload","summary":"Event photo upload","description":"Upload a JPEG, PNG, or WebP to an event photo gallery (max 10 MB, 40 million pixels). Requires event management permission. Optionally credit an eligible attendee, sponsor, or organizer using uploaded_by_client_token; the actual caller is preserved in the audit log. Identical bytes in the same gallery return the existing photo without changing its uploader. Returns the saved photo, uploader credit, and gallery URL.","tags":["Gallery"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"event_photo_upload","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"event_photo_upload","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Target event token."},"filename":{"type":"string","description":"Photo filename including extension."},"body_base64":{"type":"string","description":"Image bytes encoded as base64, without a data URL prefix."},"uploaded_by_client_token":{"type":"string","description":"Optional credited uploader token. Defaults to the authenticated caller."}},"required":["meetup_token","filename","body_base64"]}}}}}},"/api/agents/v1/gallery/search":{"get":{"operationId":"gallery_search","summary":"Gallery search","description":"Generated from the Rails route api/agents#gallery_search. No MCP input schema is currently registered for this route; parameters are derived from route metadata and known query parameters.","tags":["Gallery"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"gallery_search","x-generated-from":"Rails routes"}},"/api/agents/v1/global_hackathons/cities":{"get":{"operationId":"global_hackathon_cities_list","summary":"Global hackathon cities list","description":"List participating cities for a specific global hackathon. Shows city details, status, and participation info.","tags":["Global Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"global_hackathon_cities_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"global_hackathon_cities_list","parameters":[{"name":"hackathon_slug","in":"query","required":true,"schema":{"type":"string"},"description":"Hackathon slug identifier (required)."},{"name":"location_status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city status."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search for specific cities."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max results (default 100, max 200)."}]}},"/api/agents/v1/global_hackathons/cities/attach":{"post":{"operationId":"global_hackathon_city_attach","summary":"Global hackathon city attach","description":"Attach an existing hackathon/meetup to a global hackathon series. Supports dry-run preview and guarded reassignment.","tags":["Global Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"global_hackathon_city_attach","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"global_hackathon_city_attach","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Target global hackathon slug identifier (required)."},"hackathon_token":{"type":"string","description":"Existing hackathon token to attach."},"meetup_token":{"type":"string","description":"Meetup token for the existing hackathon to attach."},"dry_run":{"type":"boolean","description":"Preview the change without saving (default false).","default":false},"allow_reassign":{"type":"boolean","description":"Allow moving a hackathon that is already attached to another global hackathon (default false).","default":false},"sync_boards":{"type":"boolean","description":"Sync global organizer boards after saving (default true).","default":true}},"required":["hackathon_slug"]}}}}}},"/api/agents/v1/global_hackathons/entries":{"post":{"operationId":"global_hackathon_entries_list","summary":"Global hackathon entries list","description":"List hackathon submissions for a global hackathon with project, winner, city, and accepted builder/team data for recaps and winner spotlights.","tags":["Global Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"global_hackathon_entries_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"global_hackathon_entries_list","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Hackathon slug identifier (required)."},"hackathon_token":{"type":"string","description":"Optional hackathon token to filter to a single city/event."},"city":{"type":"string","description":"Optional city name filter."},"status":{"type":"string","description":"Entry status filter.","enum":["finalized","in_progress","all"],"default":"finalized"},"limit":{"type":"integer","description":"Max results (default 50, max 200).","default":50},"offset":{"type":"integer","description":"Pagination offset (default 0, max 10000).","default":0}},"required":["hackathon_slug"]}}}}}},"/api/agents/v1/global_hackathons/list":{"get":{"operationId":"global_hackathon_list","summary":"Global hackathon list","description":"List global hackathon events. Filter by search query and location status.","tags":["Global Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"global_hackathon_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"global_hackathon_list","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term."},{"name":"location_status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by location status."},{"name":"include_hackathons","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include hackathon details (default true)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 25)."}]}},"/api/agents/v1/gmail/relationship_history":{"get":{"operationId":"relationship_history_get","summary":"Relationship history get","description":"Build relationship history for one email address from Joe's Gmail and AI Tinkerers records. Use before sponsor, VIP, fund, organizer, partnership, or other relationship-sensitive replies. Returns prior interactions, promises, open loops, tone, owners, guidance, evidence, and confidence impact.","tags":["Gmail"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"relationship_history_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"relationship_history_get","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"},"description":"Counterparty email address."},{"name":"max_threads","in":"query","required":false,"schema":{"type":"integer","default":8,"minimum":1,"maximum":12},"description":"Maximum Gmail threads to inspect."},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer","default":730,"minimum":1,"maximum":1825},"description":"Gmail history window in days."}]}},"/api/agents/v1/guest_radar/comments/create":{"post":{"operationId":"guest_radar_comment_create","summary":"Guest radar comment create","description":"Add an attributed organizer comment and optionally mark the person as needing help.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_comment_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_comment_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"radar_person_token":{"type":"string"},"idempotency_key":{"type":"string"},"body":{"type":"string"},"mark_needs_help":{"type":"boolean"}},"required":["radar_person_token","idempotency_key","body"]}}}}}},"/api/agents/v1/guest_radar/comments/list":{"get":{"operationId":"guest_radar_comments_list","summary":"Guest radar comments list","description":"List the organizer conversation attached to one Prospecting person.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_comments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_comments_list","parameters":[{"name":"radar_person_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}]}},"/api/agents/v1/guest_radar/imports/commit":{"post":{"operationId":"guest_radar_import_commit","summary":"Guest radar import commit","description":"Commit the exact rows and source covered by a signed Prospecting import preview.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_import_commit","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_import_commit","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string"},"idempotency_key":{"type":"string"},"proposal_token":{"type":"string"},"source_text":{"type":"string"},"people":{"type":"array","maxItems":50,"items":{"type":"object"}}},"required":["weblog_token","idempotency_key","proposal_token","source_text","people"]}}}}}},"/api/agents/v1/guest_radar/imports/preview":{"post":{"operationId":"guest_radar_import_preview","summary":"Guest radar import preview","description":"Parse free-form organizer text into a write-free, reviewable proposal and return a signed short-lived proposal token.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_import_preview","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_import_preview","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string"},"source_text":{"type":"string"}},"required":["weblog_token","source_text"]}}}}}},"/api/agents/v1/guest_radar/people/bulk_create":{"post":{"operationId":"guest_radar_people_bulk_create","summary":"Guest radar people bulk create","description":"Create up to 50 structured Prospecting people transactionally, skipping possible duplicates and sending one aggregate notification.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_people_bulk_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_people_bulk_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string"},"idempotency_key":{"type":"string"},"source_text":{"type":"string"},"people":{"type":"array","maxItems":50,"items":{"type":"object"}}},"required":["weblog_token","idempotency_key","people"]}}}}}},"/api/agents/v1/guest_radar/people/create":{"post":{"operationId":"guest_radar_person_create","summary":"Guest radar person create","description":"Create one partial Prospecting person. Requires a write-scoped personal key and an idempotency key.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_person_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_person_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string"},"idempotency_key":{"type":"string"},"person":{"type":"object"}},"required":["weblog_token","idempotency_key","person"]}}}}}},"/api/agents/v1/guest_radar/people/get":{"get":{"operationId":"guest_radar_person_get","summary":"Guest radar person get","description":"Get one authorized Prospecting person, including partial contact data, attribution, state, and stable references.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_person_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_person_get","parameters":[{"name":"radar_person_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/guest_radar/people/list":{"get":{"operationId":"guest_radar_people_list","summary":"Guest radar people list","description":"List and filter people in one authorized Prospecting.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_people_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_people_list","parameters":[{"name":"weblog_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"query","in":"query","required":false,"schema":{"type":"string"}},{"name":"active","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["on_radar","learning","path_found","reaching_out","known","paused"]}},{"name":"priority","in":"query","required":false,"schema":{"type":"string","enum":["high","medium","low"]}},{"name":"city","in":"query","required":false,"schema":{"type":"string"}},{"name":"unknown_city","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"needs_help","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"owned_by_client_token","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}]}},"/api/agents/v1/guest_radar/people/update":{"post":{"operationId":"guest_radar_person_update","summary":"Guest radar person update","description":"Patch one Prospecting person with required optimistic concurrency and idempotency protection.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_person_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_person_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"radar_person_token":{"type":"string"},"expected_updated_at":{"type":"string"},"idempotency_key":{"type":"string"},"changes":{"type":"object"}},"required":["radar_person_token","expected_updated_at","idempotency_key","changes"]}}}}}},"/api/agents/v1/guest_radar/weblogs/list":{"get":{"operationId":"guest_radar_weblogs_list","summary":"Guest radar weblogs list","description":"List private Prospecting weblogs accessible to the personal Agent API key owner.","tags":["Guest Radar"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"guest_radar_weblogs_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"guest_radar_weblogs_list"}},"/api/agents/v1/hackathon_teams/search":{"get":{"operationId":"hackathon_team_search","summary":"Hackathon team search","description":"Search hackathon teams by team name, compact name, project name, hackathon, city, or tokens. Returns team tokens, team page URLs, and message center board details for team chat lookup.","tags":["Hackathon Teams"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"hackathon_team_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"hackathon_team_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term. Compact matching lets \"a2zai\" match names like \"A2Z AI\"."},{"name":"hackathon_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific hackathon token."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to the hackathon attached to a specific meetup token."},{"name":"hackathon_slug","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a global hackathon slug."},{"name":"team_type","in":"query","required":false,"schema":{"type":"string","enum":["participant","judge","sponsor","volunteer","mentor","organizer"]},"description":"Filter by team type."},{"name":"include_deleted","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include soft-deleted teams (default false)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."}]}},"/api/agents/v1/hackathons/sponsors":{"get":{"operationId":"hackathon_sponsors_get","summary":"Hackathon sponsors get","description":"Get the sponsors and selected sponsor logo/click URLs for a hackathon. Returns detected sponsor names, inferred logo and click URLs, configured logo and click URLs, venue sponsor, and whether the caller can update selections.","tags":["Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"hackathon_sponsors_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"hackathon_sponsors_get","parameters":[{"name":"hackathon_token","in":"query","required":false,"schema":{"type":"string"},"description":"Hackathon token."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Meetup token for the hackathon."}]}},"/api/agents/v1/hackathons/sponsors/logo":{"post":{"operationId":"hackathon_sponsor_logo_update","summary":"Hackathon sponsor logo update","description":"Change the selected meetup-level sponsor logo URL and/or sponsor click URL for one sponsor on the meetup backing a hackathon. Provide logo_url, click_url, or both. Caller must be authorized to manage sponsor logos for that meetup.","tags":["Hackathons"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"hackathon_sponsor_logo_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"hackathon_sponsor_logo_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_token":{"type":"string","description":"Hackathon token."},"meetup_token":{"type":"string","description":"Meetup token for the hackathon."},"sponsor_label":{"type":"string","description":"Sponsor name/label to update."},"logo_url":{"type":"string","description":"Selected logo image URL. Must be http or https when present."},"click_url":{"type":"string","description":"Sponsor destination URL. Must be http or https when present; pass an empty string to clear an existing click URL."}},"required":["sponsor_label"]}}}}}},"/api/agents/v1/jobs/ad_data":{"get":{"operationId":"job_ad_data_get","summary":"Job ad data get","description":"Get detailed performance data for a specific job ad, including click stats, performance interpretation, and click-through people. Allowed only for the ad purchaser or an explicit AI Tinkerers index owner.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_ad_data_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_ad_data_get","parameters":[{"name":"ad_token","in":"query","required":true,"schema":{"type":"string"},"description":"Job ad token."},{"name":"click_people_limit","in":"query","required":false,"schema":{"type":"integer","default":500},"description":"Max people who clicked to return (default 500, max 1000)."}]}},"/api/agents/v1/jobs/ats/configure":{"post":{"operationId":"job_ats_configure","summary":"Job ats configure","description":"Privileged support endpoint for admins and explicit AI Tinkerers index owners. Validates and saves the Ashby job posting ID on a job ad, optionally enabling sync and enqueueing the backlog.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_ats_configure","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_ats_configure","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ad_token":{"type":"string","description":"Exact job ad token."},"ats_job_posting_id":{"type":"string","description":"Ashby job posting ID to save."},"ats_sync_enabled":{"type":"boolean","description":"Whether structured ATS API sync should be enabled."},"validate":{"type":"boolean","description":"Validate the posting via Ashby before saving (default true).","default":true},"enqueue_backlog":{"type":"boolean","description":"Enqueue unsynced submitted leads after saving (default true).","default":true}},"required":["ad_token","ats_job_posting_id"]}}}}}},"/api/agents/v1/jobs/ats/postings/list":{"post":{"operationId":"job_ats_postings_list","summary":"Job ats postings list","description":"Privileged support endpoint for admins and explicit AI Tinkerers index owners. Lists Ashby job postings for a job ad using its stored Ashby API key and ranks likely matches.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_ats_postings_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_ats_postings_list","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ad_token":{"type":"string","description":"Exact job ad token."}},"required":["ad_token"]}}}}}},"/api/agents/v1/jobs/ats/sync_status":{"post":{"operationId":"job_ats_sync_status","summary":"Job ats sync status","description":"Summarize submitted inquiry delivery to an ATS for a job ad, including local email/API sync fields, AshbySyncWorker Sidekiq queue state, and optional Ashby application.list remote verification. Candidate details are only returned when the API key owner is the ad purchaser or an explicit AI Tinkerers index owner.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_ats_sync_status","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_ats_sync_status","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ad_token":{"type":"string","description":"Exact job ad token."},"include_queue":{"type":"boolean","description":"Include AshbySyncWorker Sidekiq queued/retry/dead jobs for the ad inquiries (default true).","default":true},"verify_remote":{"type":"boolean","description":"Call Ashby application.list using the stored API key to verify which inquiry candidates appear on the configured Ashby job (default false).","default":false},"limit":{"type":"integer","description":"Max submitted inquiries to inspect (default 100, max 100).","default":100}},"required":["ad_token"]}}}}}},"/api/agents/v1/jobs/inquiries/list":{"get":{"operationId":"job_inquiries_list","summary":"Job inquiries list","description":"List submitted job inquiries for one ad with recruiter notification, delivery, resume, and ATS push status. Candidate details are only returned when the API key owner is the ad purchaser or an explicit AI Tinkerers index owner.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_inquiries_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_inquiries_list","parameters":[{"name":"ad_token","in":"query","required":true,"schema":{"type":"string"},"description":"Exact job ad token."},{"name":"include_mail_logs","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include recruiter notification mail log details (default true)."},{"name":"include_ats","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include ATS status fields (default true)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max submitted inquiries (default 50, max 100)."}]}},"/api/agents/v1/jobs/inquiries/push_ats":{"post":{"operationId":"job_inquiry_push_ats","summary":"Job inquiry push ats","description":"Repair ATS delivery for a submitted job inquiry by resending the Ashby intake email BCC and/or queueing the Ashby API sync when the ad is fully configured. Allowed only for the ad purchaser or an explicit AI Tinkerers index owner.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_inquiry_push_ats","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_inquiry_push_ats","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"inquiry_token":{"type":"string","description":"Submitted job inquiry token."},"mode":{"type":"string","description":"Delivery path to repair.","enum":["email","api","both"],"default":"both"},"force":{"type":"boolean","description":"When true, resend/requeue even if the inquiry already appears pushed.","default":false}},"required":["inquiry_token"]}}}}}},"/api/agents/v1/jobs/search":{"get":{"operationId":"job_search","summary":"Job search","description":"Search private job posting records by keyword, city, or company. Explicit AI Tinkerers index owners only.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term: job title, company, or keywords."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city."},{"name":"company","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by company name."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","archived","ended","all"],"default":"active"},"description":"Filter by status (default active)."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["updated_desc","updated_asc","created_desc","created_asc"],"default":"updated_desc"},"description":"Sort order."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."}]}},"/api/agents/v1/jobs/support_lookup":{"get":{"operationId":"job_ad_support_lookup","summary":"Job ad support lookup","description":"Read-only support lookup for job ads, including unpaid drafts, checkout state, buyer-facing edit/placement/checkout URLs, and published status. Explicit AI Tinkerers index owners can search all ads; other callers are limited to ads they purchased.","tags":["Jobs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"job_ad_support_lookup","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"job_ad_support_lookup","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term: ad token, job title, company, client email, location, or job copy."},{"name":"company","in":"query","required":false,"schema":{"type":"string"},"description":"Company name or domain."},{"name":"owner_email","in":"query","required":false,"schema":{"type":"string"},"description":"Known purchaser or requester email."},{"name":"email_domain","in":"query","required":false,"schema":{"type":"string"},"description":"Requester company email domain, such as getsunlight.org."},{"name":"ad_token","in":"query","required":false,"schema":{"type":"string"},"description":"Exact job ad token."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","unpaid","paid","published","ended","archived","all"],"default":"open"},"description":"Filter by support status."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["updated_desc","updated_asc","created_desc","created_asc"],"default":"updated_desc"},"description":"Sort order."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 100)."}]}},"/api/agents/v1/logos/search":{"get":{"operationId":"logo_search","summary":"Logo search","description":"Search for AI Tinkerers logos and brand assets. Supports smart matching and library browsing. Optionally include co-branded logos.","tags":["Logos"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"logo_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"logo_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term (e.g. city name, logo type)."},{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["smart_match","library"],"default":"smart_match"},"description":"Search scope."},{"name":"include_co_branded","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include co-branded logos (default false)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20},"description":"Max results (default 20, max 25)."}]}},"/api/agents/v1/mail_logs/recipient_search":{"get":{"operationId":"mail_log_recipient_search","summary":"Mail log recipient search","description":"Search outbound MailLog records sent by the AI Tinkerers platform to one recipient. Use before answering support questions to verify what system, registration, logistics, portal, credit/API access, message-board, or event emails the person actually received. Returns bounded body excerpts, links, delivery flags, and related event/page/job refs.","tags":["Mail Logs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"mail_log_recipient_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"mail_log_recipient_search","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string"},"description":"Recipient email address to search. Exact match against MailLog to_email and matching client records."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 50)."},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer","default":365},"description":"History window in days when date_from/date_to are omitted (default 365, max 1825)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Optional start date (YYYY-MM-DD). Overrides days_back when provided."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"Optional end date (YYYY-MM-DD). Overrides days_back when provided."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Optional keyword filter across subject, body text/html, key, and from address."},{"name":"key","in":"query","required":false,"schema":{"type":"string"},"description":"Optional MailLog key filter, such as content_page, meetup update, message-board notification, or registration email keys."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional filter to a specific content page."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional filter to a specific meetup/event."},{"name":"send_job_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional filter to a specific email send job."},{"name":"include_body_excerpt","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include a bounded text excerpt from the logged email body (default false)."},{"name":"body_excerpt_chars","in":"query","required":false,"schema":{"type":"integer","default":1500},"description":"Maximum characters for each body excerpt (default 1500, max 20000)."}]}},"/api/agents/v1/media/files/delete":{"post":{"operationId":"media_file_delete","summary":"Media file delete","description":"Permanently delete a media file and remove it from S3 storage. This action cannot be undone.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the file to delete."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/files/download":{"get":{"operationId":"media_file_download","summary":"Media file download","description":"Get a time-limited presigned URL for an accessible media file. The agent can download the bytes directly from this URL; it expires in 1 hour. Requires an API key with export scope when scopes are explicit.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_download","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_download","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the file to download."},{"name":"disposition","in":"query","required":false,"schema":{"type":"string","enum":["attachment","inline"],"default":"attachment"},"description":"Request browser download or inline playback."}]}},"/api/agents/v1/media/files/generate_transcript":{"post":{"operationId":"media_file_transcript_generate","summary":"Media file transcript generate","description":"Start transcript generation for an audio or video media file. This is the file-oriented equivalent of the web \"create transcript\" button. Processing is async; poll media_file_transcript_status. Index owners only. Daily cap: 50.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_transcript_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_transcript_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the audio/video file to transcribe."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/files/get":{"get":{"operationId":"media_file_get","summary":"Media file get","description":"Get metadata about an accessible media file, including filename, content type, size, uploader, folder, direct source URL when present, transcript availability, and a media_file_download recipe.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_get","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the file to get metadata for."}]}},"/api/agents/v1/media/files/move":{"post":{"operationId":"media_file_move","summary":"Media file move","description":"Move a media file to a different folder the caller can access, including across accessible AI Tinkerers weblogs. Omit folder_token to move to root level in the file's current weblog.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_move","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_move","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the file to move."},"folder_token":{"type":"string","description":"Token of the destination folder. Omit to move to root level."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/files/probe":{"get":{"operationId":"media_files_probe","summary":"Media files probe","description":"Generated from the Rails route api/agents#media_file_probe. No MCP input schema is currently registered for this route; parameters are derived from route metadata and known query parameters.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_probe","x-generated-from":"Rails routes"}},"/api/agents/v1/media/files/render":{"post":{"operationId":"media_file_render","summary":"Media file render","description":"Retrieve and render the full content of a text, markdown, or JSON file. Cannot be used for video, audio, or image files. Max 5 MB.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_render","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_render","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the text/markdown/JSON file to render."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/files/scale_down":{"post":{"operationId":"media_file_scale_down","summary":"Media file scale down","description":"Start async scaling down of a video file to reduce file size and resolution. Poll media_file_scale_down_status to check progress. Only works on video files.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_scale_down","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_scale_down","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the video file to scale down."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/files/scale_down_status":{"get":{"operationId":"media_file_scale_down_status","summary":"Media file scale down status","description":"Poll the status of a video scale-down operation. Returns processing/success/failed status. On success, includes the scaled file metadata.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_scale_down_status","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_scale_down_status","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the video file to check scale-down status for."}]}},"/api/agents/v1/media/files/search":{"get":{"operationId":"media_file_search","summary":"Media file search","description":"Search media files the authenticated user can access by filename, folder name, uploader name, or note. Community organizers can search their community library; attendees and speakers see only files in folders shared with them.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term to match against filename, folder name, uploader name, or file note. Case-insensitive partial match."},{"name":"content_type","in":"query","required":false,"schema":{"type":"string","enum":["video","audio","image","document"]},"description":"Filter by media type: \"video\", \"audio\", \"image\", or \"document\"."},{"name":"has_transcript","in":"query","required":false,"schema":{"type":"boolean"},"description":"Filter to files with (true) or without (false) a completed transcript."},{"name":"folder_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope search to a specific folder and all its subfolders."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope search to a specific chapter/weblog."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max results to return (1-100, default 20)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Zero-based result offset for pagination."}]}},"/api/agents/v1/media/files/transcript":{"get":{"operationId":"media_file_transcript_get","summary":"Media file transcript get","description":"Get the completed transcript for a media file. Returns both the parsed transcript JSON and cached plain transcript_text.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_transcript_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_transcript_get","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the audio/video file to get the transcript for."}]}},"/api/agents/v1/media/files/transcript_status":{"get":{"operationId":"media_file_transcript_status","summary":"Media file transcript status","description":"Poll transcript status for a media file. Returns processing/success/failed status, error details if failed, and attempt count.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_transcript_status","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_transcript_status","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the media file to check transcript status for."}]}},"/api/agents/v1/media/files/upload":{"post":{"operationId":"media_file_upload","summary":"Media file upload","description":"Upload a file to a folder. File content must be base64-encoded. Max 50 MB via API. Supported types: video, audio, images, text, markdown, JSON. Upload .txt or .md speaker/project notes into the same folder as the raw videos to provide AI speaker, title, and caption spelling hints. Use media_folder_search/list to find a folder and media_folder_info to inspect its reference files and context limits. Existing edited outputs require a new editing pass.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_file_upload","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_file_upload","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","description":"Filename including extension (e.g. \"data.json\", \"clip.mp4\")."},"content_type":{"type":"string","description":"MIME type (e.g. \"application/json\"). Auto-detected from extension if blank."},"folder_token":{"type":"string","description":"Token of the folder to upload into."},"body_base64":{"type":"string","description":"File content as a base64-encoded string."},"note":{"type":"string","description":"Optional sticky note for the file (max 2000 chars)."}},"required":["filename","folder_token","body_base64"]}}}}}},"/api/agents/v1/media/folders/create":{"post":{"operationId":"media_folder_create","summary":"Media folder create","description":"Create a new media folder. Provide a parent_token to create a subfolder inside an existing folder, or provide a weblog_token to create a root-level folder for that weblog.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_folder_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_folder_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name for the new folder."},"parent_token":{"type":"string","description":"Token of the parent folder to create a subfolder in. If provided, weblog is inherited from parent."},"weblog_token":{"type":"string","description":"Token of the weblog to create a root-level folder for. Required if parent_token is not provided."}},"required":["name"]}}}}}},"/api/agents/v1/media/folders/delete_empty":{"post":{"operationId":"media_folder_delete_empty","summary":"Media folder delete empty","description":"Permanently delete a media folder and all of its descendant folders only when the entire folder tree contains no media files. Returns a conflict without deleting anything if any file remains.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_folder_delete_empty","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_folder_delete_empty","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folder_token":{"type":"string","description":"Token of the empty folder tree to delete."}},"required":["folder_token"]}}}}}},"/api/agents/v1/media/folders/info":{"get":{"operationId":"media_folder_info","summary":"Media folder info","description":"Get detailed info about a folder including its associated meetup (event token, name, date), weblog, and AI reference text files. Returns context limits and, for authorized uploaders, a media_file_upload recipe for adding .txt/.md speaker hints.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_folder_info","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_folder_info","parameters":[{"name":"folder_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the folder."}]}},"/api/agents/v1/media/folders/list":{"get":{"operationId":"media_folder_list","summary":"Media folder list","description":"Browse accessible media folders and files. Omit folder_token to list access roots, or pass a folder token to navigate its readable children. Community organizers see their community library; attendees and speakers see only explicitly shared or otherwise authorized folder trees.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_folder_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_folder_list","parameters":[{"name":"folder_token","in":"query","required":false,"schema":{"type":"string"},"description":"Token of the folder to list contents of. Omit for accessible roots."},{"name":"folder_limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max child folders (1-200, default 200)."},{"name":"folder_offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Zero-based child-folder offset."},{"name":"file_limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max files (1-200, default 200)."},{"name":"file_offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Zero-based file offset."}]}},"/api/agents/v1/media/folders/search":{"get":{"operationId":"media_folder_search","summary":"Media folder search","description":"Search accessible media folders by folder name, folder note, or contained filename. Results are always filtered to folder trees the authenticated user can view.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_folder_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_folder_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Case-insensitive folder, note, or contained-filename search term."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optionally scope results to one accessible chapter/community."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max results to return (1-100, default 20)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Zero-based result offset for pagination."}]}},"/api/agents/v1/media/notes/update":{"post":{"operationId":"media_note_update","summary":"Media note update","description":"Update or clear the sticky note on a file or folder. Provide either file_token or folder_token (not both). Pass empty string for note to clear.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_note_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_note_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the file to update the note on."},"folder_token":{"type":"string","description":"Token of the folder to update the note on."},"note":{"type":"string","description":"New note text (max 2000 chars). Empty string clears the note."}},"required":["note"]}}}}}},"/api/agents/v1/media/transcripts/delete":{"post":{"operationId":"media_transcript_delete","summary":"Media transcript delete","description":"Delete transcript data for a media file while keeping the file itself. Clears transcript text, status, and URL. Cannot delete a transcript that is currently processing.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_transcript_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_transcript_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the media file whose transcript to delete."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/transcripts/generate":{"post":{"operationId":"media_transcript_generate","summary":"Media transcript generate","description":"Start transcript generation for an audio or video file. Uses AI-powered speech-to-text with speaker diarization. Processing takes 1-5 minutes. Poll media_transcript_status to check progress. Only index owners can generate transcripts. Daily cap: 50.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_transcript_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_transcript_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_token":{"type":"string","description":"Token of the audio/video file to transcribe."}},"required":["file_token"]}}}}}},"/api/agents/v1/media/transcripts/get":{"get":{"operationId":"media_transcript_get","summary":"Media transcript get","description":"Get the full transcript for an audio or video file. Returns speaker-diarized transcript with paragraphs, speaker labels, and timestamps. The file must have a completed transcript (check has_transcript field from media_file_get or media_folder_list).","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_transcript_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_transcript_get","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the audio/video file to get the transcript for."}]}},"/api/agents/v1/media/transcripts/search":{"get":{"operationId":"media_transcript_search","summary":"Media transcript search","description":"Search across all transcript text to find which videos or audio files mention a topic, person, or phrase. Returns matching files with a snippet of the transcript around the match. Only searches files that have a completed transcript.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_transcript_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_transcript_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Text to search for within transcripts. Case-insensitive partial match."},{"name":"content_type","in":"query","required":false,"schema":{"type":"string","enum":["video","audio"]},"description":"Filter by media type: \"video\" or \"audio\"."},{"name":"folder_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope search to a specific folder and all its subfolders."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Scope search to a specific chapter/weblog."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max results to return (1-100, default 20)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Zero-based result offset for pagination."}]}},"/api/agents/v1/media/transcripts/status":{"get":{"operationId":"media_transcript_status","summary":"Media transcript status","description":"Poll the status of a transcription operation. Returns processing/success/failed status, error details if failed, and attempt count.","tags":["Media"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"media_transcript_status","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"media_transcript_status","parameters":[{"name":"file_token","in":"query","required":true,"schema":{"type":"string"},"description":"Token of the media file to check transcript status for."}]}},"/api/agents/v1/meetups/attendee_requirements/get":{"get":{"operationId":"meetup_attendee_requirements_get","summary":"Meetup attendee requirements get","description":"Organizer-only list of RSVP states, all structured registration answers, and dietary requirements for one meetup.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_attendee_requirements_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_attendee_requirements_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"maximum":500}}]}},"/api/agents/v1/meetups/attendee_summary":{"get":{"operationId":"meetup_attendee_summary","summary":"Meetup attendee summary","description":"Get the composer-style summary of who is attending one managed private event: anonymized and named guest descriptions in bullet and paragraph form, plus the structured guest list. Requires invitation-manager access. Serves the cached copy; returns ready=false while the first copy is being generated.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_attendee_summary","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_attendee_summary","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"},"description":"Meetup token of the private event."},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["all","anonymous","named","anonymous_paragraph","named_paragraph"],"default":"all"},"description":"Which text variant to return. Defaults to all four."},{"name":"refresh","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Generate the summary synchronously instead of serving the cached copy. Defaults to false."}]}},"/api/agents/v1/meetups/capacity/get":{"get":{"operationId":"meetup_capacity_get","summary":"Meetup capacity get","description":"Get the configured maximum attendee count for one event, plus attending, remaining, and at/over-capacity status. A null max_attendees value means the event has no attendance limit.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_capacity_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_capacity_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"},"description":"Target meetup token."}]}},"/api/agents/v1/meetups/capacity/update":{"post":{"operationId":"meetup_capacity_update","summary":"Meetup capacity update","description":"Preview or deliberately set the maximum attendee count for one event. This is the only general event API operation that changes configured capacity. Never use it merely to make room for a dinner invitation; dinner invitation overage is tracked separately. Use a positive integer to set a limit, or null to make attendance unlimited. The first call is a dry run and confirm=true is required to apply the change. Existing RSVP states are not changed when the new maximum is below the current attending count.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_capacity_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_capacity_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Target meetup token."},"max_attendees":{"type":"integer","nullable":true,"minimum":1,"maximum":100000,"description":"Maximum attendees. Use null to remove the attendance limit."},"confirm":{"type":"boolean","default":false,"description":"Set true only to apply the reviewed capacity change."}},"required":["meetup_token","max_attendees"]}}}}}},"/api/agents/v1/meetups/clone":{"post":{"operationId":"meetup_clone","summary":"Meetup clone","description":"Preview or queue creation of a new event draft from an existing meetup. confirm=true is required. The API call itself does not send requester email.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_clone","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_clone","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"instructions":{"type":"string","description":"Describe the desired changes for the cloned draft."},"confirm":{"type":"boolean","default":false}},"required":["meetup_token","instructions"]}}}}}},"/api/agents/v1/meetups/discussion_topics/generate":{"post":{"operationId":"discussion_topics_generate","summary":"Discussion topics generate","description":"Generate moderated discussion topics for a meetup or dinner, including attendee-aligned expert picks.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"discussion_topics_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"discussion_topics_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Meetup token."}},"required":["meetup_token"]}}}}}},"/api/agents/v1/meetups/get":{"get":{"operationId":"meetup_get","summary":"Meetup get","description":"Get a role-aware operational snapshot for one meetup: settings, schedule, capacity, lifecycle, registration questions, tags, organizers, lineup, sponsors, and Luma status. Hidden venue data is redacted from reader roles.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"},"description":"Target meetup token."}]}},"/api/agents/v1/meetups/lifecycle/update":{"post":{"operationId":"meetup_lifecycle_update","summary":"Meetup lifecycle update","description":"Preview or apply publish, unpublish, or cancel. confirm=true is required. Preflight enforces event readiness and the Luma guardrail; existing RSVPs are preserved and no attendee email is sent.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_lifecycle_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_lifecycle_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"lifecycle_action":{"type":"string","enum":["publish","unpublish","cancel"]},"confirm":{"type":"boolean","default":false}},"required":["meetup_token","lifecycle_action"]}}}}}},"/api/agents/v1/meetups/lineup/get":{"get":{"operationId":"meetup_lineup_get","summary":"Meetup lineup get","description":"Get approved main-stage speakers in speaking order, including no-show state.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_lineup_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_lineup_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/lineup/no_show":{"post":{"operationId":"meetup_lineup_no_show","summary":"Meetup lineup no show","description":"Preview or record an approved speaker no-show after an event. confirm=true is required; reputation_ding=true applies the standard reputation penalty.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_lineup_no_show","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_lineup_no_show","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"rsvp_token":{"type":"string"},"reputation_ding":{"type":"boolean","default":false},"reason":{"type":"string"},"confirm":{"type":"boolean","default":false}},"required":["meetup_token","rsvp_token"]}}}}}},"/api/agents/v1/meetups/lineup/update":{"post":{"operationId":"meetup_lineup_update","summary":"Meetup lineup update","description":"Set the explicit speaking order for approved main-stage speaker RSVPs.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_lineup_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_lineup_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"rsvp_tokens":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":100}},"required":["meetup_token","rsvp_tokens"]}}}}}},"/api/agents/v1/meetups/luma/reconcile":{"post":{"operationId":"meetup_luma_reconcile","summary":"Meetup luma reconcile","description":"Preview Luma reconciliation readiness, or run the existing guarded guest reconciliation with confirm=true. The preview does not call Luma or mutate records.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_luma_reconcile","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_luma_reconcile","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"confirm":{"type":"boolean","default":false}},"required":["meetup_token"]}}}}}},"/api/agents/v1/meetups/luma/status":{"get":{"operationId":"meetup_luma_status_get","summary":"Meetup luma status get","description":"Get redacted Luma integration, connection, sync, and reconciliation readiness status without exposing credentials.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_luma_status_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_luma_status_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/organizers/get":{"get":{"operationId":"meetup_organizers_get","summary":"Meetup organizers get","description":"List organizers derived from page authorship, chapter/series roles, and event-specific organizer RSVP tags.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_organizers_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_organizers_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/organizers/update":{"post":{"operationId":"meetup_organizers_update","summary":"Meetup organizers update","description":"Add or remove event-specific organizer RSVP tags using client tokens. Added organizers must already have an RSVP. Structural chapter, series, and page-author roles are not removed.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_organizers_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_organizers_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"add_client_tokens":{"type":"array","items":{"type":"string"},"maxItems":50},"remove_client_tokens":{"type":"array","items":{"type":"string"},"maxItems":50}},"required":["meetup_token"]}}}}}},"/api/agents/v1/meetups/performance":{"get":{"operationId":"meetup_performance_get","summary":"Meetup performance get","description":"Return one aggregate row per meetup for a weblog and date range, with RSVP counts, page-view traffic, and completed-RSVP conversion. Does not expose raw analytics events or visitor details.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_performance_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_performance_get","parameters":[{"name":"weblog_token","in":"query","required":true,"schema":{"type":"string"},"description":"City chapter weblog token."},{"name":"date_from","in":"query","required":true,"schema":{"type":"string"},"description":"Event start date lower bound (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":true,"schema":{"type":"string"},"description":"Event start date upper bound (YYYY-MM-DD)."},{"name":"traffic_from","in":"query","required":false,"schema":{"type":"string"},"description":"Traffic window lower bound (YYYY-MM-DD or ISO 8601). Defaults to date_from."},{"name":"traffic_to","in":"query","required":false,"schema":{"type":"string"},"description":"Traffic window upper bound (YYYY-MM-DD or ISO 8601). Defaults to date_to."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max events to return (default 100, max 200)."}]}},"/api/agents/v1/meetups/registration_questions/get":{"get":{"operationId":"meetup_registration_questions_get","summary":"Meetup registration questions get","description":"Get all structured registration questions for one meetup.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_registration_questions_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_registration_questions_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/registration_questions/update":{"post":{"operationId":"meetup_registration_questions_update","summary":"Meetup registration questions update","description":"Replace all structured registration questions for one meetup. Question ids are preserved when supplied; an empty array removes all questions.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_registration_questions_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_registration_questions_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"questions":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"response_type":{"type":"string"},"options":{"type":"array","items":{"type":"string"}},"other_option":{"type":"object"},"required":{"type":"boolean"},"default_checked":{"type":"boolean"}},"required":["title","response_type"]}}},"required":["meetup_token","questions"]}}}}}},"/api/agents/v1/meetups/schedule/update":{"post":{"operationId":"meetup_schedule_update","summary":"Meetup schedule update","description":"Preview or apply event time, named timezone, venue visibility, and directions changes. Defaults to a dry run; confirm=true applies the update. This endpoint never sends attendee email.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_schedule_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_schedule_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"starts_at":{"type":"string","description":"ISO 8601 timestamp with explicit offset."},"ends_at":{"type":"string","nullable":true,"description":"ISO 8601 timestamp with explicit offset, or null."},"timezone":{"type":"string","description":"Named IANA timezone for this event, such as America/New_York."},"location":{"type":"string","nullable":true},"hide_location":{"type":"boolean"},"directions_mode":{"type":"string","enum":["inferred","custom","hidden"]},"custom_directions":{"type":"string","nullable":true},"confirm":{"type":"boolean","default":false}},"required":["meetup_token"]}}}}}},"/api/agents/v1/meetups/search":{"get":{"operationId":"meetup_search","summary":"Meetup search","description":"Search AI Tinkerers events worldwide, including meetups, VIP dinners, and hackathons. Every eligible Agent API key can search the public catalog by city, region, local event-date range, upcoming/past status, and event type. Public rows intentionally omit organizer emails, RSVP/capacity counts, payment configuration, drafts, unlisted/disabled events, and hidden venues. City and index roles retain operational fields only for events already in their management scope.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search across meetup titles and locations."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 200)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Number of results to skip for pagination (default 0)."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter."},{"name":"meetup_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to specific meetups by token."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["upcoming","future","past","completed"]},"description":"Filter: upcoming/future or past/completed."},{"name":"event_type","in":"query","required":false,"schema":{"type":"string","enum":["dinner","hackathon","meetup"]},"description":"Filter by event type: dinner (VIP dinners), hackathon, or meetup (regular meetups)."}]}},"/api/agents/v1/meetups/settings/update":{"post":{"operationId":"meetup_settings_update","summary":"Meetup settings update","description":"Partially update allowlisted organizer settings such as screening, waitlist, reminders, data collection, speaker submissions, display options, and Stripe promotion-code availability. Updating stripe_promotion_codes_enabled also synchronizes the configured Stripe Payment Link and returns the sync result. Payment credentials, schedule, venue, and capacity are deliberately excluded.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_settings_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_settings_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string","description":"Optional optimistic-concurrency timestamp from meetup_get."},"settings":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["open","manual_screen","auto_screen","no_screen"]},"wait_list":{"type":"boolean"},"reminders_mode":{"type":"string","enum":["all","none"]},"ask_for_name":{"type":"boolean"},"ask_for_company_name":{"type":"boolean"},"ask_for_job_title":{"type":"boolean"},"ask_for_phone_number":{"type":"boolean"},"ask_for_identifier_required":{"type":"boolean"},"ask_for_identifier_optional":{"type":"boolean"},"ask_for_dietary_restrictions":{"type":"boolean"},"setting_show_counter":{"type":"boolean"},"setting_show_social_proof":{"type":"boolean"},"setting_show_contact_form":{"type":"boolean"},"setting_move_terms_above_register_button":{"type":"boolean"},"setting_show_speaker_proposals":{"type":"boolean"},"setting_show_speaker_proposals_max":{"type":"integer","nullable":true},"invite_only_presentation_mode":{"type":"boolean"},"setting_enable_hackathon":{"type":"boolean"},"setting_enable_science_fair":{"type":"boolean"},"stripe_promotion_codes_enabled":{"type":"boolean","description":"Enable or disable Stripe discount and VIP codes for this paid event. The community Stripe Discount Codes setting must be enabled first."},"display_accurate_counts":{"type":"boolean"},"attendance_display_mode":{"type":"string"},"event_type":{"type":"string"},"speaker_form_title":{"type":"string","nullable":true},"speaker_form_description":{"type":"string","nullable":true},"info_required":{"type":"string"},"also_ask_for_aws_required_fields":{"type":"boolean"},"allow_sponsor_email_sharing_opt_out":{"type":"boolean"},"sponsor_contact_sharing_consent_text":{"type":"string","nullable":true},"sponsor_contact_sharing_privacy_policy_url":{"type":"string","nullable":true},"auto_screen_min_score":{"type":"integer"},"loyalty_fast_lane_enabled":{"type":"boolean"},"low_score_screening_enabled":{"type":"boolean","description":"Move decisively low-scoring, sufficiently complete pending applications to waitlist after the review grace period."},"speaker_proposal_copy":{"type":"object"}}}},"required":["meetup_token","settings"]}}}}}},"/api/agents/v1/meetups/sponsors/get":{"get":{"operationId":"meetup_sponsors_get","summary":"Meetup sponsors get","description":"Get normalized event sponsors, venue hosts, co-organizers, and community partners.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_sponsors_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_sponsors_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/sponsors/update":{"post":{"operationId":"meetup_sponsors_update","summary":"Meetup sponsors update","description":"Replace normalized sponsors and partners for an event, including role, tier, logo, website, visibility, and display order.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_sponsors_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_sponsors_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"entities":{"type":"array","maxItems":24,"items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"website_url":{"type":"string"},"logo_url":{"type":"string"},"roles":{"type":"array","items":{"type":"string","enum":["sponsor","venue","co_organizer","community_partner"]}},"sponsor_tier":{"type":"string","enum":["standard","marquee"]},"visibility":{"type":"string","enum":["active","suppressed"]}},"required":["name","roles"]}}},"required":["meetup_token","entities"]}}}}}},"/api/agents/v1/meetups/survey_diagnostic":{"get":{"operationId":"meetup_survey_diagnostic_get","summary":"Meetup survey diagnostic get","description":"Inspect post-meetup survey state for one meetup, including scheduler eligibility gates, survey presence/open state, settings, attendee counts, and survey email counts. Authorized for blog owners on their own blogs and AI Tinkerers index owners on any blog.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_survey_diagnostic_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_survey_diagnostic_get","parameters":[{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Meetup token to inspect."},{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional content page token alternative to meetup_token."}]}},"/api/agents/v1/meetups/survey_report":{"get":{"operationId":"meetup_survey_report","summary":"Meetup survey report","description":"Report post-meetup survey coverage for completed enabled/live meetups in a lookback window. Defaults to rows where post_meetup_survey is enabled. Authorized for blog owners on their own blogs and AI Tinkerers index owners on any blog.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_survey_report","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_survey_report","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":90},"description":"Lookback window in days (default 90, max 365)."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional weblog token to scope the report."},{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Optional domain lookup alternative to weblog_token."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city lookup alternative to weblog_token."},{"name":"include_rows","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include per-meetup rows (default true)."},{"name":"include_all_completed","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include completed meetups even when post_meetup_survey is disabled (default false)."},{"name":"only_missing","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only include rows expected to send but missing attendee survey emails (default false)."}]}},"/api/agents/v1/meetups/tags/get":{"get":{"operationId":"meetup_tags_get","summary":"Meetup tags get","description":"Get event classification tag names.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_tags_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_tags_get","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/agents/v1/meetups/tags/update":{"post":{"operationId":"meetup_tags_update","summary":"Meetup tags update","description":"Replace event classification tags. An empty array removes all event tags.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_tags_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_tags_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"expected_updated_at":{"type":"string"},"tag_names":{"type":"array","items":{"type":"string"},"maxItems":20}},"required":["meetup_token","tag_names"]}}}}}},"/api/agents/v1/meetups/time_series":{"get":{"operationId":"meetup_time_series_get","summary":"Meetup time series get","description":"Get meetup event count time series for a city chapter. Shows number of events over time with configurable buckets.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"meetup_time_series_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"meetup_time_series_get","parameters":[{"name":"weblog_token","in":"query","required":true,"schema":{"type":"string"},"description":"City chapter weblog token (required)."},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["day","week","month"]},"description":"Time bucket size."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/meetups/upcoming":{"get":{"operationId":"upcoming_events_list","summary":"Upcoming events list","description":"List the worldwide public catalog of upcoming AI Tinkerers events sorted by date. Every eligible Agent API key can call this endpoint. Follow next_offset until it is null to traverse all future events. Public rows intentionally omit organizer emails, RSVP/capacity counts, payment configuration, drafts, unlisted/disabled events, and hidden venues.","tags":["Meetups"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"upcoming_events_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"upcoming_events_list","parameters":[{"name":"event_type","in":"query","required":false,"schema":{"type":"string","enum":["dinner","hackathon","meetup","all"],"default":"all"},"description":"Filter by event type."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results per page (default 25, max 100)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Number of results to skip. Start at 0 and follow next_offset until null."}]}},"/api/agents/v1/message_boards/attachments/upload":{"post":{"operationId":"message_board_attachment_upload","summary":"Message board attachment upload","description":"Upload an image from a public URL for later attachment to a message board post. Returns an attachment token. Animated GIFs from admin or index-owner callers are validated and rehosted on R2 without transcoding.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_attachment_upload","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_attachment_upload","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key (required)."},"image_url":{"type":"string","description":"Public URL of the image to upload (max 2048 chars). Privileged animated GIFs must be at most 5 MB, 1600 x 1600, 240 frames, 40 million aggregate frame-pixels, and 30 seconds per cycle."}},"required":["board_key","image_url"]}}}}}},"/api/agents/v1/message_boards/direct_messages/post":{"post":{"operationId":"direct_message_post_create","summary":"Direct message post create","description":"Create or reuse a normal non-support direct-message conversation with existing clients, then post one message. Use this for direct-HQ tasks like \"DM Diego\" or \"message this member\"; do not search for and post into old support cases. The caller is automatically included as a DM participant. Set post_as_ashley only for approved Ashley Email EA direct tasks where Ashley should author the message on behalf of the caller.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"direct_message_post_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"direct_message_post_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_refs":{"type":"array","items":{"type":"string"},"description":"Existing client tokens or email addresses to include in the normal DM. The API caller is included automatically."},"emails":{"type":"array","items":{"type":"string"},"description":"Existing client email addresses to include in the normal DM."},"content":{"type":"string","description":"DM body text (required, max 10000 chars). Use only the message content; do not include email-style greetings, closings, or signatures."},"post_as_ashley":{"type":"boolean","description":"When true, author the post as Ashley while keeping the API caller as a DM participant. Allowed only for Ashley Email EA direct-task admins.","default":false}},"required":["content"]}}}}}},"/api/agents/v1/message_boards/members/add":{"post":{"operationId":"message_board_members_add","summary":"Message board members add","description":"Add existing clients to a Message Center board so they can participate in the thread. Use this before replying when a support-case Message Center post needs an organizer, Joe, Jake, or another owner looped into the same Message Center conversation instead of moving to email.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_members_add","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_members_add","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key to update (required)."},"client_refs":{"type":"array","items":{"type":"string"},"description":"Existing client tokens or email addresses to add."},"emails":{"type":"array","items":{"type":"string"},"description":"Existing client email addresses to add."},"role":{"type":"string","enum":["member","watcher"],"description":"Membership role to apply to newly added clients. Default member.","default":"member"},"reason":{"type":"string","description":"Brief audit reason for adding these people (required)."}},"required":["board_key","reason"]}}}}}},"/api/agents/v1/message_boards/messages/list":{"get":{"operationId":"message_board_messages_list","summary":"Message board messages list","description":"List messages/posts from a specific message board. Filter by date, search text, mentions, or posts needing response.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_messages_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_messages_list","parameters":[{"name":"board_key","in":"query","required":true,"schema":{"type":"string"},"description":"Board token or identifier (required)."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search within messages."},{"name":"before_post_token","in":"query","required":false,"schema":{"type":"string"},"description":"Pagination cursor: get messages before this post."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."},{"name":"mentioned_me","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only messages mentioning me (default false)."},{"name":"needs_response","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only messages needing a response (default false)."},{"name":"include_thread","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include threaded replies (default false)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Max messages (default 30, max 50)."},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Only messages from last N days (default 30, max 90)."}]}},"/api/agents/v1/message_boards/posts/create":{"post":{"operationId":"message_board_post_create","summary":"Message board post create","description":"Create a new post or reply on a message board. Caller must be a member of the board, except ashley-email-ea-v2 may reply on support-case boards involving Joe/Jake. Ashley Email EA writes must always be replies and include reply_to_post_token; that role cannot create root posts. Write normal message-board content only: no opening email salutation, no Thanks/Best close, and no Ashley or AI Assistant signature. Optionally attach images by URL. Animated GIFs from admin or index-owner callers are validated and rehosted on R2 without transcoding. For topic-type boards (e.g. Hot Topics), include a title for the post.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_post_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_post_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key to post to (required)."},"title":{"type":"string","description":"Post title (max 300 chars). Required for topic-type boards (e.g. topic_hot_topics). Ignored for replies."},"content":{"type":"string","description":"Post body text content (required, max 10000 chars). Use only the message content; do not include email-style greetings, closings, or signatures."},"reply_to_post_token":{"type":"string","description":"Token of an existing post to reply to. Required for every Ashley Email EA Message Center write; optional for other callers."},"image_urls":{"type":"array","items":{"type":"string"},"description":"Public image URLs to attach to the post (max 4). For admin and index-owner callers, animated GIFs are preserved on R2 when they are at most 5 MB, 1600 x 1600, 240 frames, 40 million aggregate frame-pixels, and 30 seconds per cycle."}},"required":["board_key","content"]}}}}}},"/api/agents/v1/message_boards/posts/delete":{"post":{"operationId":"message_board_post_delete","summary":"Message board post delete","description":"Delete one of the caller's own message board posts. This is self-service deletion, not moderation; it cannot hide, archive, or delete posts by other people.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_post_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_post_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key containing the post (required)."},"post_token":{"type":"string","description":"Token of the caller's own post to delete (required)."}},"required":["board_key","post_token"]}}}}}},"/api/agents/v1/message_boards/posts/reach":{"get":{"operationId":"message_board_posts_reach","summary":"Message board posts reach","description":"For each given post_token, returns reach (distinct viewers via PostView), eligible audience (board member count), reach_ratio, and reaction count. Use to measure how far a message actually propagated.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_posts_reach","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_posts_reach","parameters":[{"name":"post_tokens","in":"query","required":true,"schema":{"type":"array","items":{"type":"string"}},"description":"Post tokens to measure (required, max 200)."}]}},"/api/agents/v1/message_boards/posts/search":{"get":{"operationId":"message_board_post_search","summary":"Message board post search","description":"Search across all message board posts. Filter by board, date, mentions, or posts needing response.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_post_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_post_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term."},{"name":"board_key","in":"query","required":false,"schema":{"type":"string"},"description":"Limit to a specific board."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."},{"name":"mentioned_me","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only posts mentioning me (default false)."},{"name":"needs_response","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only posts needing a response (default false)."},{"name":"include_thread","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include threaded replies (default true)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 25)."},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"Only posts from last N days (default 30, max 90)."}]}},"/api/agents/v1/message_boards/posts/update":{"post":{"operationId":"message_board_post_update","summary":"Message board post update","description":"Edit the text content of an existing message board post. Caller must be the post owner (within 30 minutes of creation) or a board moderator (no time limit). Clears any stored lexical_content and sets edited_at.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_post_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_post_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key containing the post (required)."},"post_token":{"type":"string","description":"Token of the post to edit (required)."},"content":{"type":"string","description":"Replacement post body text (required, max 10000 chars)."}},"required":["board_key","post_token","content"]}}}}}},"/api/agents/v1/message_boards/private_groups/create":{"post":{"operationId":"message_board_private_group_create","summary":"Message board private group create","description":"Create a named, invite-only Message Center private group. Restricted to explicit AI Tinkerers index owners; admin or city-organizer status alone is not sufficient. The caller becomes the owner. Optional client_refs and emails add existing AI Tinkerers clients as members. This operation does not create client accounts or send invitation emails.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_private_group_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_private_group_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Private group name (required, max 120 characters)."},"client_refs":{"type":"array","items":{"type":"string"},"description":"Existing client tokens or email addresses to add (max 20)."},"emails":{"type":"array","items":{"type":"string"},"description":"Existing client email addresses to add (max 20)."},"reason":{"type":"string","description":"Optional brief audit reason for creating the group (max 500 characters)."}},"required":["title"]}}}}}},"/api/agents/v1/message_boards/reactions/toggle":{"post":{"operationId":"message_board_reaction_toggle","summary":"Message board reaction toggle","description":"Toggle an emoji reaction on a message board post. If the reaction already exists from the caller, it is removed; otherwise it is added.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_reaction_toggle","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_reaction_toggle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_key":{"type":"string","description":"Board key containing the post."},"post_token":{"type":"string","description":"Token of the post to react to."},"reaction_type":{"type":"string","description":"Reaction type. One of: thumbs_up, thumbs_down, love, haha, fire, 100, trophy, pizza, rocket, robot, rainbow, salute, gen_ai."}},"required":["board_key","post_token","reaction_type"]}}}}}},"/api/agents/v1/message_boards/search":{"get":{"operationId":"message_board_search","summary":"Message board search","description":"Search message boards by name or topic. Optionally include direct messages and unread boards.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search term."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 50)."},{"name":"include_direct_messages","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include DM boards (default true)."},{"name":"include_unread","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only boards with unread messages (default false)."}]}},"/api/agents/v1/message_boards/threads/get":{"get":{"operationId":"message_board_thread_get","summary":"Message board thread get","description":"Fetch one message-board thread by message_center URL or by board_key plus post_token. Expands from the matched post to the thread root and returns visible replies in order.","tags":["Message Boards"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"message_board_thread_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"message_board_thread_get","parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string"},"description":"A /message_center URL containing board/topic and post parameters or a #board:post fragment."},{"name":"board_key","in":"query","required":false,"schema":{"type":"string"},"description":"Board key containing the post. Optional when url is provided or post_token is globally resolvable within caller-accessible boards."},{"name":"post_token","in":"query","required":false,"schema":{"type":"string"},"description":"Matched post token. Optional when url contains post= or #board:post."},{"name":"thread_limit","in":"query","required":false,"schema":{"type":"integer","default":200},"description":"Max posts to return from the thread (default 200, max 500)."},{"name":"content_limit","in":"query","required":false,"schema":{"type":"integer","default":8000},"description":"Max characters per post body (default 8000, max 20000)."},{"name":"include_attachments","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include ready image attachments (default true)."},{"name":"include_reactions","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include reaction counts by type (default true)."}]}},"/api/agents/v1/newsletters/eligible_demos/list":{"get":{"operationId":"newsletter_eligible_demos_list","summary":"Newsletter eligible demos list","description":"List all eligible demos in the selection window for a draft Community Spotlights newsletter edition. Returns full scoring, audience ratings, city manager nominations, technology tags, speaker scores, and selection status for each demo. Designed for agent-driven selection workflows. Index owners only.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_eligible_demos_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_eligible_demos_list","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Draft newsletter edition content page token."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier."}]}},"/api/agents/v1/newsletters/notifications/send":{"post":{"operationId":"newsletter_notifications_send","summary":"Newsletter notifications send","description":"Send feature notification emails to selected demos that have not yet been notified. Optionally target specific demos by rsvp_tokens, or omit to send all pending. Returns per-demo send status. Index owners only.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_notifications_send","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_notifications_send","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Draft newsletter edition content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"rsvp_tokens":{"type":"array","items":{"type":"string"},"description":"Optional: specific RSVP tokens to notify. If omitted, sends to all selected demos not yet notified."}}}}}}}},"/api/agents/v1/newsletters/selected_demos/description/update":{"post":{"operationId":"newsletter_selected_demo_description_update","summary":"Newsletter selected demo description update","description":"Update or clear the newsletter blurb override for one selected demo in a draft Post-Training Community Spotlights edition. Requires the AI Tinkerers index-owner role and an Agent API key with write scope. City owners and organizers cannot call this. Use newsletter_selected_demos_get first and pass its newsletter_description.sha256 as expected_current_sha256.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_selected_demo_description_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_selected_demo_description_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Draft newsletter edition content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"rsvp_token":{"type":"string","description":"RSVP token of a demo already selected in the newsletter edition."},"newsletter_blurb_override":{"type":"string","description":"Replacement newsletter description, maximum 5,000 characters."},"expected_current_sha256":{"type":"string","description":"SHA-256 returned as newsletter_description.sha256 by newsletter_selected_demos_get. Prevents overwriting a newer edit."},"clear":{"type":"boolean","description":"Clear the manual override and fall back to the cached generated description. Defaults false."}},"required":["rsvp_token","expected_current_sha256"]}}}}}},"/api/agents/v1/newsletters/selected_demos/deselect":{"post":{"operationId":"newsletter_demos_deselect","summary":"Newsletter demos deselect","description":"Remove one or more demos from a draft Community Spotlights newsletter edition. Refuses to deselect demos whose speakers have already been notified unless force: true is passed. Index owners only.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_demos_deselect","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_demos_deselect","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Draft newsletter edition content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"rsvp_tokens":{"type":"array","items":{"type":"string"},"description":"RSVP tokens of demos to deselect."},"force":{"type":"boolean","description":"Set to true to force deselection of notified demos (strongly discouraged). Default false."}},"required":["rsvp_tokens"]}}}}}},"/api/agents/v1/newsletters/selected_demos/get":{"get":{"operationId":"newsletter_selected_demos_get","summary":"Newsletter selected demos get","description":"Get the demos currently selected for a draft Post-Training Community Spotlights newsletter edition, including featured count and rank order.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_selected_demos_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_selected_demos_get","parameters":[{"name":"content_page_token","in":"query","required":false,"schema":{"type":"string"},"description":"Draft newsletter edition content page token."},{"name":"slug","in":"query","required":false,"schema":{"type":"string"},"description":"Optional fallback slug identifier within visible draft Community Spotlights scope."}]}},"/api/agents/v1/newsletters/selected_demos/ranks/update":{"post":{"operationId":"newsletter_selected_demo_ranks_update","summary":"Newsletter selected demo ranks update","description":"Update only the rank order for demos already selected in a draft Post-Training Community Spotlights newsletter edition. Only index owners and admins can call this.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_selected_demo_ranks_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_selected_demo_ranks_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Draft newsletter edition content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"ranked_rsvp_tokens":{"type":"array","items":{"type":"string"},"description":"Ordered RSVP tokens for selected demos that should receive ranks 1..N."}},"required":["ranked_rsvp_tokens"]}}}}}},"/api/agents/v1/newsletters/selected_demos/select":{"post":{"operationId":"newsletter_demos_select","summary":"Newsletter demos select","description":"Select one or more demos to feature in a draft Community Spotlights newsletter edition. Idempotent: selecting an already-selected demo is a no-op. Index owners only.","tags":["Newsletters"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_demos_select","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_demos_select","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_page_token":{"type":"string","description":"Draft newsletter edition content page token."},"slug":{"type":"string","description":"Optional fallback slug identifier."},"rsvp_tokens":{"type":"array","items":{"type":"string"},"description":"RSVP tokens of demos to select for the newsletter."}},"required":["rsvp_tokens"]}}}}}},"/api/agents/v1/people/private_notes":{"get":{"operationId":"people_private_notes","summary":"People private notes","description":"Generated from the Rails route api/agents#personal_notes_list. No MCP input schema is currently registered for this route; parameters are derived from route metadata and known query parameters.","tags":["People"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"personal_notes_list","x-generated-from":"Rails routes"}},"/api/agents/v1/people/private_notes/create":{"post":{"operationId":"personal_note_create","summary":"Personal note create","description":"Store a private conversation note about a person as the authenticated API user. Never shared with the subject or other organizers; sends no notifications. Reuse idempotency_key on retries.","tags":["People"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"personal_note_create","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"personal_note_create","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"client_token":{"type":"string"},"email":{"type":"string"},"content":{"type":"string","maxLength":2000},"idempotency_key":{"type":"string","maxLength":200}},"required":["content"],"oneOf":[{"required":["client_token"]},{"required":["email"]}]}}}}}},"/api/agents/v1/people/private_notes/delete":{"post":{"operationId":"personal_note_delete","summary":"Personal note delete","description":"Soft-delete one of the authenticated user's own private notes. Requires the person selector and note token.","tags":["People"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"personal_note_delete","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"personal_note_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"client_token":{"type":"string"},"email":{"type":"string"},"note_token":{"type":"string"}},"required":["note_token"],"oneOf":[{"required":["client_token"]},{"required":["email"]}]}}}}}},"/api/agents/v1/people/private_notes/list":{"post":{"operationId":"personal_notes_list","summary":"Personal notes list","description":"Fetch only the authenticated user's private conversation notes about one person. Never returns another user's notes.","tags":["People"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"personal_notes_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"personal_notes_list","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"client_token":{"type":"string"},"email":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":50},"offset":{"type":"integer","minimum":0,"default":0}},"required":[],"oneOf":[{"required":["client_token"]},{"required":["email"]}]}}}}}},"/api/agents/v1/people/private_notes/update":{"post":{"operationId":"personal_note_update","summary":"Personal note update","description":"Edit one of the authenticated user's own private notes. Requires the person selector and note token.","tags":["People"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"personal_note_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"personal_note_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"client_token":{"type":"string"},"email":{"type":"string"},"content":{"type":"string","maxLength":2000},"note_token":{"type":"string"}},"required":["content","note_token"],"oneOf":[{"required":["client_token"]},{"required":["email"]}]}}}}}},"/api/agents/v1/photos/search":{"get":{"operationId":"photo_search","summary":"Photo search","description":"Search event photos. Filter by city, meetup, quality, scene content (women present, people facing forward, etc.), and date. Supports sorting by recent, oldest, quality, or women_facing_forward.","tags":["Photos"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"photo_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"photo_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 100)."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific meetup."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["recent","oldest","quality","women_facing_forward"],"default":"recent"},"description":"Sort order."},{"name":"is_high_quality","in":"query","required":false,"schema":{"type":"boolean"},"description":"Only high-quality photos."},{"name":"women_present","in":"query","required":false,"schema":{"type":"boolean"},"description":"Photos with women present."},{"name":"people_facing_forward","in":"query","required":false,"schema":{"type":"boolean"},"description":"Photos with people facing forward."},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer"},"description":"Only photos from the last N days (1-3650)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD)."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."},{"name":"scene_tags_any","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter by scene tags (e.g. presentation, networking, group_photo)."}]}},"/api/agents/v1/promo_banners/create_job":{"post":{"operationId":"promo_banners_create_job","summary":"Promo banners create job","description":"Create an async promo banner generation job for one authorized event. Generated banners are persisted as PromoBanner records and appear in the existing banner UI when complete.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_create_job","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_create_job","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Global hackathon slug identifier."},"hackathon_token":{"type":"string","description":"Hackathon token to resolve one event/city."},"meetup_token":{"type":"string","description":"Meetup token to resolve one event/city."},"city":{"type":"string","description":"City name filter when using hackathon_slug."},"banner_type":{"type":"string","description":"Generation path.","enum":["agentic","integrated_text","prompted"],"default":"agentic"},"theme":{"type":"string","description":"Style or visual direction."},"subject":{"type":"string","description":"Primary subject/action for the banner."},"line_1":{"type":"string","description":"Primary rendered banner text."},"line_2":{"type":"string","description":"Secondary rendered banner text."},"line_3":{"type":"string","description":"Tertiary rendered banner text."},"include_blog_logo":{"type":"boolean","description":"Include the community brand logo. Forced true for AI Tinkerers city blogs.","default":true},"logo_inputs":{"type":"array","description":"Up to five logo inputs for agentic/Nano Banana generation. HTTPS image URLs only.","items":{"type":"object","properties":{"label":{"type":"string","description":"Logo label, e.g. sponsor or community name."},"role":{"type":"string","description":"Logo role.","enum":["brand","sponsor"],"default":"sponsor"},"url":{"type":"string","description":"HTTPS logo image URL."}},"required":["url"]}},"options":{"type":"object","description":"Optional generation settings.","properties":{"width":{"type":"integer","description":"Output width, clamped 320-2048."},"height":{"type":"integer","description":"Output height, clamped 320-2048."},"model":{"type":"string","description":"Optional model/version override for supported generation paths."}}},"idempotency_key":{"type":"string","description":"Optional caller-provided idempotency key."}}}}}}}},"/api/agents/v1/promo_banners/get":{"post":{"operationId":"promo_banners_get","summary":"Promo banners get","description":"Get official promo banner image URLs for hackathon recap content. Resolves by global hackathon slug, hackathon token, meetup token, and/or city.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_get","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Global hackathon slug identifier."},"hackathon_token":{"type":"string","description":"Hackathon token to filter to one event/city."},"meetup_token":{"type":"string","description":"Meetup token to filter to one event/city."},"city":{"type":"string","description":"City name filter when using hackathon_slug."},"include_jobs":{"type":"boolean","description":"Include recent banner generation jobs for the matching event(s).","default":false},"limit":{"type":"integer","description":"Max banner rows (default 20, max 100).","default":20}}}}}}}},"/api/agents/v1/promo_banners/jobs/get":{"post":{"operationId":"promo_banners_job_get","summary":"Promo banners job get","description":"Get the status and result of a promo banner generation job.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_job_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_job_get","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_token":{"type":"string","description":"Promo banner generation job token."}},"required":["job_token"]}}}}}},"/api/agents/v1/promo_banners/jobs/list":{"post":{"operationId":"promo_banners_jobs_list","summary":"Promo banners jobs list","description":"List promo banner generation jobs, optionally scoped to one event and/or the current caller.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_jobs_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_jobs_list","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Global hackathon slug identifier."},"hackathon_token":{"type":"string","description":"Hackathon token to resolve one event/city."},"meetup_token":{"type":"string","description":"Meetup token to resolve one event/city."},"city":{"type":"string","description":"City name filter when using hackathon_slug."},"state":{"type":"string","description":"State filter.","enum":["pending","queued","running","succeeded","failed","cancelled","lost","active","all"]},"mine":{"type":"boolean","description":"Only include jobs created by this API key owner.","default":false},"limit":{"type":"integer","description":"Max jobs (default 20, max 100).","default":20}}}}}}}},"/api/agents/v1/promo_banners/list":{"post":{"operationId":"promo_banners_list","summary":"Promo banners list","description":"List official promo banner image URLs and optionally recent generation jobs. Alias-friendly successor to promo_banners_get.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_list","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Global hackathon slug identifier."},"hackathon_token":{"type":"string","description":"Hackathon token to filter to one event/city."},"meetup_token":{"type":"string","description":"Meetup token to filter to one event/city."},"city":{"type":"string","description":"City name filter when using hackathon_slug."},"include_jobs":{"type":"boolean","description":"Include recent banner generation jobs for the matching event(s).","default":false},"limit":{"type":"integer","description":"Max banner rows/jobs (default 20, max 100).","default":20}}}}}}}},"/api/agents/v1/promo_banners/logo_inputs":{"post":{"operationId":"promo_banners_logo_inputs","summary":"Promo banners logo inputs","description":"Return brand logo and sponsor logo inputs that can be passed into promo_banners_create_job for one resolved event.","tags":["Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"promo_banners_logo_inputs","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"promo_banners_logo_inputs","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hackathon_slug":{"type":"string","description":"Global hackathon slug identifier."},"hackathon_token":{"type":"string","description":"Hackathon token to resolve one event/city."},"meetup_token":{"type":"string","description":"Meetup token to resolve one event/city."},"city":{"type":"string","description":"City name filter when using hackathon_slug."}}}}}}}},"/api/agents/v1/rag_chunks/get":{"get":{"operationId":"rag_chunks_get","summary":"Rag chunks get","description":"Get specific RAG chunks by ID or by object type+token. Use chunk_ids for known chunks, or object_type+object_token to get all chunks for an object.","tags":["RAG Chunks"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rag_chunks_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rag_chunks_get","parameters":[{"name":"chunk_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Specific chunk IDs to retrieve (max 25)."},{"name":"object_type","in":"query","required":false,"schema":{"type":"string"},"description":"Object type (e.g. client, rsvp, meetup)."},{"name":"object_token","in":"query","required":false,"schema":{"type":"string"},"description":"Object token."},{"name":"include_embeddings","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include embedding vectors (default false)."}]}},"/api/agents/v1/rag_chunks/search":{"get":{"operationId":"rag_chunk_search","summary":"Rag chunk search","description":"Semantic vector search across RAG chunks (people, RSVPs, meetups, subscribers, sponsors). Uses embeddings to find the most relevant content for a natural language query.","tags":["RAG Chunks"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rag_chunk_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rag_chunk_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Natural language search query (max 400 chars)."},{"name":"top_k","in":"query","required":false,"schema":{"type":"integer","default":10},"description":"Number of results (default 10, max 25)."},{"name":"min_score","in":"query","required":false,"schema":{"type":"number"},"description":"Minimum similarity score threshold."},{"name":"include_payload","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Include chunk payload content (default true)."},{"name":"object_types","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter by object type. Options: client, rsvp, meetup, subscriber, sponsor."},{"name":"object_refs","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to specific object tokens (max 25)."}]}},"/api/agents/v1/recommendations/newsletter/spotlights":{"get":{"operationId":"newsletter_spotlight_candidates_get","summary":"Newsletter spotlight candidates get","description":"Get AI-recommended candidates for newsletter spotlight features. Returns people who have interesting recent activity worth highlighting.","tags":["Recommendations"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"newsletter_spotlight_candidates_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"newsletter_spotlight_candidates_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max candidates to return."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter."}]}},"/api/agents/v1/recommendations/speakers/pipeline":{"get":{"operationId":"speaker_pipeline_candidates_get","summary":"Speaker pipeline candidates get","description":"Get AI-recommended speaker pipeline candidates. Returns people who show potential as future speakers based on their engagement and background.","tags":["Recommendations"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_pipeline_candidates_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_pipeline_candidates_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Max candidates to return."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter."}]}},"/api/agents/v1/restricted_content/brand_scrub/analyze":{"post":{"operationId":"restricted_content_brand_scrub_analyze","summary":"Restricted content brand scrub analyze","description":"Analyze text content for brand consistency with AIT Fund voice and style guidelines. For fund-related content only. Requires index_owner role.","tags":["Restricted Content"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"restricted_content_brand_scrub_analyze","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"restricted_content_brand_scrub_analyze","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","description":"Text content to analyze (max 12000 chars)."},"channel":{"type":"string","description":"Communication channel."},"stage":{"type":"string","description":"Content stage."},"audience":{"type":"string","description":"Target audience."}},"required":["text"]}}}}}},"/api/agents/v1/rsvps/alumni_events":{"get":{"operationId":"rsvp_alumni_events_list","summary":"Rsvp alumni events list","description":"List other AI Tinkerers events the RSVP submitter has attended as an alumnus.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_alumni_events_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_alumni_events_list","parameters":[{"name":"rsvp_ref","in":"query","required":true,"schema":{"type":"string"},"description":"RSVP token."}]}},"/api/agents/v1/rsvps/assessment":{"get":{"operationId":"rsvp_assessment_get","summary":"Rsvp assessment get","description":"Get the AI-generated assessment/evaluation for a talk submission. Includes overall score, category scores, and recommendation.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_assessment_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_assessment_get","parameters":[{"name":"rsvp_ref","in":"query","required":true,"schema":{"type":"string"},"description":"RSVP token."}]}},"/api/agents/v1/rsvps/attendance/update":{"post":{"operationId":"rsvp_attendance_update","summary":"Rsvp attendance update","description":"Record private dinner guest attendance: attended, absent (explicit no-show), or unknown (clear the record). Uses the same operation as Dinner HQ. Only event facilitators may write. Absent requires the event to have ended. Preserves registration state, including cancellations, records an audit entry, and never sends email or prints a badge. RSVP responses expose attendance_status and attendance_recorded_at; unknown means unrecorded, not an explicit no-show.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_attendance_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_attendance_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token."},"rsvp_id":{"type":"integer","description":"RSVP ID (alternative to rsvp_ref)."},"status":{"type":"string","enum":["attended","absent","unknown"],"description":"Recorded physical attendance, independent of registration state."}},"required":["status"]}}}}}},"/api/agents/v1/rsvps/awaiting_payment":{"get":{"operationId":"rsvp_awaiting_payment_list","summary":"Rsvp awaiting payment list","description":"List RSVPs that are awaiting Stripe payment for paid events. Filter by meetup or city chapter. Returns registrant details for follow-up automation (DMs, emails, etc).","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_awaiting_payment_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_awaiting_payment_list","parameters":[{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific event by meetup token."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter (weblog token)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max results (default 100, max 500)."}]}},"/api/agents/v1/rsvps/bulk_state_update":{"post":{"operationId":"rsvp_bulk_state_update","summary":"Rsvp bulk state update","description":"Change up to 100 RSVP states in one scoped request. Emails default off; each row may override send_email. Returns per-row results and errors without mutating RSVPs outside the caller scope.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_bulk_state_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_bulk_state_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"updates":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"rsvp_token":{"type":"string"},"rsvp_id":{"type":"integer"},"state":{"type":"string","enum":["registered","attending","waitlisted","denied"]},"send_email":{"type":"boolean"},"note":{"type":"string"}},"required":["state"]}},"send_email":{"type":"boolean","description":"Default email behavior for rows without an override. Defaults false.","default":false}},"required":["updates"]}}}}}},"/api/agents/v1/rsvps/comments/list":{"get":{"operationId":"rsvp_comments_list","summary":"Rsvp comments list","description":"List private comment threads attached to an RSVP. Index owners can read all RSVP comments. Other callers only receive threads they can already access as the RSVP owner, an authorized comment audience/board member, or a participant in that thread. Unrelated callers receive a non-enumerating not-found response.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_comments_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_comments_list","parameters":[{"name":"rsvp_token","in":"query","required":false,"schema":{"type":"string"},"description":"RSVP token. Provide this or rsvp_id."},{"name":"rsvp_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric RSVP id. Provide this or rsvp_token."}]}},"/api/agents/v1/rsvps/email_preview":{"get":{"operationId":"rsvp_email_preview_get","summary":"Rsvp email preview get","description":"Get a preview of the email that would be sent for a specific RSVP/talk submission. Returns subject, HTML, and text versions.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_email_preview_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_email_preview_get","parameters":[{"name":"rsvp_ref","in":"query","required":true,"schema":{"type":"string"},"description":"RSVP token."}]}},"/api/agents/v1/rsvps/export_csv":{"get":{"operationId":"rsvp_export_csv","summary":"Rsvp export csv","description":"Export filtered RSVPs as CSV data. Supports the same filters as rsvp_search. Returns CSV content with headers.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_export_csv","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_export_csv","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific meetup."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"time_field","in":"query","required":false,"schema":{"type":"string","enum":["event_start_at","rsvp_created_at","rsvp_updated_at","speaker_submitted_at","speaker_approved_at","checked_in_at"]},"description":"Timestamp field for time_from/time_to, or for date_from/date_to when provided."},{"name":"time_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"time_to","in":"query","required":false,"schema":{"type":"string"},"description":"End timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"created_from","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_from."},{"name":"created_to","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_to."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by status."},{"name":"rsvp_tag","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by RSVP tag such as sponsor or organizer."}]}},"/api/agents/v1/rsvps/get":{"get":{"operationId":"rsvp_get","summary":"Rsvp get","description":"Get full details of a specific RSVP/talk submission, including the client profile, meetup details, visibility-aware talk video, public speaker image, talk page URL, and a ready-to-use photo_search recipe for event photos. Provide either rsvp_ref or rsvp_id.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_get","parameters":[{"name":"rsvp_ref","in":"query","required":false,"schema":{"type":"string"},"description":"RSVP token to look up. Provide this or rsvp_id."},{"name":"rsvp_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric RSVP id. Provide this or rsvp_ref."}]}},"/api/agents/v1/rsvps/mark_attended":{"post":{"operationId":"rsvp_mark_attended","summary":"Rsvp mark attended","description":"Mark an RSVP as attended (checked in). This is rejected before the event starts. Use when an attendee reports they attended an event but were not checked in (e.g. arrived late, missed QR scan). Sets confirmed_at on the RSVP record and creates an audit trail entry visible via rsvp_status_history_list. Pass send_email=false for silent attendance backfills; suppresses both the checked-in follow-up and resolved-attendance emails. Defaults true to preserve existing notification behavior.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_mark_attended","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_mark_attended","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token."},"rsvp_id":{"type":"integer","description":"RSVP ID (alternative to rsvp_ref)."},"send_email":{"type":"boolean","default":true,"description":"Whether to allow check-in notification emails. Set false to suppress both checked-in follow-up and resolved-attendance emails for this operation."}}}}}}}},"/api/agents/v1/rsvps/mark_cancelled":{"post":{"operationId":"rsvp_mark_cancelled","summary":"Rsvp mark cancelled","description":"Mark an RSVP as cancelled. Use when an attendee or speaker clearly states they intended to cancel, could not make it, cannot attend in person, or missed the event. Changes RSVP state to cancelled_by_user and withdraws any submitted talk so speaker/survey workflows do not continue.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_mark_cancelled","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_mark_cancelled","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token."},"rsvp_id":{"type":"integer","description":"RSVP ID (alternative to rsvp_ref)."}}}}}}}},"/api/agents/v1/rsvps/meetup_score_audit":{"get":{"operationId":"rsvp_meetup_score_audit","summary":"Rsvp meetup score audit","description":"Audit whether recent RSVP clients have meetup_score calculated. Defaults to first visible RSVP per client in the last 24 hours, excluding the newest 15 minutes. Results are constrained to the caller-visible city/series scope; index owners can audit the full network.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_meetup_score_audit","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_meetup_score_audit","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max problematic samples to return (default 25, max 100)."},{"name":"min_age_minutes","in":"query","required":false,"schema":{"type":"integer","default":15},"description":"Exclude RSVPs newer than this many minutes (default 15)."},{"name":"first_rsvp_only","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Only audit each client at their first RSVP in the caller-visible scope (default true)."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search across talk titles, descriptions, names, locations, and cities."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific meetup."},{"name":"meetup_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple meetups."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific person."},{"name":"client_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple people."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter (weblog token)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"time_field","in":"query","required":false,"schema":{"type":"string","enum":["event_start_at","rsvp_created_at","rsvp_updated_at","speaker_submitted_at","speaker_approved_at","checked_in_at"]},"description":"Timestamp field for time_from/time_to, or for date_from/date_to when provided. Defaults to rsvp_created_at when no time filter is supplied."},{"name":"time_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"time_to","in":"query","required":false,"schema":{"type":"string"},"description":"End timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"created_from","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_from."},{"name":"created_to","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_to."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by status: main_stage, science_fair, approved, checked_in, no_show, or RSVP state."},{"name":"states","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"RSVP states to include when status is omitted. Defaults to registered, attending, and waitlisted."}]}},"/api/agents/v1/rsvps/presentation_correction":{"post":{"operationId":"rsvp_presentation_correction","summary":"Rsvp presentation correction","description":"Preview or apply a correction for a submitted presentation that did not happen. The operation marks only the selected RSVP presentation as sidelined and removes only that RSVP question from each event survey response, preserving every respondent's other answers. It also removes the stale survey question and cached report entry, never sends email, and writes an audit event. Defaults to preview; confirm=true requires the exact affected and rating counts returned by the preview.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_presentation_correction","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_presentation_correction","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"Exact RSVP token to correct."},"rsvp_id":{"type":"integer","description":"Numeric RSVP id, alternative to rsvp_ref."},"reason":{"type":"string","description":"Required audit reason for the correction."},"confirm":{"type":"boolean","description":"Must be true to apply. Omit or false for preview.","default":false},"expected_affected_response_count":{"type":"integer","minimum":0,"description":"Required on confirm; copy affected_response_count from the latest preview."},"expected_rating_count":{"type":"integer","minimum":0,"description":"Required on confirm; copy rating_count from the latest preview."}},"required":["reason"]}}}}}},"/api/agents/v1/rsvps/restore_prior_approval":{"post":{"operationId":"rsvp_restore_prior_approval","summary":"Rsvp restore prior approval","description":"Safely restore an RSVP to attending only when append-only history proves the same attendee was previously attending and then self-cancelled. For dinners, the server atomically restores only when a spot is currently available; otherwise it returns restored=false with status=dinner_full. This is a mutating action and sends the normal RSVP email by default unless send_email=false.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_restore_prior_approval","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_restore_prior_approval","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token to evaluate and restore."},"rsvp_id":{"type":"integer","description":"Numeric RSVP id. Use rsvp_ref when possible."},"send_email":{"type":"boolean","description":"Whether to send the standard confirmation email after a successful restoration. Defaults to true.","default":true},"note":{"type":"string","description":"Short internal note about the support request."}}}}}}}},"/api/agents/v1/rsvps/search":{"get":{"operationId":"rsvp_search","summary":"Rsvp search","description":"Search and filter RSVPs/talk submissions. date_from/date_to filter event_start_at by default. For other RSVP time dimensions, pass time_field with time_from/time_to (or date_from/date_to), e.g. time_field=rsvp_created_at for RSVPs created in a window. Use speaker_status for speaker proposal filters such as submitted, approved, not_approved, pending_review, main_stage, or science_fair. Supports status (checked_in, no_show, or any RSVP state), payment status, and sorting (date, recent, demo_score, user_score). Response includes raw rsvp.state for internal decisions/mutations and registrant_status, registrant_status_label, and registrant_status_text for external registrant-facing replies; use registrant_status fields when writing to the registrant because internal state denied is communicated as waitlisted. Response also includes RSVP created_at/updated_at, speaker_status, speaker_approval_status, checked_in boolean, and checked_in_at timestamp for each RSVP.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_search","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search across talk titles, descriptions, speaker names, emails, cities."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 200)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"Number of results to skip for pagination (default 0)."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific meetup."},{"name":"meetup_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple meetups."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific person."},{"name":"client_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple people."},{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by email address."},{"name":"emails","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter by multiple emails."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter (weblog token)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Filters event_start_at unless time_field is provided; then filters that time field."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Filters event_start_at unless time_field is provided; then filters that time field."},{"name":"time_field","in":"query","required":false,"schema":{"type":"string","enum":["event_start_at","rsvp_created_at","rsvp_updated_at","speaker_submitted_at","speaker_approved_at","checked_in_at"]},"description":"Timestamp field for time_from/time_to, or for date_from/date_to when provided. Default date_from/date_to behavior remains event_start_at."},{"name":"time_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"time_to","in":"query","required":false,"schema":{"type":"string"},"description":"End timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"created_from","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_from."},{"name":"created_to","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_to."},{"name":"speaker_status","in":"query","required":false,"schema":{"type":"string","enum":["submitted","approved","not_approved","submitted_not_approved","pending_review","sidelined","withdrawn","main_stage","science_fair"]},"description":"Filter by speaker proposal status. Use submitted for all speaker proposals; approved for main stage or science fair approvals; not_approved for submitted proposals without either approval timestamp; pending_review for submitted proposals not approved/sidelined/withdrawn."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["checked_in","no_show","registered","attending","waitlisted","denied","cancelled_by_user"]},"description":"Filter by RSVP/attendance status: checked_in, no_show, or RSVP state (registered, attending, waitlisted, denied, cancelled_by_user). For speaker proposal status, prefer speaker_status."},{"name":"rsvp_tag","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by RSVP tag such as sponsor, organizer, speaker, volunteer, venue, mentor, judge, finalist, winner, gold, silver, or bronze."},{"name":"payment_status","in":"query","required":false,"schema":{"type":"string","enum":["awaiting_payment","paid"]},"description":"Filter by Stripe payment status on paid events."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["date","recent","rsvp_created_at","rsvp_updated_at","checked_in_at","demo_score","user_score"],"default":"date"},"description":"Sort order (default date). recent sorts by RSVP creation time."}]}},"/api/agents/v1/rsvps/speaker_proposal_upsert":{"post":{"operationId":"rsvp_speaker_proposal_upsert","summary":"Rsvp speaker proposal upsert","description":"Create or update speaker proposal fields on an existing RSVP. Only organizers, admins, and index owners may call this, scoped to their visible events. Submits the proposal if needed and can optionally mark it main_stage, science_fair, sidelined, or pending_review. Does not send speaker or RSVP notification emails unless explicitly requested.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_speaker_proposal_upsert","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_speaker_proposal_upsert","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token to update."},"rsvp_id":{"type":"integer","description":"Numeric RSVP id, alternative to rsvp_ref."},"speaker_title":{"type":"string","description":"Speaker proposal title."},"speaker_description":{"type":"string","description":"Speaker proposal description."},"speaker_justification":{"type":"string","description":"Optional organizer/speaker justification."},"speaker_technologies":{"type":"string","description":"Optional technologies used."},"speaker_url_1":{"type":"string","description":"Optional project URL."},"speaker_url_2":{"type":"string","description":"Optional secondary project URL."},"speaker_url_3":{"type":"string","description":"Optional additional project URL."},"speaker_url_4":{"type":"string","description":"Optional additional project URL."},"speaker_url_5":{"type":"string","description":"Optional additional project URL."},"speaker_video":{"type":"string","description":"Optional video URL."},"speaker_proposal_type":{"type":"string","description":"Optional proposal type for science-fair-enabled events."},"speaker_proposal_private":{"type":"boolean","description":"Whether the proposal should be private to organizers."},"speaker_status":{"type":"string","description":"Optional review status to set.","enum":["pending_review","main_stage","science_fair","sidelined"]},"approved":{"type":"boolean","description":"Convenience flag: true means main_stage, false means pending_review."},"send_speaker_email":{"type":"boolean","description":"Whether to send talk approval/sidelined email when setting an approval status. Defaults false.","default":false},"send_rsvp_email":{"type":"boolean","description":"Whether to send RSVP status email if approval changes RSVP state to attending. Defaults false.","default":false},"note":{"type":"string","description":"Short audit note."}},"required":["speaker_title","speaker_description"]}}}}}},"/api/agents/v1/rsvps/state_update":{"post":{"operationId":"rsvp_state_update","summary":"Rsvp state update","description":"Change one RSVP state to registered, attending, waitlisted, or denied. This is a mutating action and sends the normal RSVP email by default unless send_email=false. Use only when the role policy explicitly permits the state change.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_state_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_state_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token to update."},"rsvp_id":{"type":"integer","description":"Numeric RSVP id. Use rsvp_ref when possible."},"state":{"type":"string","description":"New RSVP state.","enum":["registered","attending","waitlisted","denied"]},"send_email":{"type":"boolean","description":"Whether to send the standard status-change email. Defaults to true.","default":true},"note":{"type":"string","description":"Short internal note explaining the decision."}},"required":["state"]}}}}}},"/api/agents/v1/rsvps/status_history":{"get":{"operationId":"rsvp_status_history_list","summary":"Rsvp status history list","description":"List append-only RSVP status changes newest-first for a single RSVP, including attendance, check-in, and speaker-selection changes, with actor/source/reason metadata and cursor pagination for older events. Provide either rsvp_token or rsvp_id.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_status_history_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_status_history_list","parameters":[{"name":"rsvp_token","in":"query","required":false,"schema":{"type":"string"},"description":"RSVP token. Provide this or rsvp_id."},{"name":"rsvp_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric RSVP id. Provide this or rsvp_token."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 200)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor returned by a previous response for older events."}]}},"/api/agents/v1/rsvps/summary":{"get":{"operationId":"rsvp_summary","summary":"Rsvp summary","description":"Count RSVPs using the same filters as rsvp_search without paging through rows. Supports explicit time dimensions via time_field/time_from/time_to, including rsvp_created_at for \"RSVPs created in the last 24 hours\". For \"how many speakers are approved vs not approved for this event\", call with meetup_token, speaker_status=submitted, and group_by=speaker_approval_status. Optionally group by status, speaker_status, speaker_approval_status, city, meetup, day, week, or month.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_summary","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_summary","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Free-text search across talk titles, descriptions, speaker names, emails, cities."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max groups to return (default 100, max 500)."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city name."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific meetup."},{"name":"meetup_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple meetups."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific person."},{"name":"client_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple people."},{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by email address."},{"name":"emails","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter by multiple emails."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter (weblog token)."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Filters event_start_at unless time_field is provided."},{"name":"time_field","in":"query","required":false,"schema":{"type":"string","enum":["event_start_at","rsvp_created_at","rsvp_updated_at","speaker_submitted_at","speaker_approved_at","checked_in_at"]},"description":"Timestamp field for time_from/time_to, or for date_from/date_to when provided."},{"name":"time_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"time_to","in":"query","required":false,"schema":{"type":"string"},"description":"End timestamp or date for time_field (ISO 8601 or YYYY-MM-DD)."},{"name":"created_from","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_from."},{"name":"created_to","in":"query","required":false,"schema":{"type":"string"},"description":"Convenience alias for time_field=rsvp_created_at + time_to."},{"name":"speaker_status","in":"query","required":false,"schema":{"type":"string","enum":["submitted","approved","not_approved","submitted_not_approved","pending_review","sidelined","withdrawn","main_stage","science_fair"]},"description":"Filter by speaker proposal status: submitted, approved, not_approved, submitted_not_approved, pending_review, sidelined, withdrawn, main_stage, or science_fair."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by RSVP/attendance status: checked_in, no_show, or RSVP state. For speaker proposal status, prefer speaker_status."},{"name":"rsvp_tag","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by RSVP tag such as sponsor or organizer."},{"name":"payment_status","in":"query","required":false,"schema":{"type":"string","enum":["awaiting_payment","paid"]},"description":"Filter by Stripe payment status on paid events."},{"name":"group_by","in":"query","required":false,"schema":{"type":"string","enum":["status","speaker_status","speaker_approval_status","city","meetup","day","week","month"]},"description":"Optional aggregation dimension. speaker_approval_status groups submitted speaker proposals into approved/not_approved/none; speaker_status groups them into main_stage/science_fair/pending_review/sidelined/withdrawn/none."}]}},"/api/agents/v1/rsvps/talk_history":{"get":{"operationId":"talk_history_list","summary":"Talk history list","description":"List all talks/demos a person has given across AI Tinkerers events. Returns talk titles, descriptions, meetup details, and approval status.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"talk_history_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"talk_history_list","parameters":[{"name":"client_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Client token, email, or name."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 100)."},{"name":"include_unapproved","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include unapproved talk submissions (default false)."}]}},"/api/agents/v1/rsvps/unmark_attended":{"post":{"operationId":"rsvp_unmark_attended","summary":"Rsvp unmark attended","description":"Undo an RSVP check-in while preserving its registration state. Clears the normal confirmed_at check-in timestamp and creates an audit trail entry visible via rsvp_status_history_list.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_unmark_attended","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_unmark_attended","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_ref":{"type":"string","description":"RSVP token."},"rsvp_id":{"type":"integer","description":"RSVP ID (alternative to rsvp_ref)."}}}}}}}},"/api/agents/v1/rsvps/upsert":{"post":{"operationId":"rsvp_upsert","summary":"Rsvp upsert","description":"Create or update one RSVP for a meetup by email. Only organizers, admins, and index owners may call this, and city/series organizers are limited to their visible event scope. Creates the client if needed, validates the email, subscribes the client to the chapter, and can set registered/attending/waitlisted/denied. API-created RSVPs do not send notification email unless send_email=true.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_upsert","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_upsert","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Target meetup token."},"email":{"type":"string","description":"Registrant email address."},"name":{"type":"string","description":"Optional display/name label for a newly created or unlabeled client."},"state":{"type":"string","description":"Desired RSVP state. Defaults to registered.","enum":["registered","attending","waitlisted","denied"],"default":"registered"},"linkedin_url":{"type":"string","description":"Optional LinkedIn URL to attach if the client lacks one."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional RSVP tags such as speaker, sponsor, organizer, volunteer, or venue."},"tag":{"type":"string","description":"Single RSVP tag convenience parameter."},"send_email":{"type":"boolean","description":"Whether to send the normal RSVP status email. Defaults to false for API backfills.","default":false},"note":{"type":"string","description":"Short audit note explaining why the RSVP was created or changed."}},"required":["meetup_token","email"]}}}}}},"/api/agents/v1/rsvps/upsert_with_speaker_proposal":{"post":{"operationId":"rsvp_upsert_with_speaker_proposal","summary":"Rsvp upsert with speaker proposal","description":"Create/update an RSVP by email and create/update its speaker proposal in one call. This is intended for organizer/admin backfills such as adding a person who actually presented. Only organizers, admins, and index owners may call this, scoped to their visible events. Notification defaults are false.","tags":["RSVPs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"rsvp_upsert_with_speaker_proposal","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"rsvp_upsert_with_speaker_proposal","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Target meetup token."},"email":{"type":"string","description":"Registrant/speaker email address."},"name":{"type":"string","description":"Optional person name."},"state":{"type":"string","description":"Desired RSVP state. Defaults to registered.","enum":["registered","attending","waitlisted","denied"],"default":"registered"},"linkedin_url":{"type":"string","description":"Optional LinkedIn URL."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional RSVP tags."},"send_email":{"type":"boolean","description":"Whether to send the normal RSVP status email. Defaults false.","default":false},"send_rsvp_email":{"type":"boolean","description":"Whether to send RSVP status email if speaker approval changes RSVP state to attending. Defaults false.","default":false},"send_speaker_email":{"type":"boolean","description":"Whether to send speaker approval/sidelined email. Defaults false.","default":false},"note":{"type":"string","description":"Short audit note."},"speaker":{"type":"object","description":"Speaker proposal fields. Top-level speaker_* fields are also accepted.","properties":{"speaker_title":{"type":"string"},"speaker_description":{"type":"string"},"speaker_justification":{"type":"string"},"speaker_technologies":{"type":"string"},"speaker_url_1":{"type":"string"},"speaker_url_2":{"type":"string"},"speaker_url_3":{"type":"string"},"speaker_url_4":{"type":"string"},"speaker_url_5":{"type":"string"},"speaker_video":{"type":"string"},"speaker_proposal_type":{"type":"string"},"speaker_proposal_private":{"type":"boolean"},"speaker_status":{"type":"string","enum":["pending_review","main_stage","science_fair","sidelined"]},"approved":{"type":"boolean"},"send_speaker_email":{"type":"boolean"},"send_rsvp_email":{"type":"boolean"}}}},"required":["meetup_token","email"]}}}}}},"/api/agents/v1/social_posts/generate":{"post":{"operationId":"social_post_generate","summary":"Social post generate","description":"Generate a social post package for a meetup, RSVP, content page, client, or sponsor using agent-backed drafting.","tags":["Social Posts"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"social_post_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"social_post_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source_type":{"type":"string","enum":["meetup","rsvp","content_page","client","sponsor"],"description":"Type of source object."},"source_ref":{"type":"string","description":"Token, slug, or identifier for the source object."},"platform":{"type":"string","enum":["linkedin","x"],"description":"Target platform.","default":"linkedin"},"goal":{"type":"string","enum":["promote","recap","spotlight","announce","sponsor_thanks"],"description":"Primary goal.","default":"promote"},"tone":{"type":"string","description":"Optional tone guidance."},"city":{"type":"string","description":"Optional city override."}},"required":["source_type","source_ref"]}}}}}},"/api/agents/v1/speaker_promo_banners/custom/generate":{"post":{"operationId":"speaker_promo_custom_banners_generate","summary":"Speaker promo custom banners generate","description":"Create/update and queue a custom uploaded-photo speaker promo kit for exactly one approved speaker. Pass custom_image_url on first generation.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_custom_banners_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_custom_banners_generate","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_token":{"type":"string","description":"Specific RSVP/speaker token."},"meetup_token":{"type":"string","description":"Meetup token, often paired with client_token or query."},"client_token":{"type":"string","description":"Speaker/client token."},"email":{"type":"string","description":"Speaker email when the API key is allowed to use email fields."},"query":{"type":"string","description":"Search speaker name, talk title, description, city, or event location."},"custom_image_url":{"type":"string","description":"Publicly fetchable speaker/photo URL to import for the custom kit."},"display_name":{"type":"string","description":"Optional display name override."},"display_headline":{"type":"string","description":"Optional headline/subtitle override."},"display_talk_title":{"type":"string","description":"Optional talk title override."},"display_talk_summary":{"type":"string","description":"Optional talk summary override."},"use_uploaded_photo_for_group_banner":{"type":"boolean","description":"Use this custom photo in group banner generation.","default":false},"force":{"type":"boolean","description":"Regenerate even if custom banners already exist.","default":true}}}}}}}},"/api/agents/v1/speaker_promo_banners/download":{"get":{"operationId":"speaker_promo_banners_download","summary":"Speaker promo banners download","description":"Download one ready speaker promo banner as image bytes. Use card_token returned by speaker_promo_banners_list/get/generate.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_download","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_download","parameters":[{"name":"card_token","in":"query","required":true,"schema":{"type":"string"},"description":"Speaker promo card token."}]}},"/api/agents/v1/speaker_promo_banners/generate":{"post":{"operationId":"speaker_promo_banners_generate","summary":"Speaker promo banners generate","description":"Queue async generation of standard speaker promo banners for matched approved speakers when missing, or force regeneration when requested.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_generate","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rsvp_token":{"type":"string","description":"Specific RSVP/speaker token."},"rsvp_tokens":{"type":"array","description":"Specific RSVP/speaker tokens.","items":{"type":"string"}},"meetup_token":{"type":"string","description":"Meetup token, often paired with client_token or query."},"client_token":{"type":"string","description":"Speaker/client token."},"email":{"type":"string","description":"Speaker email when the API key is allowed to use email fields."},"query":{"type":"string","description":"Search speaker name, talk title, description, city, or event location."},"variant_scope":{"type":"string","description":"Which variants to generate: social (default), print, or all.","enum":["social","print","all"],"default":"social"},"force":{"type":"boolean","description":"Regenerate even if banners already exist.","default":false},"include_custom":{"type":"boolean","description":"Include custom uploaded-photo kits in the response payload.","default":false}}}}}}}},"/api/agents/v1/speaker_promo_banners/generate_all":{"post":{"operationId":"speaker_promo_banners_generate_all","summary":"Speaker promo banners generate all","description":"Queue all missing speaker promo banners for one meetup, optionally including the multi-speaker group banners. Returns per-speaker queue/skipped status and ready image URLs when present.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_generate_all","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_generate_all","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Meetup/event token."},"variant_scope":{"type":"string","description":"Which speaker variants to generate: social (default), print, or all.","enum":["social","print","all"],"default":"social"},"include_group_banners":{"type":"boolean","description":"Also queue missing multi-speaker group banners.","default":true},"include_custom":{"type":"boolean","description":"Include custom uploaded-photo kits in speaker response payloads.","default":false},"force":{"type":"boolean","description":"Regenerate even if banners already exist.","default":false}},"required":["meetup_token"]}}}}}},"/api/agents/v1/speaker_promo_banners/get":{"get":{"operationId":"speaker_promo_banners_get","summary":"Speaker promo banners get","description":"Get speaker promo banners for a specific approved speaker or narrowed speaker query. Returns hosted image URLs, LinkedIn text, and refs.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_get","parameters":[{"name":"rsvp_token","in":"query","required":false,"schema":{"type":"string"},"description":"Specific RSVP/speaker token."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Meetup token, often paired with client_token or query."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Speaker/client token."},{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Speaker email when the API key is allowed to use email fields."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search speaker name, talk title, description, city, or event location."},{"name":"include_custom","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include custom uploaded-photo banner kits."}]}},"/api/agents/v1/speaker_promo_banners/group_banners/generate":{"post":{"operationId":"speaker_promo_group_banners_generate","summary":"Speaker promo group banners generate","description":"Queue async generation of the multi-speaker group banners for one meetup when missing or stale, or force regeneration. Admins and explicit index owners may use force=true for a post-event repair; generation remains closed after the event for other callers.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_group_banners_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_group_banners_generate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string","description":"Meetup/event token."},"force":{"type":"boolean","description":"Regenerate even if group banners already exist and are current. For admins and explicit index owners, this also permits a post-event repair.","default":false}},"required":["meetup_token"]}}}}}},"/api/agents/v1/speaker_promo_banners/group_banners/list":{"get":{"operationId":"speaker_promo_group_banners_list","summary":"Speaker promo group banners list","description":"List multi-speaker group banner records for one meetup, including ready image URLs, stale status, missing-photo blockers, and speaker lineup context.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_group_banners_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_group_banners_list","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"},"description":"Meetup/event token."}]}},"/api/agents/v1/speaker_promo_banners/list":{"get":{"operationId":"speaker_promo_banners_list","summary":"Speaker promo banners list","description":"List LinkedIn-ready speaker promo banner records for approved speakers. Use this to find existing banner image URLs and API download paths by person, RSVP, meetup, city, or text query.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_list","parameters":[{"name":"rsvp_token","in":"query","required":false,"schema":{"type":"string"},"description":"Specific RSVP/speaker token."},{"name":"rsvp_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Specific RSVP/speaker tokens."},{"name":"meetup_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to one meetup/event."},{"name":"meetup_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple meetups/events."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to one speaker/client."},{"name":"client_tokens","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to multiple speakers/clients."},{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by speaker email when the API key is allowed to use email fields."},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search speaker name, talk title, description, city, or event location."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"City/community name filter."},{"name":"include_custom","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include custom uploaded-photo banner kits for the matched speakers."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max speakers (default 25, max 100)."}]}},"/api/agents/v1/speaker_promo_banners/regenerate":{"post":{"operationId":"speaker_promo_banners_regenerate","summary":"Speaker promo banners regenerate","description":"Regenerate one existing speaker promo card, custom speaker promo card, or multi-speaker group banner by token. Admins and explicit index owners may use force=true for a post-event multi-speaker group banner repair.","tags":["Speaker Promo Banners"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"speaker_promo_banners_regenerate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"speaker_promo_banners_regenerate","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"card_token":{"type":"string","description":"Standard speaker promo card token."},"custom_card_token":{"type":"string","description":"Custom speaker promo card token."},"group_banner_token":{"type":"string","description":"Multi-speaker group banner token."},"include_custom":{"type":"boolean","description":"Include custom uploaded-photo kits in standard card response payloads.","default":false},"force":{"type":"boolean","description":"For admins and explicit index owners, permit a post-event multi-speaker group banner repair.","default":false}}}}}}}},"/api/agents/v1/sponsors/contacts":{"get":{"operationId":"sponsor_contact_list","summary":"Sponsor contact list","description":"List contacts for a specific sponsor. Returns names, roles, and contact details.","tags":["Sponsors"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"sponsor_contact_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"sponsor_contact_list","parameters":[{"name":"sponsor_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Sponsor token."}]}},"/api/agents/v1/sponsors/pitch_generate":{"post":{"operationId":"sponsor_pitch_generate","summary":"Sponsor pitch generate","description":"Generate an AI-written sponsorship pitch for a company. Can reference an existing sponsor or provide a new company name.","tags":["Sponsors"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"sponsor_pitch_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"sponsor_pitch_generate","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sponsor_ref":{"type":"string","description":"Existing sponsor token (optional if name provided)."},"name":{"type":"string","description":"Company name (required if no sponsor_ref)."},"context":{"type":"object","description":"Additional context for the pitch."},"city":{"type":"string","description":"Target city for the pitch."},"channel":{"type":"string","description":"Communication channel (e.g. email, linkedin)."},"target_audience":{"type":"string","description":"Target audience description."}}}}}}}},"/api/agents/v1/sponsors/research_generate":{"post":{"operationId":"sponsor_research_generate","summary":"Sponsor research generate","description":"Generate an AI-researched sponsor/company brief with timely developments, scale signals, and fit notes for AI Tinkerers.","tags":["Sponsors"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"sponsor_research_generate","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"sponsor_research_generate","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sponsor_ref":{"type":"string","description":"Existing sponsor token (optional if name provided)."},"name":{"type":"string","description":"Company name (required if no sponsor_ref)."},"domain":{"type":"string","description":"Company domain for grounding."},"context":{"type":"object","description":"Additional research context."},"city":{"type":"string","description":"Optional city context."},"target_audience":{"type":"string","description":"Optional target audience description."}}}}}}}},"/api/agents/v1/sponsors/search":{"get":{"operationId":"sponsor_search","summary":"Sponsor search","description":"Search for sponsors by name, industry, or city. Filter by active status.","tags":["Sponsors"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"sponsor_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"sponsor_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term: company name, industry, or city."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 25)."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by city."},{"name":"industry","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by industry."},{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Only active sponsors (default false)."}]}},"/api/agents/v1/subscribers/growth_stats":{"get":{"operationId":"subscriber_growth_stats_get","summary":"Subscriber growth stats get","description":"Get subscriber growth time series for a city chapter newsletter. Shows subscriber count over time with configurable buckets (day/week/month).","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_growth_stats_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_growth_stats_get","parameters":[{"name":"weblog_token","in":"query","required":true,"schema":{"type":"string"},"description":"City chapter weblog token (required)."},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["day","week","month"]},"description":"Time bucket size."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Max 730 days range."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/subscribers/opt_out_metrics":{"get":{"operationId":"subscriber_opt_out_metrics_get","summary":"Subscriber opt out metrics get","description":"Get opt-out/unsubscribe metrics over time for a city chapter newsletter. Shows opt-out count, active subscribers, and opt-out rate percentage.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_opt_out_metrics_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_opt_out_metrics_get","parameters":[{"name":"weblog_token","in":"query","required":true,"schema":{"type":"string"},"description":"City chapter weblog token (required)."},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["day","week","month"]},"description":"Time bucket size."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Max 730 days range."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD)."}]}},"/api/agents/v1/subscribers/preferences/get":{"get":{"operationId":"subscriber_preferences_get","summary":"Subscriber preferences get","description":"Get email preference and newsletter subscription state. Admins and AI Tinkerers index owners may target any user; all other API users may only retrieve their own preferences.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_preferences_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_preferences_get","parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string"},"description":"Target user email. Privileged callers only unless it is the API key owner email."},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"},"description":"Target client token. Privileged callers only unless it is the API key owner token."},{"name":"subscriber_token","in":"query","required":false,"schema":{"type":"string"},"description":"Target subscriber token. Privileged callers only unless it belongs to the API key owner."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optional AI Tinkerers weblog token to inspect. Defaults to Post Training."}]}},"/api/agents/v1/subscribers/preferences/update":{"post":{"operationId":"subscriber_preferences_update","summary":"Subscriber preferences update","description":"Change email preferences or blog subscription state. Admins and AI Tinkerers index owners may target any user; all other API users may only change their own preferences.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_preferences_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_preferences_update","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Target user email. Privileged callers only unless it is the API key owner email."},"client_token":{"type":"string","description":"Target client token. Privileged callers only unless it is the API key owner token."},"subscriber_token":{"type":"string","description":"Target subscriber token. Privileged callers only unless it belongs to the API key owner."},"weblog_token":{"type":"string","description":"AI Tinkerers weblog token for a series preference or subscription update."},"key":{"type":"string","description":"Single mail preference key or series token to update."},"enabled":{"type":"boolean","description":"Whether the single preference key should be enabled."},"subscribed":{"type":"boolean","description":"When provided with weblog_token, changes the whole blog subscription state."},"preferences":{"type":"array","description":"Batch preference updates.","items":{"type":"object","properties":{"key":{"type":"string"},"enabled":{"type":"boolean"},"weblog_token":{"type":"string"}},"required":["key","enabled"]}},"subscriptions":{"type":"array","description":"Batch blog subscription updates.","items":{"type":"object","properties":{"weblog_token":{"type":"string"},"subscribed":{"type":"boolean"}},"required":["weblog_token","subscribed"]}}}}}}}}},"/api/agents/v1/subscribers/score_details":{"get":{"operationId":"subscriber_score_details_get","summary":"Subscriber score details get","description":"Get detailed engagement score breakdown for a subscriber, including activity metrics and scoring factors.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_score_details_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_score_details_get","parameters":[{"name":"subscriber_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Subscriber token."}]}},"/api/agents/v1/subscribers/search":{"get":{"operationId":"subscriber_search","summary":"Subscriber search","description":"Search newsletter subscribers by name, email, or company. Filter by city chapter and opt-in/opt-out status.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term: name, email, or company."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25, max 25)."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a specific city chapter."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["opt_in","opted_in","opt_out","opted_out"]},"description":"Filter by subscription status."},{"name":"tag","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by subscriber tag."}]}},"/api/agents/v1/subscribers/talk_history":{"get":{"operationId":"subscriber_talk_history_get","summary":"Subscriber talk history get","description":"Get talk/demo history for a subscriber. Resolves the subscriber to their client profile and returns their presentation history.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_talk_history_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_talk_history_get","parameters":[{"name":"subscriber_ref","in":"query","required":true,"schema":{"type":"string"},"description":"Subscriber token."}]}},"/api/agents/v1/subscribers/unsubscribe_all":{"post":{"operationId":"subscriber_unsubscribe_all","summary":"Subscriber unsubscribe all","description":"Unsubscribe a user from the selected AI Tinkerers weblog plus network newsletter subscriptions and related mail preference keys. Admins and AI Tinkerers index owners may target any user; all other API users may only unsubscribe themselves.","tags":["Subscribers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"subscriber_unsubscribe_all","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"subscriber_unsubscribe_all","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Target user email. Privileged callers only unless it is the API key owner email."},"client_token":{"type":"string","description":"Target client token. Privileged callers only unless it is the API key owner token."},"subscriber_token":{"type":"string","description":"Target subscriber token. Privileged callers only unless it belongs to the API key owner."},"weblog_token":{"type":"string","description":"AI Tinkerers weblog token. Defaults to Post Training."},"ref":{"type":"string","description":"Optional source/reference token for audit logging."}}}}}}}},"/api/agents/v1/technologies/list":{"get":{"operationId":"technology_list","summary":"Technology list","description":"List technologies/frameworks mentioned in AI Tinkerers talk submissions. Search by name to find specific technologies.","tags":["Technologies"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"technology_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"technology_list","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Search for a specific technology name (e.g. \"langchain\", \"openai\")."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25)."}]}},"/api/agents/v1/technologies/projects":{"get":{"operationId":"technology_projects_list","summary":"Technology projects list","description":"List projects/talks that use a specific technology. Use technology_list first to find the exact technology name.","tags":["Technologies"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"technology_projects_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"technology_projects_list","parameters":[{"name":"technology","in":"query","required":true,"schema":{"type":"string"},"description":"Technology name (e.g. \"langchain\", \"openai\")."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25},"description":"Max results (default 25)."}]}},"/api/agents/v1/tiers/list":{"get":{"operationId":"client_tier_list","summary":"Client tier list","description":"List client tier assignments (expert tier, expert_score, computed_at) with cursor pagination and optional tier_in filter.","tags":["Tiers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_tier_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_tier_list","parameters":[{"name":"tier_in","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Filter to specific tier values."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Max assignments (default 100, max 500)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Pagination cursor from prior response."}]}},"/api/agents/v1/tiers/upsert":{"post":{"operationId":"client_tier_upsert","summary":"Client tier upsert","description":"Upsert a batch of client tier assignments. Restricted to index owners. Agents use this to write their computed tier assignments back to the platform.","tags":["Tiers"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"client_tier_upsert","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"client_tier_upsert","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assignments":{"type":"array","items":{"type":"object","properties":{"client_token":{"type":"string"},"tier":{"type":"string"},"expert_score":{"type":"number"},"computed_at":{"type":"string","description":"ISO 8601 timestamp."},"raw_metrics":{"type":"object"}},"required":["client_token","tier"]},"description":"Array of tier assignments (max 500)."}},"required":["assignments"]}}}}}},"/api/agents/v1/vip_event_emails/list":{"get":{"operationId":"vip_event_emails_list","summary":"Vip event emails list","description":"List every VIP attendee lifecycle email type, including unavailable types, sent state, provider evidence, and eligibility reasons. Supports all VIP event formats and optional attendee filtering.","tags":["Vip Event Emails"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"vip_event_emails_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"vip_event_emails_list","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"client_token","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0}}]}},"/api/agents/v1/vip_event_emails/preview":{"get":{"operationId":"vip_event_emails_preview","summary":"Vip event emails preview","description":"Preview a VIP attendee lifecycle email or read its exact stored sent copy. Sending eligibility uses the event local timezone.","tags":["Vip Event Emails"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"vip_event_emails_preview","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"vip_event_emails_preview","parameters":[{"name":"meetup_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"client_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"message_type","in":"query","required":true,"schema":{"type":"string","enum":["invitation","confirmation","waitlist","cancellation","five_day_reminder","day_before","day_of","check_in","survey","survey_results"]}}]}},"/api/agents/v1/vip_event_emails/send":{"post":{"operationId":"vip_event_emails_send","summary":"Vip event emails send","description":"Send one unsent VIP attendee lifecycle email with confirm=true. Rejects already-sent, in-progress, uncertain, inapplicable, or mistimed sends. Day-before requires the previous local date; day-of closes one hour before start. Repeated calls cannot resend an already-sent email.","tags":["Vip Event Emails"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"vip_event_emails_send","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"vip_event_emails_send","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"meetup_token":{"type":"string"},"client_token":{"type":"string"},"message_type":{"type":"string","enum":["invitation","confirmation","waitlist","cancellation","five_day_reminder","day_before","day_of","check_in","survey","survey_results"]},"confirm":{"type":"boolean"}},"required":["meetup_token","client_token","message_type","confirm"]}}}}}},"/api/agents/v1/weblogs/list":{"get":{"operationId":"weblog_list","summary":"Weblog list","description":"List AI Tinkerers city chapters (weblogs). Filter by region, status, and date range.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_list","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_list","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"Max results (default 50, max 100)."},{"name":"region","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by region."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by chapter status."},{"name":"date_from","in":"query","required":false,"schema":{"type":"string"},"description":"Start date (YYYY-MM-DD). Defaults to 30 days ago."},{"name":"date_to","in":"query","required":false,"schema":{"type":"string"},"description":"End date (YYYY-MM-DD). Defaults to today."}]}},"/api/agents/v1/weblogs/lookup":{"get":{"operationId":"weblog_lookup","summary":"Weblog lookup","description":"Find a weblog by domain, including custom domains and subdomain-based dream.page domains. Returns a single visible weblog.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_lookup","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_lookup","parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string"},"description":"Domain name or URL to look up, e.g. ee.dream.page."}]}},"/api/agents/v1/weblogs/lookup_city":{"get":{"operationId":"weblog_lookup_city","summary":"Weblog lookup city","description":"Find the AI Tinkerers city chapter (weblog) for a given city name. Returns the best match and any alternatives.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_lookup_city","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_lookup_city","parameters":[{"name":"city","in":"query","required":true,"schema":{"type":"string"},"description":"City name to look up (e.g. \"Seattle\", \"San Francisco\")."}]}},"/api/agents/v1/weblogs/roles/update":{"post":{"operationId":"weblog_roles_update","summary":"Weblog roles update","description":"Change an existing member permission profile on an active permissions V2 chapter. Requires chapter access management permission and a write-enabled key. Granting or revoking Chapter Lead additionally requires an admin or explicit AI Tinkerers index owner and confirmed=true. Cannot change your own access, rescope a Lead, or demote the final Lead. This tool does not remove memberships or send email.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_roles_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_roles_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string","description":"Chapter weblog token."},"domain":{"type":"string","description":"Alternative chapter lookup by domain."},"city":{"type":"string","description":"Alternative chapter lookup by city."},"client_token":{"type":"string","description":"Client token of an existing chapter member."},"permission_profile":{"type":"string","enum":["chapter_lead","chapter_organizer","track_organizer","contributor","viewer"]},"confirmed":{"type":"boolean","description":"Must be true when granting or revoking Chapter Lead."}},"required":["client_token","permission_profile"]}}}}}},"/api/agents/v1/weblogs/settings/get":{"get":{"operationId":"weblog_settings_get","summary":"Weblog settings get","description":"List discoverable settings and effective values for a weblog. Authorized for blog owners on their own blogs and AI Tinkerers index owners on any blog.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_settings_get","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_settings_get","parameters":[{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Weblog token to inspect."},{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Optional domain lookup alternative to weblog_token."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Optional city lookup alternative to weblog_token."},{"name":"setting_key","in":"query","required":false,"schema":{"type":"string"},"description":"Optional single setting key to return, e.g. post_meetup_survey."}]}},"/api/agents/v1/weblogs/settings/update":{"post":{"operationId":"weblog_settings_update","summary":"Weblog settings update","description":"Update a weblog setting. Authorized for blog owners on their own blogs and AI Tinkerers index owners on any blog.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_settings_update","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_settings_update","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weblog_token":{"type":"string","description":"Weblog token to update."},"domain":{"type":"string","description":"Optional domain lookup alternative to weblog_token."},"city":{"type":"string","description":"Optional city lookup alternative to weblog_token."},"setting_key":{"type":"string","description":"Setting key to update, e.g. post_meetup_survey."},"setting_value":{"description":"New setting value. Booleans are accepted for switch settings."}},"required":["setting_key","setting_value"]}}}}}},"/api/agents/v1/weblogs/universal_search":{"get":{"operationId":"weblog_universal_search","summary":"Weblog universal search","description":"Search across multiple object types (weblogs, meetups, content pages, RSVPs, clients, subscribers, sponsors) in one call. Good for broad exploratory queries.","tags":["Weblogs"],"responses":{"200":{"description":"Successful response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-rails-controller":"api/agents","x-rails-action":"weblog_universal_search","x-generated-from":"Api::AgentsMcpController::TOOL_DEFINITIONS","x-mcp-tool-name":"weblog_universal_search","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term."},{"name":"object_types","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}},"description":"Object types to search (default: all). Options: weblog, meetup, content_page, rsvp, client, subscriber, sponsor."},{"name":"weblog_token","in":"query","required":false,"schema":{"type":"string"},"description":"Optionally scope search to a specific city chapter."}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Recommended. Send `Authorization: Bearer \u003capi_key\u003e`."},"apiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Alternative API key header."}},"schemas":{"AgentsApiEnvelope":{"type":"object","properties":{"ok":{"type":"boolean"},"data":{"type":"object","additionalProperties":true},"error":{"$ref":"#/components/schemas/AgentsApiError"},"request_id":{"type":"string"}},"required":["ok"]},"AgentsApiError":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"AgentsApiErrorEnvelope":{"type":"object","properties":{"ok":{"type":"boolean","enum":[false]},"error":{"$ref":"#/components/schemas/AgentsApiError"},"request_id":{"type":"string"}},"required":["ok","error"]}},"responses":{"BadRequest":{"description":"Bad request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiErrorEnvelope"}}}},"Unauthorized":{"description":"Missing, invalid, revoked, or suspended API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiErrorEnvelope"}}}},"Forbidden":{"description":"Caller role, scope, or API group is not authorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiErrorEnvelope"}}}},"NotFound":{"description":"Resource or route not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiErrorEnvelope"}}}},"RateLimited":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsApiErrorEnvelope"}}}}}}}