@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 +5 -5
- package/dist/index.js +90 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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: `
|
|
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,
|
|
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
|
-
|
|
120871
|
+
Ticket id: ${created.id}
|
|
120795
120872
|
Title: ${title}
|
|
120796
120873
|
Status: ${status}
|
|
120797
120874
|
Priority: ${priority}
|