{"openapi":"3.0.3","info":{"title":"AI Tinkerers Agents API","version":"1.0.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":"Content"},{"name":"Content Pages"},{"name":"Docs"},{"name":"Dossier"},{"name":"Email Send Jobs"},{"name":"Event Promos"},{"name":"Fund Content"},{"name":"Gallery"},{"name":"Global Hackathons"},{"name":"Hackathon Teams"},{"name":"Hackathons"},{"name":"Jobs"},{"name":"Logos"},{"name":"Mail Logs"},{"name":"Media"},{"name":"Meetups"},{"name":"Message Boards"},{"name":"Newsletters"},{"name":"Photos"},{"name":"Promo Banners"},{"name":"RAG Chunks"},{"name":"RSVPs"},{"name":"Recommendations"},{"name":"Restricted Content"},{"name":"Social Posts"},{"name":"Sponsors"},{"name":"Subscribers"},{"name":"Technologies"},{"name":"Tiers"},{"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/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). IMPORTANT: After calling this tool you MUST call ait_availability_verify_booking to confirm the calendar is actually blocked before telling anyone the meeting is scheduled. Never claim a meeting was booked without the verify_booking confirmation.","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."},"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, subscriber tags, and RSVP activity summary.","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/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. 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/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_pages_body_publish","summary":"Content pages body publish","description":"Generated from the Rails route api/agents#content_page_body_publish. 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_body_publish","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/content_pages/body/revert":{"post":{"operationId":"content_pages_body_revert","summary":"Content pages body revert","description":"Generated from the Rails route api/agents#content_page_body_revert. 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_body_revert","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/api/agents/v1/content_pages/body/update":{"post":{"operationId":"content_pages_body_update","summary":"Content pages body update","description":"Generated from the Rails route api/agents#content_page_body_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_body_update","x-generated-from":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/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/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."}]}},"/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/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/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. 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)."},"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/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). 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/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/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 download URL for a media file. URL expires in 1 hour.","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."}]}},"/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 a media file: filename, content type, size, uploader, creation date, folder, and note.","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 for media files across all folders by filename, folder name, uploader name, or note. Returns matching files sorted by most recent first. Much faster than browsing folders one at a time.","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)."}]}},"/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.","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/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) if any, and the weblog it belongs to.","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":"List folders and files in the media upload system. Pass folder_token to browse a specific folder, or omit for root-level listing. Returns child folders and 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_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 root level."}]}},"/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)."}]}},"/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/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/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/search":{"get":{"operationId":"meetup_search","summary":"Meetup search","description":"Search for AI Tinkerers events including meetups, VIP dinners, and hackathons. Filter by city, region, date range, status (upcoming/past), and event type. Returns event details including location, date, and RSVP counts.","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/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/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 all upcoming AI Tinkerers events across all chapters sorted by date. Returns dinners, meetups, and hackathons. Convenience endpoint that requires no parameters.","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 (default 25, max 100)."}]}},"/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.","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)."}},"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. 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. 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 (optional)."},"image_urls":{"type":"array","items":{"type":"string"},"description":"Public image URLs to attach to the post (max 4)."}},"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/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/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/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/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":"rsvps_bulk_state_update","summary":"Rsvps bulk state update","description":"Generated from the Rails route api/agents#rsvp_bulk_state_update. No MCP input schema is currently registered for this route, so the request schema is intentionally permissive.","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":"Rails routes","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"/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 and meetup details. 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). 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.","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)."}}}}}}}},"/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/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_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 state changes and check-in events, with actor/source 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/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_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/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/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/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"}}}}}}}