get_recent_observations
Retrieve bird observation data from eBird for a specified region, including species, locations, dates, and counts from the past 30 days.
Instructions
Get recent bird observations in a region (up to 30 days ago). Returns species, location, date, and count info.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| region_code | Yes | Country, subnational1, subnational2, or location code (e.g., 'US', 'US-NY', 'US-NY-109', 'L99381') | |
| back | No | Number of days back to fetch (1-30) | |
| cat | No | Taxonomic category filter (e.g., 'species', 'hybrid') | |
| hotspot | No | Only fetch from hotspots | |
| include_provisional | No | Include unreviewed observations | |
| max_results | No | Maximum observations to return | |
| spp_locale | No | Language for common names | en |
Implementation Reference
- src/index.ts:59-71 (handler)The handler function that implements the core logic: maps input args to API params, calls the shared makeRequest helper to query the eBird /data/obs/{region}/recent endpoint, and formats the response as MCP content.
async (args) => { const params: Record<string, string | number | boolean> = { back: args.back, hotspot: args.hotspot, includeProvisional: args.include_provisional, sppLocale: args.spp_locale, }; if (args.cat) params.cat = args.cat; if (args.max_results) params.maxResults = args.max_results; const result = await makeRequest(`/data/obs/${args.region_code}/recent`, params); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } - src/index.ts:50-58 (schema)Zod schema defining the input parameters for the tool, including region_code (required), back (days), optional filters like cat, hotspot, etc.
{ region_code: z.string().describe("Country, subnational1, subnational2, or location code (e.g., 'US', 'US-NY', 'US-NY-109', 'L99381')"), back: z.number().min(1).max(30).default(14).describe("Number of days back to fetch (1-30)"), cat: z.string().optional().describe("Taxonomic category filter (e.g., 'species', 'hybrid')"), hotspot: z.boolean().default(false).describe("Only fetch from hotspots"), include_provisional: z.boolean().default(false).describe("Include unreviewed observations"), max_results: z.number().min(1).max(10000).optional().describe("Maximum observations to return"), spp_locale: z.string().default("en").describe("Language for common names"), }, - src/index.ts:48-72 (registration)The server.tool() call that registers the 'get_recent_observations' tool with the MCP server, providing name, description, input schema, and handler function.
"get_recent_observations", "Get recent bird observations in a region (up to 30 days ago). Returns species, location, date, and count info.", { region_code: z.string().describe("Country, subnational1, subnational2, or location code (e.g., 'US', 'US-NY', 'US-NY-109', 'L99381')"), back: z.number().min(1).max(30).default(14).describe("Number of days back to fetch (1-30)"), cat: z.string().optional().describe("Taxonomic category filter (e.g., 'species', 'hybrid')"), hotspot: z.boolean().default(false).describe("Only fetch from hotspots"), include_provisional: z.boolean().default(false).describe("Include unreviewed observations"), max_results: z.number().min(1).max(10000).optional().describe("Maximum observations to return"), spp_locale: z.string().default("en").describe("Language for common names"), }, async (args) => { const params: Record<string, string | number | boolean> = { back: args.back, hotspot: args.hotspot, includeProvisional: args.include_provisional, sppLocale: args.spp_locale, }; if (args.cat) params.cat = args.cat; if (args.max_results) params.maxResults = args.max_results; const result = await makeRequest(`/data/obs/${args.region_code}/recent`, params); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } ); - src/index.ts:19-36 (helper)Shared helper function used by all tools to construct and make authenticated HTTP requests to the eBird API, handling URL params, auth header, error checking, and JSON parsing.
async function makeRequest(endpoint: string, params: Record<string, string | number | boolean> = {}): Promise<unknown> { const url = new URL(`${BASE_URL}${endpoint}`); Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null) { url.searchParams.append(key, String(value)); } }); const response = await fetch(url.toString(), { headers: { "X-eBirdApiToken": API_KEY! }, }); if (!response.ok) { throw new Error(`eBird API error: ${response.status} ${response.statusText}`); } return response.json(); }