@mgsoftwarebv/mcp-server-bridge 3.3.5 → 3.3.7

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.
package/README.md CHANGED
@@ -98,11 +98,11 @@ Use **get-teams** to list the providers you can act on and copy a `teamId`.
98
98
  - **get-teams** — list the provider teams (workspaces) you can act on; use a returned id as `teamId` on other tools
99
99
 
100
100
  ### Tickets, Customers & Projects
101
- - **get-tickets** — list tickets with filters (status, priority, project, customer, text query)
102
- - **get-ticket-by-id** — fetch one ticket with comment text, a full attachment listing (ids), and inline images (base64)
103
- - **create-ticket** — create a new ticket
104
- - **update-ticket** — update fields (title, description, status, priority, type, project, customer, assignee, estimated hours); `assigneeId: null` unassigns
105
- - **add-ticket-comment** — add a comment (plain text or TipTap JSON); `isInternal` for internal-only notes
101
+ - **get-tickets** — list tickets with filters (status, priority, project, customer, text query); each result includes the ticket ID (UUID) and ticket number
102
+ - **get-ticket-by-id** — fetch one ticket by UUID or ticket number, with comment text, a full attachment listing (ids), and inline images (base64)
103
+ - **create-ticket** — create a new ticket (returns UUID and ticket number)
104
+ - **update-ticket** — update fields (title, description, status, priority, type, project, customer, assignee, estimated hours); accepts UUID or ticket number; `assigneeId: null` unassigns
105
+ - **add-ticket-comment** — add a comment (plain text or TipTap JSON); accepts UUID or ticket number; `isInternal` for internal-only notes
106
106
  - **get-ticket-comments** — read all comments as plain text (author, internal flag, timestamp)
107
107
  - **get-ticket-attachment** — get a 1-hour signed download URL for any ticket/comment attachment (any file type)
108
108
  - **get-customers** — list/search customers
package/dist/index.js CHANGED
@@ -105508,6 +105508,10 @@ var teamIdProp = {
105508
105508
  type: "string",
105509
105509
  description: "Provider team ID. Optional when you belong to a single provider; required when you belong to several. Call get-teams to list the providers you can act on."
105510
105510
  };
