@mgsoftwarebv/mcp-server-bridge 3.3.6 → 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) {
106700
+ return {
106701
+ content: [
106702
+ {
106703
+ type: "text",
106704
+ text: `Ticket not found or no access: ${identifier}. Call get-tickets to find the correct ticket.`
106705
+ }
106706
+ ]
106707
+ };
106708
+ }
106709
+ function multipleMatchesResponse(identifier, matches) {
106710
+ const list = matches.map((t8) => `- **${t8.ticketNumber}** (ID: ${t8.id}): ${t8.title}`).join("\n");
106692
106711
  return {
106693
106712
  content: [
106694
106713
  {
106695
106714
  type: "text",
106696
- text: `Ticket not found or no access: ${ticketId}. Call get-tickets to find the correct ticket.`
106715
+ text: `Multiple tickets match "${identifier}":
106716
+ ${list}
106717
+
106718
+ Pass a more specific ticket number or include \`teamId\` to disambiguate.`
106697
106719
  }
106698
106720
  ]
106699
106721
  };
106700
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) };
@@ -120466,6 +120540,7 @@ async function handleGetTickets(input) {
120466
120540
  ${rows.map((t8) => {
120467
120541
  const ticketTags2 = tagsByTicket.get(t8.id) ?? [];
120468
120542
  return `**${t8.ticketNumber}**: ${t8.title}
120543
+ ID: ${t8.id}
120469
120544
  Status: ${t8.status} | Priority: ${t8.priority}
120470
120545
  ${ticketTags2.length > 0 ? `Tags: ${formatTagList(ticketTags2)}
120471
120546
  ` : ""}${t8.projectName ? `Project: ${t8.projectName}
@@ -120479,11 +120554,13 @@ ${ticketTags2.length > 0 ? `Tags: ${formatTagList(ticketTags2)}
120479
120554
  }
120480
120555
  async function handleGetTicketById(input) {
120481
120556
  const { id } = input;
120557
+ const resolved = await resolveTicketIdentifier(input.teamId, id);
120558
+ if (!resolved.ok) return resolved.response;
120482
120559
  const scope = await resolveTeamScope(input.teamId);
120483
120560
  if (!scope.ok) return scope.response;
120484
120561
  const { teamIds, projectIds, customerIds } = scope;
120485
120562
  const ticketRow = await db.query.tickets.findFirst({
120486
- where: eq(schema_exports.tickets.id, id),
120563
+ where: eq(schema_exports.tickets.id, resolved.id),
120487
120564
  with: {
120488
120565
  project: { columns: { id: true, name: true } },
120489
120566
  customer: { columns: { id: true, name: true } },
@@ -120791,7 +120868,7 @@ async function handleCreateTicket(input) {
120791
120868
  text: `\u2705 **Ticket Created Successfully!**
120792
120869
 
120793
120870
  Ticket Number: **${created.ticketNumber}**
120794
- ID: ${created.id}
120871
+ Ticket id: ${created.id}
120795
120872
  Title: ${title}
120796
120873
  Status: ${status}
120797
120874
  Priority: ${priority}