UNPKG

@access-mcp/affinity-groups

Version:

MCP server for ACCESS-CI Affinity Groups API

227 lines (226 loc) 8.35 kB
import { BaseAccessServer, handleApiError, sanitizeGroupId, } from "@access-mcp/shared"; export class AffinityGroupsServer extends BaseAccessServer { constructor() { super("access-mcp-affinity-groups", "0.3.0"); } getTools() { return [ { name: "list_affinity_groups", description: "List all ACCESS-CI affinity groups", inputSchema: { type: "object", properties: {}, required: [], }, }, { name: "get_affinity_group", description: "Get information about a specific ACCESS-CI affinity group", inputSchema: { type: "object", properties: { group_id: { type: "string", description: "The affinity group ID (e.g., aici.access-ci.org)", }, }, required: ["group_id"], }, }, { name: "get_affinity_group_events", description: "Get events and trainings for a specific ACCESS-CI affinity group", inputSchema: { type: "object", properties: { group_id: { type: "string", description: "The affinity group ID (e.g., aici.access-ci.org)", }, }, required: ["group_id"], }, }, { name: "get_affinity_group_kb", description: "Get knowledge base resources for a specific ACCESS-CI affinity group", inputSchema: { type: "object", properties: { group_id: { type: "string", description: "The affinity group ID (e.g., aici.access-ci.org)", }, }, required: ["group_id"], }, }, ]; } getResources() { return [ { uri: "accessci://affinity-groups", name: "ACCESS-CI Affinity Groups", description: "Information about ACCESS-CI affinity groups, their events, and knowledge base resources", mimeType: "application/json", }, ]; } async handleToolCall(request) { const { name, arguments: args = {} } = request.params; try { switch (name) { case "list_affinity_groups": return await this.listAffinityGroups(); case "get_affinity_group": if (!args.group_id) { throw new Error("group_id parameter is required"); } return await this.getAffinityGroup(args.group_id); case "get_affinity_group_events": if (!args.group_id) { throw new Error("group_id parameter is required"); } return await this.getAffinityGroupEvents(args.group_id); case "get_affinity_group_kb": if (!args.group_id) { throw new Error("group_id parameter is required"); } return await this.getAffinityGroupKB(args.group_id); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: "text", text: `Error: ${handleApiError(error)}`, }, ], }; } } async handleResourceRead(request) { const { uri } = request.params; if (uri === "accessci://affinity-groups") { return { contents: [ { uri, mimeType: "text/plain", text: "ACCESS-CI Affinity Groups API - Use the available tools to query specific groups, events, and knowledge base resources.", }, ], }; } throw new Error(`Unknown resource: ${uri}`); } async getAffinityGroup(groupId) { const sanitizedId = sanitizeGroupId(groupId); const response = await this.httpClient.get(`/1.1/affinity_groups/${sanitizedId}`); // Check if response data exists if (!response.data) { return { content: [ { type: "text", text: `No data found for affinity group ID: ${groupId}`, }, ], }; } // Clean up the response data const cleanData = Array.isArray(response.data) ? response.data.map((group) => ({ title: group?.title, description: group?.description ?.replace(/<[^>]*>/g, "") .replace(/\\n/g, "\n") .trim(), coordinator: group?.coordinator_name, category: group?.field_affinity_group_category, slack_link: group?.slack_link, support_url: group?.url, ask_ci_forum: group?.field_ask_ci_locale, })) : response.data; return { content: [ { type: "text", text: JSON.stringify(cleanData, null, 2), }, ], }; } async getAffinityGroupEvents(groupId) { const sanitizedId = sanitizeGroupId(groupId); const response = await this.httpClient.get(`/1.1/events/ag/${sanitizedId}`); return { content: [ { type: "text", text: JSON.stringify(response.data, null, 2), }, ], }; } async getAffinityGroupKB(groupId) { const sanitizedId = sanitizeGroupId(groupId); const response = await this.httpClient.get(`/1.0/kb/${sanitizedId}`); // Check for empty array response if (Array.isArray(response.data) && response.data.length === 0) { return { content: [ { type: "text", text: "No knowledge base resources found for this affinity group", }, ], }; } return { content: [ { type: "text", text: JSON.stringify(response.data, null, 2), }, ], }; } async listAffinityGroups() { const response = await this.httpClient.get("/1.1/affinity_groups/all"); // Clean up the response data for better readability const cleanData = Array.isArray(response.data) ? response.data.map((group) => ({ id: group.field_group_id || group.nid, // Use field_group_id if available nid: group.nid, title: group.title, description: group.description ?.replace(/<[^>]*>/g, "") .replace(/\\n/g, "\n") .trim(), coordinator: group.coordinator_name, category: group.field_affinity_group_category, slack_link: group.slack_link, support_url: group.url, ask_ci_forum: group.field_ask_ci_locale, })) : response.data; return { content: [ { type: "text", text: JSON.stringify({ total_groups: Array.isArray(cleanData) ? cleanData.length : 0, groups: cleanData, }, null, 2), }, ], }; } }