105511
+ var ticketIdentifierProp = {
105512
+ type: "string",
105513
+ description: "Ticket ID (UUID) or ticket number (e.g. 2026-REFRO-116). Pass teamId when using a ticket number across multiple providers."
105514
+ };
105511
105515
  var TOOLS = [
105512
105516
  {
105513
105517
  name: "get-teams",
@@ -105520,7 +105524,7 @@ var TOOLS = [
105520
105524
  },
105521
105525
  {
105522
105526
  name: "get-tickets",
105523
- description: "Get tickets with optional filtering by status, priority, project, customer, tags, or search query. Each ticket includes its tags.",
105527
+ description: "Get tickets with optional filtering by status, priority, project, customer, tags, or search query. Each ticket includes its ID (UUID), ticket number, and tags.",
105524
105528
  inputSchema: {
105525
105529
  type: "object",
105526
105530
  properties: {
@@ -105567,12 +105571,12 @@ var TOOLS = [
105567
105571
  },
105568
105572
  {
105569
105573
  name: "get-ticket-by-id",
105570
- description: "Get a specific ticket by its ID, including tags, comment text and a full attachment listing (with ids). Images from ticket and comment attachments are downloaded and returned inline as base64. For non-image attachments, call get-ticket-attachment with the listed id to get a download URL.",
105574
+ description: "Get a specific ticket by its ID or ticket number, including tags, comment text and a full attachment listing (with ids). Images from ticket and comment attachments are downloaded and returned inline as base64. For non-image attachments, call get-ticket-attachment with the listed id to get a download URL.",
105571
105575
  inputSchema: {
105572
105576
  type: "object",
105573
105577
  properties: {
105574
105578
  teamId: teamIdProp,
105575
- id: { type: "string", description: "Ticket ID" }
105579
+ id: ticketIdentifierProp
105576
105580
  },
105577
105581
  required: ["id"]
105578
105582
  }
@@ -105642,7 +105646,7 @@ var TOOLS = [
105642
105646
  type: "object",
105643
105647
  properties: {
105644
105648
  teamId: teamIdProp,
105645
- id: { type: "string", description: "Ticket ID" },
105649
+ id: ticketIdentifierProp,
105646
105650
  title: { type: "string" },
105647
105651
  description: {
105648
105652
  type: "string",
@@ -105844,7 +105848,7 @@ var TOOLS = [
105844
105848
  type: "object",
105845
105849
  properties: {
105846
105850
  teamId: teamIdProp,
105847
- ticketId: { type: "string", description: "Ticket ID" },
105851
+ ticketId: ticketIdentifierProp,
105848
105852
  content: { type: "string", description: "Comment body" },
105849
105853
  isInternal: { type: "boolean", default: false }
105850
105854
  },
@@ -105858,7 +105862,7 @@ var TOOLS = [
105858
105862
  type: "object",
105859
105863
  properties: {
105860
105864
  teamId: teamIdProp,
105861
- ticketId: { type: "string", description: "Ticket ID" }
105865
+ ticketId: ticketIdentifierProp
105862
105866
  },
105863
105867
  required: ["ticketId"]
105864
105868
  }
@@ -105886,8 +105890,8 @@ var TOOLS = [
105886
105890
  properties: {
105887
105891
  teamId: teamIdProp,
105888
105892
  ticketId: {
105889
- type: "string",
105890
- description: "Ticket ID (UUID) to attach the file to."
105893
+ ...ticketIdentifierProp,
105894
+ description: "Ticket ID (UUID) or ticket number to attach the file to."
105891
105895
  },
105892
105896
  filePath: {
105893
105897
  type: "string",
@@ -106688,17 +106692,87 @@ async function resolveTeamScope(requestedTeamId) {
106688
106692
  }
106689
106693
 
106690
106694
  // src/tools/ticket-access.ts
106691
- function notFoundResponse(ticketId) {
106695
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
106696
+ function isUuid(value) {
106697
+ return UUID_REGEX.test(value);
106698
+ }
106699
+ function notFoundResponse(identifier) {
106692
106700
  return {
106693
106701
  content: [
106694
106702
  {
106695
106703
  type: "text",
106696
- text: `Ticket not found or no access: ${ticketId}. Call get-tickets to find the correct ticket.`
106704
+ text: `Ticket not found or no access: ${identifier}. Call get-tickets to find the correct ticket.`
106697
106705
  }
106698
106706
  ]
106699
106707
  };
106700
106708
  }
106709
+ function multipleMatchesResponse(identifier, matches) {
106710
+ const list = matches.map((t8) => `- **${t8.ticketNumber}** (ID: ${t8.id}): ${t8.title}`).join("\n");
106711
+ return {
106712
+ content: [
106713
+ {
106714
+ type: "text",
106715
+ text: `Multiple tickets match "${identifier}":
106716
+ ${list}
106717
+
106718
+ Pass a more specific ticket number or include \`teamId\` to disambiguate.`
106719
+ }
106720
+ ]
106721
+ };
106722
+ }
106723
+ var ticketLookupFields = {
106724
+ id: schema_exports.tickets.id,
106725
+ ticketNumber: schema_exports.tickets.ticketNumber,
106726
+ title: schema_exports.tickets.title
106727
+ };
106728
+ async function resolveTicketIdentifier(requestedTeamId, identifier) {
106729
+ if (isUuid(identifier)) {
106730
+ return { ok: true, id: identifier };
106731
+ }
106732
+ const scope = await resolveTeamScope(requestedTeamId);
106733
+ if (!scope.ok) return scope;
106734
+ const accessPredicate = buildTicketAccessPredicate(
106735
+ scope.teamIds,
106736
+ scope.projectIds,
106737
+ scope.customerIds
106738
+ );
106739
+ const baseFilters = [
106740
+ accessPredicate,
106741
+ eq(schema_exports.tickets.isDeleted, false)
106742
+ ];
106743
+ const exactMatches = await db.select(ticketLookupFields).from(schema_exports.tickets).where(
106744
+ and(
106745
+ ...baseFilters,
106746
+ sql`lower(${schema_exports.tickets.ticketNumber}) = lower(${identifier})`
106747
+ )
106748
+ ).limit(5);
106749
+ let matches = exactMatches;
106750
+ if (matches.length === 0) {
106751
+ matches = await db.select(ticketLookupFields).from(schema_exports.tickets).where(
106752
+ and(...baseFilters, ilike(schema_exports.tickets.ticketNumber, `%${identifier}%`))
106753
+ ).limit(5);
106754
+ }
106755
+ if (matches.length === 0) {
106756
+ return {
106757
+ ok: false,
106758
+ response: {
106759
+ content: [
106760
+ {
106761
+ type: "text",
106762
+ text: `No ticket found with number "${identifier}". Call get-tickets to search by title or keyword.`
106763
+ }
106764
+ ]
106765
+ }
106766
+ };
106767
+ }
106768
+ if (matches.length > 1) {
106769
+ return { ok: false, response: multipleMatchesResponse(identifier, matches) };
106770
+ }
106771
+ return { ok: true, id: matches[0].id };
106772
+ }
106701
106773
  async function loadAccessibleTicket(requestedTeamId, ticketId) {
106774
+ const resolved = await resolveTicketIdentifier(requestedTeamId, ticketId);
106775
+ if (!resolved.ok) return resolved;
106702
106776
  const scope = await resolveTeamScope(requestedTeamId);
106703
106777
  if (!scope.ok) return scope;
106704
106778
  const [ticket] = await db.select({
@@ -106712,7 +106786,7 @@ async function loadAccessibleTicket(requestedTeamId, ticketId) {
106712
106786
  priority: schema_exports.tickets.priority,
106713
106787
  type: schema_exports.tickets.type,
106714
106788
  assigneeId: schema_exports.tickets.assigneeId
106715
- }).from(schema_exports.tickets).where(eq(schema_exports.tickets.id, ticketId)).limit(1);
106789
+ }).from(schema_exports.tickets).where(eq(schema_exports.tickets.id, resolved.id)).limit(1);
106716
106790
  if (!ticket) return { ok: false, response: notFoundResponse(ticketId) };
106717
106791
  const hasAccess = scope.teamIds.includes(ticket.teamId) || !!ticket.projectId && scope.projectIds.includes(ticket.projectId) || !!ticket.customerId && scope.customerIds.includes(ticket.customerId);
106718
106792
  if (!hasAccess) return { ok: false, response: notFoundResponse(ticketId) };
@@ -119809,6 +119883,10 @@ function tiptapToPlainText(content) {
119809
119883
  if (doc?.type !== "doc" || !Array.isArray(doc.content)) return content;
119810
119884
  return doc.content.map(renderNode).join("").trim();
119811
119885
  }
119886
+ function descriptionPlainText(content) {
119887
+ const text3 = tiptapToPlainText(content).trim();
119888
+ return text3 || null;
119889
+ }
119812
119890
 
119813
119891
  // src/tools/ticket-comments.ts
119814
119892
  async function handleAddTicketComment(input) {
@@ -120462,6 +120540,7 @@ async function handleGetTickets(input) {
120462
120540
  ${rows.map((t8) => {
120463
120541
  const ticketTags2 = tagsByTicket.get(t8.id) ?? [];
120464
120542
  return `**${t8.ticketNumber}**: ${t8.title}
120543
+ ID: ${t8.id}
120465
120544
  Status: ${t8.status} | Priority: ${t8.priority}
120466
120545
  ${ticketTags2.length > 0 ? `Tags: ${formatTagList(ticketTags2)}
120467
120546
  ` : ""}${t8.projectName ? `Project: ${t8.projectName}
@@ -120475,11 +120554,13 @@ ${ticketTags2.length > 0 ? `Tags: ${formatTagList(ticketTags2)}
120475
120554
  }
120476
120555
  async function handleGetTicketById(input) {
120477
120556
  const { id } = input;
120557
+ const resolved = await resolveTicketIdentifier(input.teamId, id);
120558
+ if (!resolved.ok) return resolved.response;
120478
120559
  const scope = await resolveTeamScope(input.teamId);
120479
120560
  if (!scope.ok) return scope.response;
120480
120561
  const { teamIds, projectIds, customerIds } = scope;
120481
120562
  const ticketRow = await db.query.tickets.findFirst({
120482
- where: eq(schema_exports.tickets.id, id),
120563
+ where: eq(schema_exports.tickets.id, resolved.id),
120483
120564
  with: {
120484
120565
  project: { columns: { id: true, name: true } },
120485
120566
  customer: { columns: { id: true, name: true } },
@@ -120587,6 +120668,7 @@ ${text3.split("\n").map((l4) => ` ${l4}`).join("\n")}`;
120587
120668
  const tagsLine = ticketTags2.length > 0 ? `Tags: ${formatTagList(ticketTags2)}
120588
120669
  ` : `Tags: (none)
120589
120670
  `;
120671
+ const descriptionText = descriptionPlainText(ticketRow.description);
120590
120672
  const content = [
120591
120673
  {
120592
120674
  type: "text",
@@ -120599,7 +120681,7 @@ Status: ${ticketRow.status}
120599
120681
  Priority: ${ticketRow.priority}
120600
120682
  Type: ${ticketRow.type}
120601
120683
  ${ticketRow.dueDate ? `Deadline: ${new Date(ticketRow.dueDate).toLocaleDateString()}
120602
- ` : ""}${ticketRow.description ? `Description: ${tiptapToPlainText(ticketRow.description)}
120684
+ ` : ""}${descriptionText ? `Description: ${descriptionText}
120603
120685
  ` : ""}${ticketRow.project?.name ? `Project: ${ticketRow.project.name}
120604
120686
  ` : ""}${ticketRow.customer?.name ? `Customer: ${ticketRow.customer.name}
120605
120687
  ` : ""}` + tagsLine + assigneeLine + requesterLine + `Created: ${new Date(ticketRow.createdAt).toLocaleDateString()}
@@ -120743,7 +120825,7 @@ async function handleCreateTicket(input) {
120743
120825
  teamId: resolvedTeamId,
120744
120826
  ticketNumber,
120745
120827
  title,
120746
- description: description ?? null,
120828
+ description: ensureTipTapFormat(description),
120747
120829
  status,
120748
120830
  priority,
120749
120831
  type,
@@ -120786,7 +120868,7 @@ async function handleCreateTicket(input) {
120786
120868
  text: `\u2705 **Ticket Created Successfully!**
120787
120869
 
120788
120870
  Ticket Number: **${created.ticketNumber}**
120789
- ID: ${created.id}
120871
+ Ticket id: ${created.id}
120790
120872
  Title: ${title}
120791
120873
  Status: ${status}
120792
120874
  Priority: ${priority}