Skip to main content
Glama
Codeshark-NET

ClimateTriage MCP Server

search_climate_triage_issues

Find open source issues related to climate change and sustainability projects. Filter by category, programming language, or keyword to discover opportunities to contribute. Supports pagination and sorting for easy access to relevant issues.

Instructions

Searches for open source issues related to climate change, sustainability and more. Use this tool to find opportunities to contribute to projects addressing climate challenges, explore issues in specific programming languages, or discover projects in various sustainability categories. Returns information about issues including project details, descriptions, and links. Supports filtering, pagination, and sorting to help find relevant issues.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
categoryNoFilter issues by project category
keywordNoFilter issues by project keyword (e.g., 'bug', 'help wanted', 'enhancement')
languageNoFilter issues by programming language
orderNoSort order (asc or desc) (default: desc for most recent first)desc
pageNoPagination page number (starts at 1)
per_pageNoNumber of records per page (default: 10)
sortNoField to sort by (default: created_at). Use created_at for most recent issues first.created_at

Implementation Reference

  • index.ts:15-223 (registration)
    Registration of the 'search_climate_triage_issues' tool using server.addTool, including name, description, parameters schema, and execute handler.
    server.addTool({ name: "search_climate_triage_issues", description: "Searches for open source issues related to climate change, sustainability and more. " + "Use this tool to find opportunities to contribute to projects addressing climate challenges, " + "explore issues in specific programming languages, or discover projects in various sustainability categories. " + "Returns information about issues including project details, descriptions, and links. " + "Supports filtering, pagination, and sorting to help find relevant issues.", parameters: z.object({ category: z .enum([ "Climate Change", "Energy Systems", "Emissions", "Consumption", "Biosphere", "Hydrosphere", "Sustainable Development", ]) .describe("Filter issues by project category") .optional(), language: z .enum([ "JavaScript", "TypeScript", "Python", "Java", "C#", "C++", "C", "Ruby", "Go", "Rust", "Swift", "Kotlin", "PHP", "HTML", "CSS", "Shell", "Dart", "Scala", "R", "Elixir", "Clojure", ]) .describe("Filter issues by programming language") .optional(), keyword: z .string() .describe( "Filter issues by project keyword (e.g., 'bug', 'help wanted', 'enhancement')" ) .optional(), page: z .number() .int() .min(1) .describe("Pagination page number (starts at 1)") .optional(), per_page: z .number() .int() .min(1) .default(10) .describe("Number of records per page (default: 10)") .optional(), sort: z .enum(["created_at", "updated_at", "stars"]) .default("created_at") .describe( "Field to sort by (default: created_at). Use created_at for most recent issues first." ) .optional(), order: z .enum(["asc", "desc"]) .default("desc") .describe( "Sort order (asc or desc) (default: desc for most recent first)" ) .optional(), }), execute: async (args, { log }) => { try { log.info("Searching for climate issues", { category: args.category, language: args.language, keyword: args.keyword, page: args.page, per_page: args.per_page, sort: args.sort, order: args.order, }); const params = new URLSearchParams(); if (args.category) { params.append("category", args.category); } if (args.language) { params.append("language", args.language); } if (args.keyword) { params.append("keyword", args.keyword); } if (args.page) { params.append("page", args.page.toString()); } if (args.per_page !== undefined) { params.append("per_page", args.per_page.toString()); } if (args.sort) { params.append("sort", args.sort); } if (args.order) { params.append("order", args.order); } const response = await fetch( `${API_BASE_URL}/issues?${params.toString()}` ); if (!response.ok) { throw new UserError( `Failed to search climate issues: ${response.statusText} (${response.status})` ); } const data = await response.json(); // Transform the data to include only necessary fields const transformedData = Array.isArray(data) ? data.map((issue) => transformIssue(issue)) : []; log.info("Climate issues search completed", { resultsCount: transformedData.length, }); // Get pagination info const totalCount = parseInt(response.headers.get("X-Total-Count") || "0", 10) || transformedData.length; const currentPage = args.page || 1; const perPage = args.per_page || 10; const totalPages = Math.ceil(totalCount / perPage); // Format the results in Markdown for better LLM presentation // Update the formatting in your execute method const formattedResults = transformedData .map((issue, index) => { return ` ISSUE #${index + 1}: "${issue.title}" ISSUE LINK: ${issue.url} ISSUE CREATED: ${formatDate(issue.created_at)} ISSUE STATE: ${issue.state} ISSUE LABELS: ${issue.labels.join(", ") || "None"} BELONGS TO PROJECT: "${issue.project.name}" PROJECT LINK: ${issue.project.repository_url} PROJECT LANGUAGE: ${issue.project.language || "Unknown"} PROJECT CATEGORY: ${issue.project.category || "Uncategorized"} PROJECT STARS: ${issue.project.stars} ${issue.body ? `ISSUE DESCRIPTION: ${issue.body}\n` : ""} `; }) .join("\n------------------------------\n"); // Add pagination information let paginationInfo = ""; if (transformedData.length > 0) { paginationInfo = `\n\n---\n\nShowing page ${currentPage} of ${totalPages} (${transformedData.length} of ${totalCount} total results)`; if (currentPage < totalPages) { paginationInfo += `\nUse \`page: ${ currentPage + 1 }\` to see more results.`; } } return { content: [ { type: "text", text: transformedData.length > 0 ? `# Found ${totalCount} Climate Issues\n\n${formattedResults}${paginationInfo}` : "No issues found matching your criteria. Try adjusting your search parameters.", }, ], }; } catch (error) { if (error instanceof UserError) { throw error; } const errorMessage = error instanceof Error ? error.message : String(error); throw new UserError(`Error searching climate issues: ${errorMessage}`); } }, });
  • index.ts:96-222 (handler)
    The execute function that implements the core logic: builds query params, fetches from API, transforms data, formats output in Markdown with pagination.
    execute: async (args, { log }) => { try { log.info("Searching for climate issues", { category: args.category, language: args.language, keyword: args.keyword, page: args.page, per_page: args.per_page, sort: args.sort, order: args.order, }); const params = new URLSearchParams(); if (args.category) { params.append("category", args.category); } if (args.language) { params.append("language", args.language); } if (args.keyword) { params.append("keyword", args.keyword); } if (args.page) { params.append("page", args.page.toString()); } if (args.per_page !== undefined) { params.append("per_page", args.per_page.toString()); } if (args.sort) { params.append("sort", args.sort); } if (args.order) { params.append("order", args.order); } const response = await fetch( `${API_BASE_URL}/issues?${params.toString()}` ); if (!response.ok) { throw new UserError( `Failed to search climate issues: ${response.statusText} (${response.status})` ); } const data = await response.json(); // Transform the data to include only necessary fields const transformedData = Array.isArray(data) ? data.map((issue) => transformIssue(issue)) : []; log.info("Climate issues search completed", { resultsCount: transformedData.length, }); // Get pagination info const totalCount = parseInt(response.headers.get("X-Total-Count") || "0", 10) || transformedData.length; const currentPage = args.page || 1; const perPage = args.per_page || 10; const totalPages = Math.ceil(totalCount / perPage); // Format the results in Markdown for better LLM presentation // Update the formatting in your execute method const formattedResults = transformedData .map((issue, index) => { return ` ISSUE #${index + 1}: "${issue.title}" ISSUE LINK: ${issue.url} ISSUE CREATED: ${formatDate(issue.created_at)} ISSUE STATE: ${issue.state} ISSUE LABELS: ${issue.labels.join(", ") || "None"} BELONGS TO PROJECT: "${issue.project.name}" PROJECT LINK: ${issue.project.repository_url} PROJECT LANGUAGE: ${issue.project.language || "Unknown"} PROJECT CATEGORY: ${issue.project.category || "Uncategorized"} PROJECT STARS: ${issue.project.stars} ${issue.body ? `ISSUE DESCRIPTION: ${issue.body}\n` : ""} `; }) .join("\n------------------------------\n"); // Add pagination information let paginationInfo = ""; if (transformedData.length > 0) { paginationInfo = `\n\n---\n\nShowing page ${currentPage} of ${totalPages} (${transformedData.length} of ${totalCount} total results)`; if (currentPage < totalPages) { paginationInfo += `\nUse \`page: ${ currentPage + 1 }\` to see more results.`; } } return { content: [ { type: "text", text: transformedData.length > 0 ? `# Found ${totalCount} Climate Issues\n\n${formattedResults}${paginationInfo}` : "No issues found matching your criteria. Try adjusting your search parameters.", }, ], }; } catch (error) { if (error instanceof UserError) { throw error; } const errorMessage = error instanceof Error ? error.message : String(error); throw new UserError(`Error searching climate issues: ${errorMessage}`); } },
  • Zod schema defining input parameters for category, language, keyword, pagination, sorting.
    parameters: z.object({ category: z .enum([ "Climate Change", "Energy Systems", "Emissions", "Consumption", "Biosphere", "Hydrosphere", "Sustainable Development", ]) .describe("Filter issues by project category") .optional(), language: z .enum([ "JavaScript", "TypeScript", "Python", "Java", "C#", "C++", "C", "Ruby", "Go", "Rust", "Swift", "Kotlin", "PHP", "HTML", "CSS", "Shell", "Dart", "Scala", "R", "Elixir", "Clojure", ]) .describe("Filter issues by programming language") .optional(), keyword: z .string() .describe( "Filter issues by project keyword (e.g., 'bug', 'help wanted', 'enhancement')" ) .optional(), page: z .number() .int() .min(1) .describe("Pagination page number (starts at 1)") .optional(), per_page: z .number() .int() .min(1) .default(10) .describe("Number of records per page (default: 10)") .optional(), sort: z .enum(["created_at", "updated_at", "stars"]) .default("created_at") .describe( "Field to sort by (default: created_at). Use created_at for most recent issues first." ) .optional(), order: z .enum(["asc", "desc"]) .default("desc") .describe( "Sort order (asc or desc) (default: desc for most recent first)" ) .optional(), }),
  • Helper function to transform raw API issue data into a standardized format, extracting labels, truncating body, nesting project info.
    function transformIssue(issue: any) { // Extract labels as strings const labels = Array.isArray(issue.labels) ? issue.labels.map((label: any) => typeof label === "string" ? label : label.name || label.toString() ) : []; return { id: issue.uuid, number: issue.number, title: issue.title, state: issue.state, author: issue.user?.login || issue.user?.name || "anonymous", labels: labels, comments_count: issue.comments_count || 0, created_at: issue.created_at, updated_at: issue.updated_at, url: issue.html_url, body: issue.body ? issue.body.substring(0, 200) + (issue.body.length > 200 ? "..." : "") : "", project: { name: issue.project?.name || "Unknown Project", description: issue.project?.description || "", language: issue.project?.language || "", category: issue.project?.category || "", stars: issue.project?.repository?.stargazers_count || 0, owner: issue.project?.repository?.owner?.login || issue.project?.repository?.owner || "unknown", repository_url: issue.project?.repository?.html_url || issue.project?.html_url || "", }, }; }
  • Helper function to format issue created_at dates into readable locale format.
    function formatDate(dateString: string | undefined): string { if (!dateString) return "Unknown date"; try { const date = new Date(dateString); return date.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric", }); } catch (e) { return dateString; } }

Other Tools

Related Tools

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/Codeshark-NET/climate-triage-mcp'

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