list_sources
Display each indexed source for youth opportunities, showing the number of opportunities contributed and the time of last refresh.
Instructions
List indexed sources, the count each contributed, and last-refresh time.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/opportunity_mcp/server.py:86-101 (handler)The list_sources tool handler function. Decorated with @mcp.tool(), it queries the index for source statistics (count and last_refreshed) and merges them with the static SOURCES registry (name, homepage) to return a list of source info dicts.
@mcp.tool() def list_sources() -> list[dict]: """List indexed sources, the count each contributed, and last-refresh time.""" stats = {row["source_site"]: row for row in _get_index().source_stats()} out = [] for adapter in SOURCES: s = stats.get(adapter.name, {}) out.append( { "name": adapter.name, "homepage": adapter.homepage, "count": s.get("count", 0), "last_refreshed": s.get("last_refreshed"), } ) return out - src/opportunity_mcp/index.py:240-251 (helper)The source_stats() method on the Index class that runs a SQL GROUP BY query on the opportunities table to return per-source counts and max scraped_at timestamps.
def source_stats(self) -> list[dict]: rows = self.conn.execute( """ SELECT source_site, COUNT(*) AS count, MAX(scraped_at) AS last_refreshed FROM opportunities GROUP BY source_site ORDER BY source_site """ ).fetchall() return [dict(r) for r in rows] - src/opportunity_mcp/server.py:86-86 (registration)Registration via the @mcp.tool() decorator on the list_sources function, which registers it as an MCP tool named 'list_sources'.
@mcp.tool() - The SOURCES list: a registry of 7 RSSAdapter instances with name and homepage used by list_sources to compile the output.
SOURCES: list[SourceAdapter] = [ RSSAdapter( name="opportunities_corners", homepage="https://opportunitiescorners.com/", feed_url="https://opportunitiescorners.com/feed/", ), RSSAdapter( name="opportunities_for_youth", homepage="https://opportunitiesforyouth.org/", feed_url="https://opportunitiesforyouth.org/feed/", ), RSSAdapter( name="opportunity_desk", homepage="https://opportunitydesk.org/", feed_url="https://opportunitydesk.org/feed/", ), RSSAdapter( name="scholarships_corner", homepage="https://scholarshipscorner.website/", feed_url="https://scholarshipscorner.website/feed/", ), RSSAdapter( name="opportunities_circle", homepage="https://www.opportunitiescircle.com/", feed_url="https://www.opportunitiescircle.com/feed/", ), RSSAdapter( name="opportunities_for_africans", homepage="https://www.opportunitiesforafricans.com/", feed_url="https://www.opportunitiesforafricans.com/feed/", ), RSSAdapter( name="scholars4dev", homepage="https://www.scholars4dev.com/", feed_url="https://www.scholars4dev.com/feed/", ), ]