Skip to main content
Glama
GodisinHisHeaven

USCardForum MCP Server

get_topic_posts

Fetch posts from a USCardForum topic in batches for paginated reading, starting at a specified position to retrieve content and metadata.

Instructions

Fetch a batch of posts from a topic starting at a specific position. Args: topic_id: The numeric topic ID post_number: Which post number to start from (default: 1 = first post) include_raw: Include raw markdown source (default: False, returns HTML) This fetches ~20 posts per call starting from post_number. Use for paginated reading of topics. Returns a list of Post objects with: - post_number: Position in topic (1, 2, 3...) - username: Author's username - cooked: HTML content of the post - raw: Markdown source (if include_raw=True) - created_at: When posted - updated_at: Last edit time - like_count: Number of likes - reply_count: Number of direct replies - reply_to_post_number: Which post this replies to (if any) Pagination example: 1. Call with post_number=1, get posts 1-20 2. Call with post_number=21, get posts 21-40 3. Continue until no posts returned

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
topic_idYesThe numeric topic ID
post_numberNoWhich post number to start from (default: 1 = first post)
include_rawNoInclude raw markdown source (default: False, returns HTML)

Implementation Reference

  • The core handler function for the MCP tool 'get_topic_posts'. It uses @mcp.tool() decorator for registration, defines input schema via Pydantic Annotated Fields, and delegates to DiscourseClient.get_topic_posts via get_client() helper.
    @mcp.tool() def get_topic_posts( topic_id: Annotated[ int, Field(description="The numeric topic ID"), ], post_number: Annotated[ int, Field(default=1, description="Which post number to start from (default: 1 = first post)"), ] = 1, include_raw: Annotated[ bool, Field(default=False, description="Include raw markdown source (default: False, returns HTML)"), ] = False, ) -> list[Post]: """ Fetch a batch of posts from a topic starting at a specific position. Args: topic_id: The numeric topic ID post_number: Which post number to start from (default: 1 = first post) include_raw: Include raw markdown source (default: False, returns HTML) This fetches ~20 posts per call starting from post_number. Use for paginated reading of topics. Returns a list of Post objects with: - post_number: Position in topic (1, 2, 3...) - username: Author's username - cooked: HTML content of the post - raw: Markdown source (if include_raw=True) - created_at: When posted - updated_at: Last edit time - like_count: Number of likes - reply_count: Number of direct replies - reply_to_post_number: Which post this replies to (if any) Pagination example: 1. Call with post_number=1, get posts 1-20 2. Call with post_number=21, get posts 21-40 3. Continue until no posts returned """ return get_client().get_topic_posts( topic_id, post_number=post_number, include_raw=include_raw )
  • Pydantic model for Post objects returned by get_topic_posts, defining the output schema with fields, descriptions, and validation.
    class Post(BaseModel): """A single post within a topic.""" id: int = Field(..., description="Unique post identifier") post_number: int = Field(..., description="Position in topic (1-indexed)") username: str = Field(..., description="Author's username") cooked: str | None = Field(None, description="HTML-rendered content") raw: str | None = Field(None, description="Raw markdown source") created_at: datetime | None = Field(None, description="When posted") updated_at: datetime | None = Field(None, description="Last edit time") like_count: int = Field(0, description="Number of likes") reply_count: int = Field(0, description="Number of direct replies") reply_to_post_number: int | None = Field( None, description="Post number this replies to" ) class Config: extra = "ignore"
  • Shared helper function get_client() that initializes and returns the DiscourseClient instance used by all forum tools, including optional auto-login.
    def get_client() -> DiscourseClient: """Get or create the Discourse client instance.""" global _client, _login_attempted if _client is None: base_url = os.environ.get("USCARDFORUM_URL", "https://www.uscardforum.com") timeout = float(os.environ.get("USCARDFORUM_TIMEOUT", "15.0")) _client = DiscourseClient(base_url=base_url, timeout_seconds=timeout) # Auto-login if credentials are provided if not _login_attempted: _login_attempted = True username = os.environ.get("NITAN_USERNAME") password = os.environ.get("NITAN_PASSWORD") if username and password: try: result = _client.login(username, password) if result.success: print(f"[uscardforum] Auto-login successful as '{result.username}'") elif result.requires_2fa: print( "[uscardforum] Auto-login failed: 2FA required. Use login() tool with second_factor_token." ) else: print( f"[uscardforum] Auto-login failed: {result.error or 'Unknown error'}" ) except Exception as e: # pragma: no cover - logging side effect print(f"[uscardforum] Auto-login error: {e}") return _client
  • Explicit import of get_topic_posts in server_tools __init__.py, making it available in the tools namespace for the MCP server.
    from .topics import get_topic_info, get_topic_posts, get_all_topic_posts
  • Underlying API implementation in TopicsAPI.get_topic_posts that makes HTTP requests to Discourse API and parses JSON into Post models, called by the MCP tool handler.
    def get_topic_posts( self, topic_id: int, *, post_number: int = 1, include_raw: bool = False, ) -> list[Post]: """Fetch a batch of posts starting at a specific post number. Args: topic_id: Topic ID post_number: Starting post number (default: 1) include_raw: Include raw markdown (default: False) Returns: List of posts sorted by post_number """ params_list: list[tuple[str, Any]] = [ ("post_number", int(post_number)), ("asc", "true"), ("include_suggested", "false"), ("include_raw", str(include_raw).lower()), ] payload = self._get(f"t/topic/{int(topic_id)}.json", params=params_list) raw_posts = payload.get("post_stream", {}).get("posts", []) posts = [] for p in raw_posts: post = Post( id=p.get("id", 0), post_number=p.get("post_number", 0), username=p.get("username", ""), cooked=p.get("cooked"), raw=p.get("raw") if include_raw else None, created_at=p.get("created_at"), updated_at=p.get("updated_at"), like_count=p.get("like_count", 0), reply_count=p.get("reply_count", 0), reply_to_post_number=p.get("reply_to_post_number"), ) posts.append(post) posts.sort(key=lambda p: p.post_number) return posts

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GodisinHisHeaven/uscardforum-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server