list_posts
List recent stories published by a Medium user, defaulting to the authenticated user. Retrieve details like title and URL for content review.
Instructions
Read-only. List recent stories by a user (default: self).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| username | No |
Implementation Reference
- src/medium_ops/client.py:267-331 (handler)MediumClient.list_posts() - Core handler that lists recent stories by a user. Uses a hybrid approach: first tries RSS (zero-auth, fast), then falls back to GraphQL (needs sid). Supports source='auto' (default), 'rss', or 'graphql'. Resolves username from config or viewer profile if not provided.
def list_posts( self, *, limit: int = 20, username: str | None = None, source: str = "auto", ) -> list[dict[str, Any]]: """List latest stories by a user (default: self). source: - "auto" (default): RSS first (zero-auth, fast); GraphQL fallback on miss/error or when limit > 10 (RSS only returns ~10). - "rss": force RSS only. - "graphql": force GraphQL (needs sid). """ username = (username or self.cfg.username or "").lstrip("@") if not username and (source == "auto" or source == "graphql"): try: viewer = self.get_my_profile() username = viewer.get("username") or "" except MediumAPIError: pass if not username: raise MediumAPIError(400, "no username to query (set MEDIUM_USERNAME or pass username=...)") if source in ("auto", "rss"): try: rss_posts = list_posts_via_rss(username, http=self.http, limit=limit) if source == "rss": return [p.to_dict() for p in rss_posts] # auto: return RSS result if it satisfies `limit`, else fall # through to GraphQL for full pagination. if rss_posts and len(rss_posts) >= limit: return [p.to_dict() for p in rss_posts][:limit] except Exception: if source == "rss": raise data = self._gql( operation="UserStreamOverview", query=""" query UserStreamOverview($username: ID!, $first: Int!) { user(username: $username) { id username postsConnection(first: $first) { edges { node { id title uniqueSlug mediumUrl firstPublishedAt clapCount postResponses { count } } } } } } """, variables={"username": username, "first": limit}, ) edges = (((data.get("user") or {}).get("postsConnection") or {}).get("edges")) or [] return [e["node"] for e in edges if e and e.get("node")][:limit] - src/medium_ops/mcp/server.py:81-92 (schema)MCP tool schema registration for 'list_posts' in the TOOLS dict - defines description, and input_schema with optional 'limit' (integer, default 20) and 'username' (string).
"list_posts": { "description": ( "Read-only. List recent stories by a user (default: self)." ), "input_schema": { "type": "object", "properties": { "limit": {"type": "integer", "default": 20}, "username": {"type": "string"}, }, }, }, - src/medium_ops/mcp/server.py:448-449 (registration)Dispatch handler in _dispatch() that routes 'list_posts' calls to MediumClient.list_posts() with limit=20 default and optional username.
if name == "list_posts": return c.list_posts(limit=args.get("limit", 20), username=args.get("username")) - src/medium_ops/rss.py:225-233 (helper)list_posts_via_rss() - Helper function that fetches and parses Medium's RSS feed for a user, returning up to `limit` RssPost objects. Used as the zero-auth transport layer by the main handler.
def list_posts_via_rss( username: str, *, http: httpx.Client | None = None, limit: int = 20, ) -> list[RssPost]: """High-level: fetch + parse, return up to `limit` posts.""" xml = fetch_rss(username, http=http) return parse_rss(xml)[:limit]