search_forum
Search USCardForum for credit card discussions using queries with operators like in:title, @username, category:name, #tag, and date filters. Sort results by relevance, latest, views, likes, activity, or posts.
Instructions
Search USCardForum for topics and posts matching a query.
Args:
query: Search query string. Supports Discourse operators:
- Basic: "chase sapphire bonus"
- In title only: "chase sapphire in:title"
- By author: "@username chase"
- In category: "category:credit-cards chase"
- With tag: "#amex bonus"
- Exact phrase: '"sign up bonus"'
- Exclude: "chase -sapphire"
- Time: "after:2024-01-01" or "before:2024-06-01"
page: Page number for pagination (starts at 1)
order: Sort order for results. Options:
- "relevance": Best match (default)
- "latest": Most recent first
- "views": Most viewed
- "likes": Most liked
- "activity": Recent activity
- "posts": Most replies
Returns a SearchResult object with:
- posts: List of matching SearchPost objects with excerpts
- topics: List of matching SearchTopic objects
- users: List of matching SearchUser objects
- grouped_search_result: Metadata about result counts
Example queries:
- "Chase Sapphire Reserve order:latest" - Recent CSR discussions
- "AMEX popup in:title" - Topics about AMEX popup in title
- "data point category:credit-cards" - Data points in CC category
- "@expert_user order:likes" - Most liked posts by a user
Pagination: If more results exist, increment page parameter.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query string. Supports operators: 'in:title', '@username', 'category:name', '#tag', 'after:date', 'before:date' | |
| page | No | Page number for pagination (starts at 1) | |
| order | No | Sort order: 'relevance' (default), 'latest', 'views', 'likes', 'activity', or 'posts' |
Implementation Reference
- The core implementation of the 'search_forum' MCP tool. Decorated with @mcp.tool(), it defines input parameters with Pydantic Field descriptions (serving as input schema), a detailed docstring, and executes the search via the client, returning SearchResult.@mcp.tool() def search_forum( query: Annotated[ str, Field( description="Search query string. Supports operators: 'in:title', '@username', 'category:name', '#tag', 'after:date', 'before:date'" ), ], page: Annotated[ int | None, Field(default=None, description="Page number for pagination (starts at 1)"), ] = None, order: Annotated[ str | None, Field( default=None, description="Sort order: 'relevance' (default), 'latest', 'views', 'likes', 'activity', or 'posts'", ), ] = None, ) -> SearchResult: """ Search USCardForum for topics and posts matching a query. Args: query: Search query string. Supports Discourse operators: - Basic: "chase sapphire bonus" - In title only: "chase sapphire in:title" - By author: "@username chase" - In category: "category:credit-cards chase" - With tag: "#amex bonus" - Exact phrase: '"sign up bonus"' - Exclude: "chase -sapphire" - Time: "after:2024-01-01" or "before:2024-06-01" page: Page number for pagination (starts at 1) order: Sort order for results. Options: - "relevance": Best match (default) - "latest": Most recent first - "views": Most viewed - "likes": Most liked - "activity": Recent activity - "posts": Most replies Returns a SearchResult object with: - posts: List of matching SearchPost objects with excerpts - topics: List of matching SearchTopic objects - users: List of matching SearchUser objects - grouped_search_result: Metadata about result counts Example queries: - "Chase Sapphire Reserve order:latest" - Recent CSR discussions - "AMEX popup in:title" - Topics about AMEX popup in title - "data point category:credit-cards" - Data points in CC category - "@expert_user order:likes" - Most liked posts by a user Pagination: If more results exist, increment page parameter. """ return get_client().search(query, page=page, order=order)
- Pydantic models defining the output structure returned by the search_forum tool, including SearchResult (primary), SearchPost, SearchTopic, SearchUser, and GroupedSearchResult with fields, descriptions, and a parser method.class SearchPost(BaseModel): """A post in search results.""" id: int = Field(..., description="Post ID") topic_id: int = Field(..., description="Parent topic ID") post_number: int = Field(..., description="Position in topic") username: str | None = Field(None, description="Author username") blurb: str | None = Field(None, description="Content excerpt with highlights") created_at: datetime | None = Field(None, description="When posted") like_count: int = Field(0, description="Number of likes") class Config: extra = "ignore" class SearchTopic(BaseModel): """A topic in search results.""" id: int = Field(..., description="Topic ID") title: str = Field(..., description="Topic title") posts_count: int = Field(0, description="Number of posts") views: int = Field(0, description="View count") like_count: int = Field(0, description="Total likes") category_id: int | None = Field(None, description="Category ID") category_name: str | None = Field(None, description="Category name") created_at: datetime | None = Field(None, description="Creation time") class Config: extra = "ignore" class SearchUser(BaseModel): """A user in search results.""" id: int = Field(..., description="User ID") username: str = Field(..., description="Username") name: str | None = Field(None, description="Display name") avatar_template: str | None = Field(None, description="Avatar URL") class Config: extra = "ignore" class GroupedSearchResult(BaseModel): """Metadata about search result counts.""" post_ids: list[int] = Field(default_factory=list, description="Matching post IDs") topic_ids: list[int] = Field(default_factory=list, description="Matching topic IDs") user_ids: list[int] = Field(default_factory=list, description="Matching user IDs") more_posts: bool | None = Field(None, description="More posts available") more_topics: bool | None = Field(None, description="More topics available") class Config: extra = "ignore" class SearchResult(BaseModel): """Complete search results.""" posts: list[SearchPost] = Field(default_factory=list, description="Matching posts") topics: list[SearchTopic] = Field( default_factory=list, description="Matching topics" ) users: list[SearchUser] = Field(default_factory=list, description="Matching users") grouped_search_result: GroupedSearchResult | None = Field( None, description="Result metadata" ) class Config: extra = "ignore" @classmethod def from_api_response(cls, data: dict[str, Any]) -> "SearchResult": """Parse from raw API response.""" posts = [SearchPost(**p) for p in data.get("posts", [])] topics = [SearchTopic(**t) for t in data.get("topics", [])] users = [SearchUser(**u) for u in data.get("users", [])] grouped = None if "grouped_search_result" in data: grouped = GroupedSearchResult(**data["grouped_search_result"]) return cls( posts=posts, topics=topics, users=users, grouped_search_result=grouped, )
- src/uscardforum/server.py:15-44 (registration)Import statement in the main server entrypoint that imports all MCP tools, including search_forum, which triggers registration via their @mcp.tool() decorators when the server starts.from uscardforum.server_tools import ( analyze_user, bookmark_post, compare_cards, find_data_points, get_all_topic_posts, get_categories, get_current_session, get_hot_topics, get_new_topics, get_notifications, get_top_topics, get_topic_info, get_topic_posts, get_user_actions, get_user_badges, get_user_followers, get_user_following, get_user_reactions, get_user_replies, get_user_summary, get_user_topics, list_users_with_badge, login, research_topic, resource_categories, resource_hot_topics, resource_new_topics, search_forum, subscribe_topic,
- src/uscardforum/server_tools/__init__.py:25-26 (registration)Re-export of the search_forum tool from its module into the server_tools package __init__.py, making it available for bulk import in server.py.from .topics import get_hot_topics, get_new_topics, get_top_topics from .search import search_forum