@kaddo/mcp 3.88.2 → 3.88.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +52 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12295,7 +12295,7 @@ function buildJql(filters) {
12295
12295
  if (filters?.updatedAfter) clauses.push(`updated >= ${escapeJql(filters.updatedAfter)}`);
12296
12296
  if (filters?.search) clauses.push(`(summary ~ ${escapeJql(filters.search)} OR description ~ ${escapeJql(filters.search)})`);
12297
12297
  if (filters?.providerQuery) clauses.push(`(${filters.providerQuery})`);
12298
- return clauses.join(" AND ") || "ORDER BY updated DESC";
12298
+ return clauses.join(" AND ");
12299
12299
  }
12300
12300
  function normalizeBaseUrl(raw) {
12301
12301
  let url = raw.trim();
@@ -12306,6 +12306,26 @@ function authHeader(email, token) {
12306
12306
  const encoded = typeof Buffer !== "undefined" ? Buffer.from(`${email}:${token}`).toString("base64") : btoa(`${email}:${token}`);
12307
12307
  return `Basic ${encoded}`;
12308
12308
  }
12309
+ async function handleJiraResponse(res) {
12310
+ if (res.status === 401) throw integrationError("INTEGRATION_UNAUTHORIZED");
12311
+ if (res.status === 403) throw integrationError("INTEGRATION_FORBIDDEN");
12312
+ if (res.status === 404) throw integrationError("INTEGRATION_NOT_FOUND");
12313
+ if (res.status === 410) throw integrationError("INTEGRATION_UNAVAILABLE", "Jira API endpoint deprecated (410 Gone).");
12314
+ if (res.status === 429) throw integrationError("INTEGRATION_RATE_LIMITED");
12315
+ if (res.status >= 500) throw integrationError("INTEGRATION_UNAVAILABLE");
12316
+ if (!res.ok) {
12317
+ let detail = "";
12318
+ try {
12319
+ const body = await res.json();
12320
+ const msgs = body.errorMessages?.filter(Boolean) ?? [];
12321
+ const fieldErrs = body.errors ? Object.entries(body.errors).map(([k2, v]) => `${k2}: ${v}`) : [];
12322
+ detail = [...msgs, ...fieldErrs].join("; ");
12323
+ } catch {
12324
+ }
12325
+ throw integrationError("INTEGRATION_PROVIDER_ERROR", detail || `Jira responded with status ${res.status}.`);
12326
+ }
12327
+ return await res.json();
12328
+ }
12309
12329
  async function jiraFetch(baseUrl, path6, auth, timeoutMs, params) {
12310
12330
  const url = new URL(path6, baseUrl + "/");
12311
12331
  if (params) for (const [k2, v] of Object.entries(params)) url.searchParams.set(k2, v);
@@ -12317,14 +12337,26 @@ async function jiraFetch(baseUrl, path6, auth, timeoutMs, params) {
12317
12337
  headers: { Authorization: auth, Accept: "application/json" },
12318
12338
  signal: controller.signal
12319
12339
  });
12320
- if (res.status === 401) throw integrationError("INTEGRATION_UNAUTHORIZED");
12321
- if (res.status === 403) throw integrationError("INTEGRATION_FORBIDDEN");
12322
- if (res.status === 404) throw integrationError("INTEGRATION_NOT_FOUND");
12323
- if (res.status === 410) throw integrationError("INTEGRATION_UNAVAILABLE", "Jira API endpoint deprecated (410 Gone).");
12324
- if (res.status === 429) throw integrationError("INTEGRATION_RATE_LIMITED");
12325
- if (res.status >= 500) throw integrationError("INTEGRATION_UNAVAILABLE");
12326
- if (!res.ok) throw integrationError("INTEGRATION_PROVIDER_ERROR", `Jira responded with status ${res.status}.`);
12327
- return await res.json();
12340
+ return await handleJiraResponse(res);
12341
+ } catch (err) {
12342
+ if (err instanceof Error && err.name === "AbortError") throw integrationError("INTEGRATION_TIMEOUT");
12343
+ throw normalizeProviderError(err);
12344
+ } finally {
12345
+ clearTimeout(timer);
12346
+ }
12347
+ }
12348
+ async function jiraPost(baseUrl, path6, auth, timeoutMs, body) {
12349
+ const url = new URL(path6, baseUrl + "/");
12350
+ const controller = new AbortController();
12351
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
12352
+ try {
12353
+ const res = await fetch(url.toString(), {
12354
+ method: "POST",
12355
+ headers: { Authorization: auth, Accept: "application/json", "Content-Type": "application/json" },
12356
+ body: JSON.stringify(body),
12357
+ signal: controller.signal
12358
+ });
12359
+ return await handleJiraResponse(res);
12328
12360
  } catch (err) {
12329
12361
  if (err instanceof Error && err.name === "AbortError") throw integrationError("INTEGRATION_TIMEOUT");
12330
12362
  throw normalizeProviderError(err);
@@ -12443,18 +12475,19 @@ function createJiraAdapter() {
12443
12475
  const auth = authHeader(email, apiToken);
12444
12476
  const jql = buildJql(request.filters);
12445
12477
  const pageSize = Math.min(Math.max(1, request.pageSize ?? DEFAULT_PAGE_SIZE), 100);
12446
- const startAt = request.cursor ? Math.max(0, Number.parseInt(request.cursor, 10) || 0) : 0;
12478
+ const nextPageToken = request.cursor || void 0;
12447
12479
  try {
12448
- const data = await jiraFetch(baseUrl, "/rest/api/3/search/jql", auth, request.context.timeoutMs, {
12449
- jql: jql.startsWith("ORDER BY") ? jql : jql + " ORDER BY updated DESC",
12450
- startAt: String(startAt),
12451
- maxResults: String(pageSize),
12452
- fields: SEARCH_FIELDS
12453
- });
12480
+ const fullJql = jql ? jql + " ORDER BY updated DESC" : "updated >= -30d ORDER BY updated DESC";
12481
+ const body = {
12482
+ jql: fullJql,
12483
+ maxResults: pageSize,
12484
+ fields: SEARCH_FIELDS.split(",")
12485
+ };
12486
+ if (nextPageToken) body.nextPageToken = nextPageToken;
12487
+ const data = await jiraPost(baseUrl, "/rest/api/3/search/jql", auth, request.context.timeoutMs, body);
12454
12488
  const items = data.issues.map((issue) => normalizeIssue(issue, baseUrl, request.context.integrationId));
12455
- const nextStart = data.startAt + data.issues.length;
12456
- const hasMore = nextStart < data.total;
12457
- return { items, hasMore, ...hasMore ? { nextCursor: String(nextStart) } : {} };
12489
+ const hasMore = data.isLast === false;
12490
+ return { items, hasMore, ...hasMore && data.nextPageToken ? { nextCursor: data.nextPageToken } : {} };
12458
12491
  } catch (err) {
12459
12492
  throw normalizeProviderError(err);
12460
12493
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.88.2",
3
+ "version": "3.88.4",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {