@kepler-project/almanac
Advanced tools
+216
-92
@@ -134,2 +134,6 @@ #!/usr/bin/env node | ||
| function shouldFallbackToRest(error) { | ||
| return String(error?.message || error || "").includes("gRPC "); | ||
| } | ||
| async function fetchJson(pathname, { method = "GET", query = {}, body = undefined, auth = true, _retried = false } = {}) { | ||
@@ -175,3 +179,3 @@ const apiBase = authBaseUrlFromGrpcEndpoint(GRPC_ENDPOINT); | ||
| const server = new McpServer({ name: "kepler-almanac", version: "0.2.7" }); | ||
| const server = new McpServer({ name: "kepler-almanac", version: "0.2.8" }); | ||
@@ -233,22 +237,37 @@ function jsonResult(data) { | ||
| }, async (a) => { | ||
| const clients = await getGrpcClients(); | ||
| const response = await grpcUnary(clients.communications, "searchCommunications", { | ||
| query: "", | ||
| accountId: a.account_id || "", | ||
| teamIds: [], | ||
| customerName: a.participant_name || "", | ||
| customerNames: a.customer_names || [], | ||
| commType: a.type || "", | ||
| days: 0, | ||
| limit: a.limit ?? 50, | ||
| offset: 0, | ||
| direction: "", | ||
| sentAfter: a.start_date || "", | ||
| sentBefore: a.end_date || "", | ||
| include: [], | ||
| }).catch((e) => { throw grpcError(e); }); | ||
| return jsonResult({ | ||
| results: response.results, | ||
| ...paginationTotals(response), | ||
| }); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| const response = await grpcUnary(clients.communications, "searchCommunications", { | ||
| query: "", | ||
| accountId: a.account_id || "", | ||
| teamIds: [], | ||
| customerName: a.participant_name || "", | ||
| customerNames: a.customer_names || [], | ||
| commType: a.type || "", | ||
| days: 0, | ||
| limit: a.limit ?? 50, | ||
| offset: 0, | ||
| direction: "", | ||
| sentAfter: a.start_date || "", | ||
| sentBefore: a.end_date || "", | ||
| include: [], | ||
| }).catch((e) => { throw grpcError(e); }); | ||
| return jsonResult({ | ||
| results: response.results, | ||
| ...paginationTotals(response), | ||
| }); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/communications/search", { | ||
| query: { | ||
| account_id: a.account_id, | ||
| customer_name: a.participant_name, | ||
| customer_names: a.customer_names?.join(","), | ||
| type: a.type, | ||
| sent_after: a.start_date, | ||
| sent_before: a.end_date, | ||
| limit: a.limit ?? 50, | ||
| }, | ||
| })); | ||
| } | ||
| }); | ||
@@ -262,13 +281,28 @@ | ||
| if (!briefId) throw new Error("brief_id or account_id is required"); | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.briefs, "getBrief", { briefId, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.briefs, "getBrief", { briefId, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/briefs/${encodeURIComponent(briefId)}`)); | ||
| } | ||
| }); | ||
| server.tool("almanac_get_communication_detail", { id: z.string() }, async ({ id }) => { | ||
| const clients = await getGrpcClients(); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.communications, "getCall", { callId: id }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!String(error.message).includes("NOT_FOUND")) throw error; | ||
| return jsonResult(await grpcUnary(clients.communications, "getEmail", { emailId: id }).catch((e) => { throw grpcError(e); })); | ||
| if (!String(error.message).includes("NOT_FOUND") && !shouldFallbackToRest(error)) throw error; | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.communications, "getEmail", { emailId: id }).catch((e) => { throw grpcError(e); })); | ||
| } catch (inner) { | ||
| if (!shouldFallbackToRest(inner)) throw inner; | ||
| try { | ||
| return jsonResult(await fetchJson(`/v1/communications/calls/${encodeURIComponent(id)}`)); | ||
| } catch { | ||
| return jsonResult(await fetchJson(`/v1/communications/emails/${encodeURIComponent(id)}`)); | ||
| } | ||
| } | ||
| } | ||
@@ -283,4 +317,9 @@ }); | ||
| if (!cid) throw new Error("communication_id or id is required"); | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getRawContent", { communicationId: cid }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getRawContent", { communicationId: cid }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/communications/${encodeURIComponent(cid)}/raw-content`)); | ||
| } | ||
| }); | ||
@@ -298,14 +337,30 @@ | ||
| }, async (a) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "semanticSearchCommunications", { | ||
| query: a.query, | ||
| customerNames: a.customer_names || [], | ||
| accountIds: a.account_ids || [], | ||
| commType: a.type || "", | ||
| sentAfter: a.sent_after || "", | ||
| sentBefore: a.sent_before || "", | ||
| minSimilarity: a.min_similarity ?? 0, | ||
| limit: a.limit ?? 20, | ||
| enrich: false, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "semanticSearchCommunications", { | ||
| query: a.query, | ||
| customerNames: a.customer_names || [], | ||
| accountIds: a.account_ids || [], | ||
| commType: a.type || "", | ||
| sentAfter: a.sent_after || "", | ||
| sentBefore: a.sent_before || "", | ||
| minSimilarity: a.min_similarity ?? 0, | ||
| limit: a.limit ?? 20, | ||
| enrich: false, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/communications/semantic-search", { | ||
| query: { | ||
| q: a.query, | ||
| account_ids: a.account_ids?.join(","), | ||
| customer_names: a.customer_names?.join(","), | ||
| type: a.type, | ||
| sent_after: a.sent_after, | ||
| sent_before: a.sent_before, | ||
| min_similarity: a.min_similarity, | ||
| limit: a.limit ?? 20, | ||
| }, | ||
| })); | ||
| } | ||
| }); | ||
@@ -318,18 +373,33 @@ | ||
| }, async ({ query, min_similarity = 0.6, limit = 10 }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "semanticSearchGaps", { | ||
| query, | ||
| minSimilarity: min_similarity, | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "semanticSearchGaps", { | ||
| query, | ||
| minSimilarity: min_similarity, | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/gaps/semantic-search", { query: { q: query, min_similarity, limit } })); | ||
| } | ||
| }); | ||
| server.tool("almanac_get_account_gaps", { account_id: z.string() }, async ({ account_id }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getAccountGaps", { accountId: account_id, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getAccountGaps", { accountId: account_id, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/gaps/accounts/${encodeURIComponent(account_id)}`)); | ||
| } | ||
| }); | ||
| server.tool("almanac_get_opportunity_gaps", { opportunity_id: z.string() }, async ({ opportunity_id }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getOpportunityGaps", { opportunityId: opportunity_id }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getOpportunityGaps", { opportunityId: opportunity_id }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/gaps/opportunities/${encodeURIComponent(opportunity_id)}`)); | ||
| } | ||
| }); | ||
@@ -343,14 +413,31 @@ | ||
| }, async (a) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchGaps", { | ||
| query: a.query || "", | ||
| productArea: a.product_area || "", | ||
| minAccountCount: a.min_account_count ?? 0, | ||
| limit: a.limit ?? 25, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchGaps", { | ||
| query: a.query || "", | ||
| productArea: a.product_area || "", | ||
| minAccountCount: a.min_account_count ?? 0, | ||
| limit: a.limit ?? 25, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/gaps/search", { | ||
| query: { | ||
| q: a.query, | ||
| product_area: a.product_area, | ||
| min_account_count: a.min_account_count ?? 0, | ||
| limit: a.limit ?? 25, | ||
| }, | ||
| })); | ||
| } | ||
| }); | ||
| server.tool("sf_get_account", { account_id: z.string() }, async ({ account_id }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.salesforce, "getAccount", { accountId: account_id, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.salesforce, "getAccount", { accountId: account_id, enrich: false }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/salesforce/accounts/${encodeURIComponent(account_id)}`)); | ||
| } | ||
| }); | ||
@@ -365,12 +452,25 @@ | ||
| }, async (a) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.communications, "getTeamCommunications", { | ||
| managerEmail: a.manager_email, | ||
| startAt: a.start_at || "", | ||
| endAt: a.end_at || "", | ||
| commType: a.type || "", | ||
| scope: "", | ||
| limit: a.limit ?? 500, | ||
| cursor: "", | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.communications, "getTeamCommunications", { | ||
| managerEmail: a.manager_email, | ||
| startAt: a.start_at || "", | ||
| endAt: a.end_at || "", | ||
| commType: a.type || "", | ||
| scope: "", | ||
| limit: a.limit ?? 500, | ||
| cursor: "", | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/communications/teams/search", { | ||
| query: { | ||
| manager_email: a.manager_email, | ||
| start_at: a.start_at, | ||
| end_at: a.end_at, | ||
| type: a.type, | ||
| limit: a.limit ?? 500, | ||
| }, | ||
| })); | ||
| } | ||
| }); | ||
@@ -384,9 +484,16 @@ | ||
| }, async ({ query, space_key, min_similarity = 0.3, limit = 10 }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchConfluence", { | ||
| query, | ||
| spaceKey: space_key || "", | ||
| minSimilarity: min_similarity, | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchConfluence", { | ||
| query, | ||
| spaceKey: space_key || "", | ||
| minSimilarity: min_similarity, | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/knowledge/confluence/search", { | ||
| query: { q: query, space_key, min_similarity, limit }, | ||
| })); | ||
| } | ||
| }); | ||
@@ -398,7 +505,12 @@ | ||
| }, async ({ page_id, max_chars }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getConfluencePage", { | ||
| pageId: page_id, | ||
| maxChars: max_chars ?? 0, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getConfluencePage", { | ||
| pageId: page_id, | ||
| maxChars: max_chars ?? 0, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/knowledge/confluence/pages/${encodeURIComponent(page_id)}`, { query: { max_chars } })); | ||
| } | ||
| }); | ||
@@ -412,16 +524,28 @@ | ||
| }, async ({ query, project_key, sources, limit = 10 }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchJira", { | ||
| query, | ||
| sources: sources || (project_key ? [project_key] : []), | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "searchJira", { | ||
| query, | ||
| sources: sources || (project_key ? [project_key] : []), | ||
| limit, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson("/v1/knowledge/jira/search", { | ||
| query: { q: query, project_key, limit }, | ||
| })); | ||
| } | ||
| }); | ||
| server.tool("jira_get_issue", { issue_key: z.string() }, async ({ issue_key }) => { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getJiraIssue", { | ||
| issueKey: issue_key, | ||
| enrich: false, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| try { | ||
| const clients = await getGrpcClients(); | ||
| return jsonResult(await grpcUnary(clients.knowledge, "getJiraIssue", { | ||
| issueKey: issue_key, | ||
| enrich: false, | ||
| }).catch((e) => { throw grpcError(e); })); | ||
| } catch (error) { | ||
| if (!shouldFallbackToRest(error)) throw error; | ||
| return jsonResult(await fetchJson(`/v1/knowledge/jira/issues/${encodeURIComponent(issue_key)}`)); | ||
| } | ||
| }); | ||
@@ -428,0 +552,0 @@ |
+1
-1
| { | ||
| "name": "@kepler-project/almanac", | ||
| "version": "0.2.7", | ||
| "version": "0.2.8", | ||
| "description": "Kepler Almanac MCP server.", | ||
@@ -5,0 +5,0 @@ "license": "UNLICENSED", |
42843
10.85%503
32.37%