search_opportunities
Search across all indexed opportunities using natural language. Filter by type, funding status, and deadline to locate relevant scholarships, fellowships, and more.
Instructions
Full-text search across all indexed opportunities.
Args: query: Natural-language search query (e.g. "fully funded master's scholarship Germany"). type: Optional filter by opportunity type (scholarship, fellowship, internship, conference, …). funded_only: If True, only return fully-funded opportunities. deadline_before: Only return opportunities with deadlines on or before this date (ISO YYYY-MM-DD). limit: Maximum number of results. Default 20.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| type | No | ||
| funded_only | No | ||
| deadline_before | No | ||
| limit | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/opportunity_mcp/server.py:28-54 (handler)The MCP tool handler for 'search_opportunities'. Decorated with @mcp.tool(), it delegates to Index.search().
@mcp.tool() def search_opportunities( query: str, type: OpportunityType | None = None, funded_only: bool = False, deadline_before: date | None = None, limit: int = 20, ) -> list[Opportunity]: """Full-text search across all indexed opportunities. Args: query: Natural-language search query (e.g. "fully funded master's scholarship Germany"). type: Optional filter by opportunity type (scholarship, fellowship, internship, conference, …). funded_only: If True, only return fully-funded opportunities. deadline_before: Only return opportunities with deadlines on or before this date (ISO YYYY-MM-DD). limit: Maximum number of results. Default 20. """ return _get_index().search( query, opp_type=type, funded_only=funded_only, deadline_before=deadline_before, limit=limit, ) - src/opportunity_mcp/server.py:28-28 (registration)The @mcp.tool() decorator registers this function as an MCP tool named 'search_opportunities'.
@mcp.tool() - src/opportunity_mcp/schema.py:40-42 (schema)The Opportunity Pydantic model used as the return type of search_opportunities.
class Opportunity(BaseModel): """A single opportunity record. The shape every adapter must produce.""" - src/opportunity_mcp/schema.py:11-20 (schema)The OpportunityType enum used as the 'type' parameter in search_opportunities.
class OpportunityType(StrEnum): SCHOLARSHIP = "scholarship" FELLOWSHIP = "fellowship" INTERNSHIP = "internship" CONFERENCE = "conference" EXCHANGE = "exchange" COMPETITION = "competition" GRANT = "grant" AWARD = "award" OTHER = "other" - src/opportunity_mcp/index.py:164-199 (helper)The Index.search() method that executes the FTS5 search with optional filters and returns parsed Opportunity objects.
def search( self, query: str, *, opp_type: OpportunityType | None = None, funded_only: bool = False, deadline_before: date | None = None, limit: int = 20, ) -> list[Opportunity]: fts_query = _to_fts_query(query) if fts_query is None: # No usable tokens — fall through to a posted_at-ordered listing. return self.latest(opp_type=opp_type, limit=limit) sql = ( "SELECT o.* FROM opportunities o " "JOIN opportunities_fts f ON f.rowid = o.rowid " "WHERE opportunities_fts MATCH ?" ) params: list = [fts_query] if opp_type: sql += " AND o.type = ?" params.append(opp_type.value) if funded_only: sql += " AND o.funded = ?" params.append(FundingLevel.FULLY_FUNDED.value) if deadline_before: sql += " AND o.deadline IS NOT NULL AND o.deadline <= ?" params.append(deadline_before.isoformat()) sql += " ORDER BY rank LIMIT ?" params.append(limit) rows = self.conn.execute(sql, params).fetchall() return [_row_to_opportunity(r) for r in rows]