Server¶
The entry point for the FastMCP server. Defines the two MCP tools and wires together authentication, storage, and generation.
MCP tools¶
create_podcast_transcript¶
Generates a podcast transcript on the given topic.
Calls PodcastGeneration.generate_transcript(), which sends a structured prompt to Gemini and parses the response into (speaker, text) turns.
Arguments:
| Argument | Type | Description |
|---|---|---|
topic |
str |
The topic for the podcast episode. Any string works — be as specific or general as you like. |
Returns: A list of (speaker, text) tuples. Speaker is either "Annabelle" or "Link".
Example return value:
[
("Annabelle", "[excitement] Okay so today we're diving into Voyager 1..."),
("Link", "[curiosity] Right, and what always gets me is just how far it's traveled..."),
...
]
create_podcast_episode¶
@mcp.tool()
def create_podcast_episode(title: str, transcript: list[tuple[str, str]]) -> dict[str, str]
Synthesizes a transcript into audio and uploads it to GCS.
Calls PodcastGeneration.generate_podcast() to produce a .wav file, then uploads it to the GCS_BUCKET_NAME bucket at episodes/<timestamp>/<title>.wav.
Arguments:
| Argument | Type | Description |
|---|---|---|
title |
str |
Episode title, used as the filename. Spaces are replaced with underscores. |
transcript |
list[tuple[str, str]] |
Output of create_podcast_transcript. |
Returns: {"episode_id": "<filename>", "status": "created"}
HTTP endpoints¶
| Path | Method | Description |
|---|---|---|
/sse |
GET |
MCP SSE transport. Primary client entrypoint. |
/health |
GET |
Health check — returns {"service": "the-curator", "status": "ok"} |
/oauth2/callback |
GET |
Google OAuth callback. Handled by GoogleOAuthProvider. |
/.well-known/oauth-authorization-server |
GET |
OAuth 2.0 server metadata (MCP discovery). |
/register |
POST |
Dynamic Client Registration. |
/authorize |
GET |
MCP authorization endpoint — redirects to Google. |
/token |
POST |
Token endpoint — exchanges codes and refreshes tokens. |
/revoke |
POST |
Token revocation endpoint. |
Module reference¶
the_curator.main
¶
logger = logging.getLogger(__name__)
module-attribute
¶
oauth_provider = GoogleOAuthProvider(google_client_id=(os.environ.get('GOOGLE_CLIENT_ID', '')), google_client_secret=(os.environ.get('GOOGLE_CLIENT_SECRET', '')), allowed_email=(os.environ.get('ALLOWED_EMAIL', '')), server_url=_server_url, gcs_bucket=(os.environ.get('OAUTH_STATE_BUCKET', 'the-curator-oauth-state')))
module-attribute
¶
mcp = FastMCP('The Curator', auth_server_provider=oauth_provider, auth=(AuthSettings(issuer_url=(AnyHttpUrl(_server_url)), resource_server_url=(AnyHttpUrl(_server_url)), client_registration_options=(ClientRegistrationOptions(enabled=True, valid_scopes=['podcast:read', 'podcast:write'], default_scopes=['podcast:read', 'podcast:write'])), revocation_options=(RevocationOptions(enabled=True)), required_scopes=[])))
module-attribute
¶
generator = PodcastGeneration()
module-attribute
¶
app = mcp.sse_app()
module-attribute
¶
create_podcast_transcript(topic: str) -> list[tuple[str, str]]
¶
Create a podcast transcript on the given topic.
create_podcast_episode(title: str, transcript: list[tuple[str, str]]) -> dict[str, str]
¶
Create a podcast episode with the given title and transcript.