Skip to main content
Glama

Squad AI

insight.ts8 kB
import { z } from "zod"; import { chatToolHelperSchema, UserContext } from "./helpers/getUser.js"; import { squadClient } from "./lib/clients/squad.js"; import { InsightSourceEnum } from "./lib/openapi/squad/models/InsightSourceEnum.js"; import { CreateInsightRequestTypeEnum } from "./lib/openapi/squad/models/CreateInsightRequest.js"; export enum InsightTool { CreateInsight = "create_insight", ListInsights = "list_insights", GetInsight = "get_insight", DeleteInsight = "delete_insight", } // Schema definitions export const CreateInsightArgsSchema = z.object({ type: z .enum([ CreateInsightRequestTypeEnum.Feedback, CreateInsightRequestTypeEnum.Bug, CreateInsightRequestTypeEnum.FeatureRequest, ]) .describe( "The type of insight: 'Feedback' for customer feedback, 'Bug' for bug reports, or 'FeatureRequest' for feature requests.", ), title: z.string().describe("A brief title summarizing the insight"), description: z.string().describe("A short description of the insight"), }); export const createInsightTool = { name: InsightTool.CreateInsight, description: "Create a new insight entry. An insight is customer-generated feedback about your product, often from reviews, surveys, or questionnaires.", inputSchema: CreateInsightArgsSchema, }; export const createInsight = async ( context: UserContext, body: Record<string, unknown> | undefined, ): Promise<{ content: { type: "text"; text: string }[] }> => { try { const { orgId, workspaceId } = context; const safeBody = CreateInsightArgsSchema.parse(body); const res = await squadClient( context.jwt, ).createInsight({ orgId, workspaceId, createInsightRequest: { type: safeBody.type, title: safeBody.title, description: safeBody.description, organisationId: orgId, workspaceId: workspaceId, }, }); return { content: [ { type: "text", text: JSON.stringify(res), }, ], }; } catch (e) { console.error("error", e); throw e; } }; // Schema for listing insights export const ListInsightsArgsSchema = z.object({}); export const listInsightsTool = { name: InsightTool.ListInsights, description: "List all insights for the workspace. These insights are gathered from various sources, created by customers, and help understand how to improve the business.", inputSchema: ListInsightsArgsSchema, }; export const listInsights = async ( context: UserContext, ): Promise<{ content: { type: "text"; text: string }[] }> => { try { const { orgId, workspaceId } = context; const insights = await squadClient( context.jwt, ).listInsights({ orgId, workspaceId, }); if (insights.data.length === 0) { return { content: [ { type: "text", text: "No insight entries found.", }, ], }; } return { content: [ { type: "text", text: JSON.stringify(insights), }, ], }; } catch (e) { console.error("error", e); throw e; } }; // Schema for getting a single insight entry export const GetInsightArgsSchema = z.object({ insightId: z.string().describe("The ID of the insight entry to retrieve"), relationships: z .array(z.enum(["opportunities", "solutions", "outcomes"])) .optional() .describe("Show other entities that this insight is related to."), }); export const getInsightTool = { name: InsightTool.GetInsight, description: "Get details of a specific insight entry by ID. Insight entries are text documents that can be used as references or information sources.", inputSchema: GetInsightArgsSchema, }; export const getInsight = async ( context: UserContext, body: Record<string, unknown> | undefined, ): Promise<{ content: { type: "text"; text: string }[] }> => { try { const { orgId, workspaceId } = context; const safeBody = GetInsightArgsSchema.parse(body); // Build params conditionally - don't include relationships if not provided const insight = safeBody.relationships && safeBody.relationships.length > 0 ? await squadClient(context.jwt).getInsight({ orgId, workspaceId, insightId: safeBody.insightId, relationships: safeBody.relationships.join(","), }) : await squadClient(context.jwt).getInsight({ orgId, workspaceId, insightId: safeBody.insightId, }); return { content: [ { type: "text", text: JSON.stringify(insight), }, ], }; } catch (e) { console.error("error", e); throw e; } }; // Schema for deleting an insight entry export const DeleteInsightArgsSchema = z.object({ insightId: z.string().describe("The ID of the insight entry to delete"), }); export const deleteInsightTool = { name: InsightTool.DeleteInsight, description: "Delete an insight entry by ID.", inputSchema: DeleteInsightArgsSchema, }; export const deleteInsight = async ( context: UserContext, body: Record<string, unknown> | undefined, ): Promise<{ content: { type: "text"; text: string }[] }> => { try { const { orgId, workspaceId } = context; const safeBody = DeleteInsightArgsSchema.parse(body); const insightId = safeBody.insightId; const result = await squadClient( context.jwt, ).deleteInsight({ orgId, workspaceId, insightId, }); return { content: [ { type: "text", text: JSON.stringify(result), }, ], }; } catch (e) { console.error("error", e); throw e; } }; export const insightTools = [ createInsightTool, listInsightsTool, getInsightTool, deleteInsightTool, ]; export const runInsightTool = (name: string) => { const mapper = { [InsightTool.CreateInsight]: createInsight, [InsightTool.ListInsights]: listInsights, [InsightTool.GetInsight]: getInsight, [InsightTool.DeleteInsight]: deleteInsight, }; if (!mapper[name as keyof typeof mapper]) { return null; } return mapper[name as keyof typeof mapper]; }; const createInsightChatTool = CreateInsightArgsSchema.merge( chatToolHelperSchema({ defaultInProgressText: "Creating insight...", defaultCompletedText: "Insight created.", }), ); const listInsightsChatTool = ListInsightsArgsSchema.merge( chatToolHelperSchema({ defaultInProgressText: "Listing insights...", defaultCompletedText: "Insights listed.", }), ); const getInsightChatTool = GetInsightArgsSchema.merge( chatToolHelperSchema({ defaultInProgressText: "Getting insight...", defaultCompletedText: "Insight retrieved.", }), ); const deleteInsightChatTool = DeleteInsightArgsSchema.merge( chatToolHelperSchema({ defaultInProgressText: "Deleting insight...", defaultCompletedText: "Insight deleted.", }), ); export const vercelTool = (context: UserContext) => ({ [InsightTool.CreateInsight]: { description: createInsightTool.description, parameters: createInsightChatTool, execute: async (args: z.infer<typeof createInsightChatTool>) => await createInsight(context, args), }, [InsightTool.ListInsights]: { description: listInsightsTool.description, parameters: listInsightsChatTool, execute: async (args: z.infer<typeof listInsightsChatTool>) => await listInsights(context), }, [InsightTool.GetInsight]: { description: getInsightTool.description, parameters: getInsightChatTool, execute: async (args: z.infer<typeof getInsightChatTool>) => await getInsight(context, args), }, [InsightTool.DeleteInsight]: { description: deleteInsightTool.description, parameters: deleteInsightChatTool, execute: async (args: z.infer<typeof deleteInsightChatTool>) => await deleteInsight(context, args), }, });

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/the-basilisk-ai/squad-mcp'

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