@promptprojectmanager/mcp-server 2.8.6 → 2.8.8
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/dist/index.js +106 -193
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -346,22 +346,16 @@ async function startServer(config, convexClient) {
|
|
|
346
346
|
const dynamicTicketTools = [];
|
|
347
347
|
for (const workspaceSlug of workspaceSlugs) {
|
|
348
348
|
dynamicTicketTools.push({
|
|
349
|
-
name: `${workspaceSlug}:tickets:
|
|
350
|
-
description: `
|
|
349
|
+
name: `${workspaceSlug}:tickets:open`,
|
|
350
|
+
description: `Open the next ticket from the "${workspaceSlug}" workspace queue and move it to working status. Optionally specify a ticket number or slug.`,
|
|
351
351
|
workspaceSlug,
|
|
352
|
-
type: "
|
|
352
|
+
type: "open"
|
|
353
353
|
});
|
|
354
354
|
dynamicTicketTools.push({
|
|
355
|
-
name: `${workspaceSlug}:tickets:
|
|
356
|
-
description: `
|
|
355
|
+
name: `${workspaceSlug}:tickets:work`,
|
|
356
|
+
description: `Resume work on a ticket in the "${workspaceSlug}" workspace. Returns ticket content and all progress messages for context recovery.`,
|
|
357
357
|
workspaceSlug,
|
|
358
|
-
type: "
|
|
359
|
-
});
|
|
360
|
-
dynamicTicketTools.push({
|
|
361
|
-
name: `${workspaceSlug}:tickets:working`,
|
|
362
|
-
description: `List all tickets currently being worked on in the "${workspaceSlug}" workspace`,
|
|
363
|
-
workspaceSlug,
|
|
364
|
-
type: "working"
|
|
358
|
+
type: "work"
|
|
365
359
|
});
|
|
366
360
|
dynamicTicketTools.push({
|
|
367
361
|
name: `${workspaceSlug}:tickets:close`,
|
|
@@ -375,12 +369,6 @@ async function startServer(config, convexClient) {
|
|
|
375
369
|
workspaceSlug,
|
|
376
370
|
type: "message"
|
|
377
371
|
});
|
|
378
|
-
dynamicTicketTools.push({
|
|
379
|
-
name: `${workspaceSlug}:tickets:get`,
|
|
380
|
-
description: `Get a specific ticket from the "${workspaceSlug}" workspace by number or slug`,
|
|
381
|
-
workspaceSlug,
|
|
382
|
-
type: "get"
|
|
383
|
-
});
|
|
384
372
|
dynamicTicketTools.push({
|
|
385
373
|
name: `${workspaceSlug}:tickets:create`,
|
|
386
374
|
description: `Create a new ticket in the "${workspaceSlug}" workspace queue`,
|
|
@@ -423,7 +411,7 @@ async function startServer(config, convexClient) {
|
|
|
423
411
|
name: st.name,
|
|
424
412
|
description: st.description
|
|
425
413
|
}));
|
|
426
|
-
const ticketPromptSchemas = dynamicTicketTools.
|
|
414
|
+
const ticketPromptSchemas = dynamicTicketTools.map((tt) => ({
|
|
427
415
|
name: tt.name,
|
|
428
416
|
description: tt.description
|
|
429
417
|
}));
|
|
@@ -453,29 +441,33 @@ async function startServer(config, convexClient) {
|
|
|
453
441
|
};
|
|
454
442
|
}
|
|
455
443
|
const ticketTool = dynamicTicketTools.find((tt) => tt.name === promptName);
|
|
456
|
-
const
|
|
457
|
-
if (ticketTool ||
|
|
444
|
+
const ticketOpenMatch = promptName.match(/^(.+):tickets:open\s+(.+)$/);
|
|
445
|
+
if (ticketTool || ticketOpenMatch) {
|
|
458
446
|
let promptContent;
|
|
459
447
|
let description;
|
|
460
|
-
if (
|
|
461
|
-
const workspaceSlug =
|
|
462
|
-
const ticketArg =
|
|
463
|
-
description = `
|
|
464
|
-
promptContent = `
|
|
465
|
-
|
|
466
|
-
Call the \`${workspaceSlug}:tickets:
|
|
467
|
-
} else if (ticketTool.type === "
|
|
448
|
+
if (ticketOpenMatch) {
|
|
449
|
+
const workspaceSlug = ticketOpenMatch[1];
|
|
450
|
+
const ticketArg = ticketOpenMatch[2].trim();
|
|
451
|
+
description = `Open ticket "${ticketArg}" from "${workspaceSlug}"`;
|
|
452
|
+
promptContent = `Open ticket "${ticketArg}" from the "${workspaceSlug}" workspace queue and move it to working status.
|
|
453
|
+
|
|
454
|
+
Call the \`${workspaceSlug}:tickets:open\` tool with ticketSlug: "${ticketArg}".`;
|
|
455
|
+
} else if (ticketTool.type === "open") {
|
|
468
456
|
description = ticketTool.description;
|
|
469
|
-
promptContent = `
|
|
457
|
+
promptContent = `Open the next ticket from the "${ticketTool.workspaceSlug}" workspace queue and move it to working status.
|
|
458
|
+
|
|
459
|
+
Call the \`${ticketTool.name}\` tool to get the next ticket.
|
|
470
460
|
|
|
471
|
-
|
|
472
|
-
} else if (ticketTool.type === "
|
|
461
|
+
You can also specify a ticket: /ppm:${ticketTool.workspaceSlug}:tickets:open <number-or-slug>`;
|
|
462
|
+
} else if (ticketTool.type === "work") {
|
|
473
463
|
description = ticketTool.description;
|
|
474
|
-
promptContent = `
|
|
464
|
+
promptContent = `Resume work on a ticket in the "${ticketTool.workspaceSlug}" workspace.
|
|
465
|
+
|
|
466
|
+
Call the \`${ticketTool.name}\` tool to get ticket content and all progress messages for context recovery.
|
|
475
467
|
|
|
476
|
-
|
|
468
|
+
If no ticket slug is provided, returns the first working ticket (by startedAt).
|
|
477
469
|
|
|
478
|
-
You can also specify a ticket: /ppm:${ticketTool.workspaceSlug}:tickets:
|
|
470
|
+
You can also specify a ticket: /ppm:${ticketTool.workspaceSlug}:tickets:work <number-or-slug>`;
|
|
479
471
|
} else if (ticketTool.type === "create") {
|
|
480
472
|
description = ticketTool.description;
|
|
481
473
|
promptContent = `Create a new ticket in the "${ticketTool.workspaceSlug}" workspace queue.
|
|
@@ -503,9 +495,19 @@ The user provides **instructions** (not raw content). You interpret those instru
|
|
|
503
495
|
- "just the tasks from this file" \u2192 Extract only task items
|
|
504
496
|
|
|
505
497
|
Call the \`${ticketTool.name}\` tool with the final generated content.`;
|
|
498
|
+
} else if (ticketTool.type === "close") {
|
|
499
|
+
description = ticketTool.description;
|
|
500
|
+
promptContent = `Close a working ticket in the "${ticketTool.workspaceSlug}" workspace.
|
|
501
|
+
|
|
502
|
+
Call the \`${ticketTool.name}\` tool with the ticket number or slug.`;
|
|
503
|
+
} else if (ticketTool.type === "message") {
|
|
504
|
+
description = ticketTool.description;
|
|
505
|
+
promptContent = `Add a progress message to a working or closed ticket in the "${ticketTool.workspaceSlug}" workspace.
|
|
506
|
+
|
|
507
|
+
Call the \`${ticketTool.name}\` tool with the ticket number/slug and your message.`;
|
|
506
508
|
} else {
|
|
507
509
|
description = ticketTool.description;
|
|
508
|
-
promptContent = `
|
|
510
|
+
promptContent = `Use the \`${ticketTool.name}\` tool.`;
|
|
509
511
|
}
|
|
510
512
|
return {
|
|
511
513
|
description,
|
|
@@ -538,10 +540,10 @@ Call the \`${ticketTool.name}\` tool with the final generated content.`;
|
|
|
538
540
|
description: st.description,
|
|
539
541
|
inputSchema: st.inputSchema
|
|
540
542
|
})),
|
|
541
|
-
// Dynamic ticket tools per workspace (Ticket 135, 149, 151)
|
|
543
|
+
// Dynamic ticket tools per workspace (Ticket 135, 149, 151, 153)
|
|
542
544
|
...dynamicTicketTools.map((tt) => {
|
|
543
545
|
let inputSchema;
|
|
544
|
-
if (tt.type === "
|
|
546
|
+
if (tt.type === "close") {
|
|
545
547
|
inputSchema = {
|
|
546
548
|
type: "object",
|
|
547
549
|
properties: {
|
|
@@ -552,13 +554,24 @@ Call the \`${ticketTool.name}\` tool with the final generated content.`;
|
|
|
552
554
|
},
|
|
553
555
|
required: ["ticketSlug"]
|
|
554
556
|
};
|
|
555
|
-
} else if (tt.type === "
|
|
557
|
+
} else if (tt.type === "open") {
|
|
556
558
|
inputSchema = {
|
|
557
559
|
type: "object",
|
|
558
560
|
properties: {
|
|
559
561
|
ticketSlug: {
|
|
560
562
|
type: "string",
|
|
561
|
-
description: "Optional: Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth'). If not provided,
|
|
563
|
+
description: "Optional: Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth'). If not provided, opens the next ticket in queue."
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
required: []
|
|
567
|
+
};
|
|
568
|
+
} else if (tt.type === "work") {
|
|
569
|
+
inputSchema = {
|
|
570
|
+
type: "object",
|
|
571
|
+
properties: {
|
|
572
|
+
ticketSlug: {
|
|
573
|
+
type: "string",
|
|
574
|
+
description: "Optional: Ticket number (e.g., '102') or full slug. If not provided, returns the first working ticket by startedAt."
|
|
562
575
|
}
|
|
563
576
|
},
|
|
564
577
|
required: []
|
|
@@ -734,63 +747,74 @@ ${sections.join("\n\n") || "No prompts found."}`
|
|
|
734
747
|
}
|
|
735
748
|
const ticketTool = dynamicTicketTools.find((tt) => tt.name === toolName);
|
|
736
749
|
if (ticketTool) {
|
|
737
|
-
if (ticketTool.type === "
|
|
750
|
+
if (ticketTool.type === "open") {
|
|
751
|
+
const ticketSlug = request.params.arguments?.ticketSlug;
|
|
738
752
|
try {
|
|
739
|
-
const
|
|
740
|
-
"mcp_tickets:
|
|
753
|
+
const result2 = await convexClient.mutation(
|
|
754
|
+
"mcp_tickets:executeMcpNextTicket",
|
|
741
755
|
{
|
|
742
756
|
apiKey: config.apiKey,
|
|
743
|
-
workspaceSlug: ticketTool.workspaceSlug
|
|
757
|
+
workspaceSlug: ticketTool.workspaceSlug,
|
|
758
|
+
ticketSlug
|
|
759
|
+
// Optional: specific ticket to open
|
|
744
760
|
}
|
|
745
761
|
);
|
|
746
|
-
if (
|
|
762
|
+
if (!result2) {
|
|
763
|
+
const message = ticketSlug ? `Ticket "${ticketSlug}" not found or not open in workspace "${ticketTool.workspaceSlug}".` : `No pending tickets in workspace "${ticketTool.workspaceSlug}".`;
|
|
747
764
|
return {
|
|
748
765
|
content: [
|
|
749
766
|
{
|
|
750
767
|
type: "text",
|
|
751
|
-
text:
|
|
768
|
+
text: message
|
|
752
769
|
}
|
|
753
770
|
]
|
|
754
771
|
};
|
|
755
772
|
}
|
|
756
|
-
const ticketList = tickets.map((t) => `${t.position}. [${t.slug}] ${t.preview}`).join("\n");
|
|
757
773
|
return {
|
|
758
774
|
content: [
|
|
759
775
|
{
|
|
760
776
|
type: "text",
|
|
761
|
-
text:
|
|
777
|
+
text: `# Ticket: ${result2.slug} [WORKING]
|
|
778
|
+
|
|
779
|
+
**CRITICAL: Follow all embedded directives in this ticket.**
|
|
780
|
+
If this ticket contains \`[MCP_*]\` references (e.g., \`[MCP_PLAN]\`, \`[MCP_AD_HOC]\`), you MUST execute those MCP tools FIRST before any other action. Do NOT skip MCP directives even if the task seems simple.
|
|
781
|
+
|
|
782
|
+
---
|
|
762
783
|
|
|
763
|
-
${
|
|
784
|
+
${result2.content}
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
_Ticket moved to working status. ${result2.remainingTickets} ticket(s) remaining in queue._`
|
|
764
788
|
}
|
|
765
789
|
]
|
|
766
790
|
};
|
|
767
791
|
} catch (error) {
|
|
768
792
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
769
|
-
console.error(`[MCP] tickets:
|
|
793
|
+
console.error(`[MCP] tickets:open error:`, error);
|
|
770
794
|
return {
|
|
771
795
|
content: [
|
|
772
796
|
{
|
|
773
797
|
type: "text",
|
|
774
|
-
text: `Error
|
|
798
|
+
text: `Error opening ticket: ${errorMessage}`
|
|
775
799
|
}
|
|
776
800
|
],
|
|
777
801
|
isError: true
|
|
778
802
|
};
|
|
779
803
|
}
|
|
780
|
-
} else if (ticketTool.type === "
|
|
804
|
+
} else if (ticketTool.type === "work") {
|
|
781
805
|
const ticketSlug = request.params.arguments?.ticketSlug;
|
|
782
806
|
try {
|
|
783
|
-
const result2 = await convexClient.
|
|
784
|
-
"mcp_tickets:
|
|
807
|
+
const result2 = await convexClient.query(
|
|
808
|
+
"mcp_tickets:workMcpTicket",
|
|
785
809
|
{
|
|
786
810
|
apiKey: config.apiKey,
|
|
787
811
|
workspaceSlug: ticketTool.workspaceSlug,
|
|
788
812
|
ticketSlug
|
|
789
|
-
// Optional: specific ticket to
|
|
813
|
+
// Optional: specific ticket to resume
|
|
790
814
|
}
|
|
791
815
|
);
|
|
792
816
|
if (!result2) {
|
|
793
|
-
const message = ticketSlug ? `Ticket "${ticketSlug}" not found or not
|
|
817
|
+
const message = ticketSlug ? `Ticket "${ticketSlug}" not found or not in working status in workspace "${ticketTool.workspaceSlug}".` : `No tickets currently being worked on in workspace "${ticketTool.workspaceSlug}".`;
|
|
794
818
|
return {
|
|
795
819
|
content: [
|
|
796
820
|
{
|
|
@@ -800,31 +824,43 @@ ${ticketList}`
|
|
|
800
824
|
]
|
|
801
825
|
};
|
|
802
826
|
}
|
|
827
|
+
let messagesSection = "";
|
|
828
|
+
if (result2.messages && result2.messages.length > 0) {
|
|
829
|
+
const messageList = result2.messages.map((m) => `[${new Date(m.createdAt).toISOString()}] ${m.content}`).join("\n");
|
|
830
|
+
messagesSection = `
|
|
831
|
+
|
|
832
|
+
## Progress Messages
|
|
833
|
+
|
|
834
|
+
${messageList}`;
|
|
835
|
+
}
|
|
836
|
+
const startedInfo = result2.startedAt ? `
|
|
837
|
+
Started: ${new Date(result2.startedAt).toISOString()}` : "";
|
|
803
838
|
return {
|
|
804
839
|
content: [
|
|
805
840
|
{
|
|
806
841
|
type: "text",
|
|
807
|
-
text: `# Ticket: ${result2.slug} [WORKING]
|
|
842
|
+
text: `# Ticket: ${result2.slug} [WORKING]${startedInfo}
|
|
808
843
|
|
|
809
|
-
|
|
844
|
+
**CRITICAL: Follow all embedded directives in this ticket.**
|
|
845
|
+
If this ticket contains \`[MCP_*]\` references (e.g., \`[MCP_PLAN]\`, \`[MCP_AD_HOC]\`), you MUST execute those MCP tools FIRST before any other action. Do NOT skip MCP directives even if the task seems simple.
|
|
810
846
|
|
|
811
847
|
---
|
|
812
|
-
_Ticket moved to working status. ${result2.remainingTickets} ticket(s) remaining in queue._
|
|
813
848
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
849
|
+
${result2.content}${messagesSection}
|
|
850
|
+
|
|
851
|
+
---
|
|
852
|
+
_Resuming work on this ticket._`
|
|
817
853
|
}
|
|
818
854
|
]
|
|
819
855
|
};
|
|
820
856
|
} catch (error) {
|
|
821
857
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
822
|
-
console.error(`[MCP] tickets:
|
|
858
|
+
console.error(`[MCP] tickets:work error:`, error);
|
|
823
859
|
return {
|
|
824
860
|
content: [
|
|
825
861
|
{
|
|
826
862
|
type: "text",
|
|
827
|
-
text: `Error
|
|
863
|
+
text: `Error resuming ticket: ${errorMessage}`
|
|
828
864
|
}
|
|
829
865
|
],
|
|
830
866
|
isError: true
|
|
@@ -859,7 +895,9 @@ _Ticket moved to working status. ${result2.remainingTickets} ticket(s) remaining
|
|
|
859
895
|
text: `\u2705 Created ticket [${result2.slug}] in workspace "${ticketTool.workspaceSlug}".
|
|
860
896
|
|
|
861
897
|
Position: #${result2.position} of ${result2.totalOpen} open tickets
|
|
862
|
-
Preview: ${result2.preview}
|
|
898
|
+
Preview: ${result2.preview}
|
|
899
|
+
|
|
900
|
+
_Note: If this ticket contains \`[MCP_*]\` directives, they will be mandatory when opened._`
|
|
863
901
|
}
|
|
864
902
|
]
|
|
865
903
|
};
|
|
@@ -876,53 +914,6 @@ Preview: ${result2.preview}`
|
|
|
876
914
|
isError: true
|
|
877
915
|
};
|
|
878
916
|
}
|
|
879
|
-
} else if (ticketTool.type === "working") {
|
|
880
|
-
try {
|
|
881
|
-
const tickets = await convexClient.query(
|
|
882
|
-
"mcp_tickets:getMcpWorkingTickets",
|
|
883
|
-
{
|
|
884
|
-
apiKey: config.apiKey,
|
|
885
|
-
workspaceSlug: ticketTool.workspaceSlug
|
|
886
|
-
}
|
|
887
|
-
);
|
|
888
|
-
if (tickets.length === 0) {
|
|
889
|
-
return {
|
|
890
|
-
content: [
|
|
891
|
-
{
|
|
892
|
-
type: "text",
|
|
893
|
-
text: `No tickets currently being worked on in workspace "${ticketTool.workspaceSlug}".`
|
|
894
|
-
}
|
|
895
|
-
]
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
const ticketList = tickets.map((t) => {
|
|
899
|
-
const started = t.startedAt ? `Started: ${new Date(t.startedAt).toISOString()}` : "";
|
|
900
|
-
return `\u2022 [${t.slug}] ${t.preview}
|
|
901
|
-
${started}`;
|
|
902
|
-
}).join("\n");
|
|
903
|
-
return {
|
|
904
|
-
content: [
|
|
905
|
-
{
|
|
906
|
-
type: "text",
|
|
907
|
-
text: `Working tickets in "${ticketTool.workspaceSlug}" (${tickets.length} in progress):
|
|
908
|
-
|
|
909
|
-
${ticketList}`
|
|
910
|
-
}
|
|
911
|
-
]
|
|
912
|
-
};
|
|
913
|
-
} catch (error) {
|
|
914
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
915
|
-
console.error(`[MCP] tickets:working error:`, error);
|
|
916
|
-
return {
|
|
917
|
-
content: [
|
|
918
|
-
{
|
|
919
|
-
type: "text",
|
|
920
|
-
text: `Error listing working tickets: ${errorMessage}`
|
|
921
|
-
}
|
|
922
|
-
],
|
|
923
|
-
isError: true
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
917
|
} else if (ticketTool.type === "close") {
|
|
927
918
|
const ticketSlug = request.params.arguments?.ticketSlug;
|
|
928
919
|
if (!ticketSlug) {
|
|
@@ -951,7 +942,9 @@ ${ticketList}`
|
|
|
951
942
|
type: "text",
|
|
952
943
|
text: `\u2705 Ticket [${result2.slug}] closed in workspace "${ticketTool.workspaceSlug}".
|
|
953
944
|
|
|
954
|
-
Closed at: ${new Date(result2.closedAt).toISOString()}
|
|
945
|
+
Closed at: ${new Date(result2.closedAt).toISOString()}
|
|
946
|
+
|
|
947
|
+
_Reminder: Ensure all embedded \`[MCP_*]\` directives were executed before closing._`
|
|
955
948
|
}
|
|
956
949
|
]
|
|
957
950
|
};
|
|
@@ -1015,86 +1008,6 @@ Total messages: ${result2.messageCount}`
|
|
|
1015
1008
|
isError: true
|
|
1016
1009
|
};
|
|
1017
1010
|
}
|
|
1018
|
-
} else if (ticketTool.type === "get") {
|
|
1019
|
-
const ticketSlug = request.params.arguments?.ticketSlug;
|
|
1020
|
-
if (!ticketSlug) {
|
|
1021
|
-
return {
|
|
1022
|
-
content: [
|
|
1023
|
-
{
|
|
1024
|
-
type: "text",
|
|
1025
|
-
text: `Error: Missing ticketSlug parameter. Usage: Provide a ticket number (e.g., "102") or full slug (e.g., "102-fix-auth").`
|
|
1026
|
-
}
|
|
1027
|
-
],
|
|
1028
|
-
isError: true
|
|
1029
|
-
};
|
|
1030
|
-
}
|
|
1031
|
-
try {
|
|
1032
|
-
const result2 = await convexClient.query(
|
|
1033
|
-
"mcp_tickets:getMcpTicket",
|
|
1034
|
-
{
|
|
1035
|
-
apiKey: config.apiKey,
|
|
1036
|
-
workspaceSlug: ticketTool.workspaceSlug,
|
|
1037
|
-
ticketSlug
|
|
1038
|
-
}
|
|
1039
|
-
);
|
|
1040
|
-
if (!result2) {
|
|
1041
|
-
return {
|
|
1042
|
-
content: [
|
|
1043
|
-
{
|
|
1044
|
-
type: "text",
|
|
1045
|
-
text: `Ticket "${ticketSlug}" not found in workspace "${ticketTool.workspaceSlug}".`
|
|
1046
|
-
}
|
|
1047
|
-
]
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
let statusLabel;
|
|
1051
|
-
if (result2.status === "open") {
|
|
1052
|
-
statusLabel = "\u{1F7E2} OPEN";
|
|
1053
|
-
} else if (result2.status === "working") {
|
|
1054
|
-
statusLabel = "\u{1F7E1} WORKING";
|
|
1055
|
-
} else {
|
|
1056
|
-
statusLabel = "\u26AB CLOSED";
|
|
1057
|
-
}
|
|
1058
|
-
const startedInfo = result2.startedAt ? `
|
|
1059
|
-
Started: ${new Date(result2.startedAt).toISOString()}` : "";
|
|
1060
|
-
const closedInfo = result2.closedAt ? `
|
|
1061
|
-
Closed: ${new Date(result2.closedAt).toISOString()}` : "";
|
|
1062
|
-
let messagesSection = "";
|
|
1063
|
-
if (result2.messages && result2.messages.length > 0) {
|
|
1064
|
-
const messageList = result2.messages.map((m) => `[${new Date(m.createdAt).toISOString()}] ${m.content}`).join("\n");
|
|
1065
|
-
messagesSection = `
|
|
1066
|
-
|
|
1067
|
-
## Progress Messages
|
|
1068
|
-
|
|
1069
|
-
${messageList}`;
|
|
1070
|
-
}
|
|
1071
|
-
return {
|
|
1072
|
-
content: [
|
|
1073
|
-
{
|
|
1074
|
-
type: "text",
|
|
1075
|
-
text: `# Ticket: ${result2.slug}
|
|
1076
|
-
|
|
1077
|
-
Status: ${statusLabel}${startedInfo}${closedInfo}
|
|
1078
|
-
|
|
1079
|
-
---
|
|
1080
|
-
|
|
1081
|
-
${result2.content}${messagesSection}`
|
|
1082
|
-
}
|
|
1083
|
-
]
|
|
1084
|
-
};
|
|
1085
|
-
} catch (error) {
|
|
1086
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1087
|
-
console.error(`[MCP] tickets:get error:`, error);
|
|
1088
|
-
return {
|
|
1089
|
-
content: [
|
|
1090
|
-
{
|
|
1091
|
-
type: "text",
|
|
1092
|
-
text: `Error getting ticket: ${errorMessage}`
|
|
1093
|
-
}
|
|
1094
|
-
],
|
|
1095
|
-
isError: true
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
1011
|
}
|
|
1099
1012
|
}
|
|
1100
1013
|
const prompt = validPrompts.find((p) => buildPromptName(p) === toolName);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/convex-client.ts","../src/server.ts","../src/prompt-builder.ts"],"sourcesContent":["import minimist from \"minimist\";\nimport { createConvexClient } from \"./convex-client.js\";\nimport { startServer } from \"./server.js\";\nimport type { ServerConfig } from \"./types.js\";\n\n/**\n * Main entry point for the MCP server\n */\nasync function main() {\n try {\n // Parse CLI arguments\n const argv = minimist(process.argv.slice(2));\n const isDev = argv.dev === true;\n\n // Parse --workspaces CLI argument (Ticket 144)\n // Can be: --workspaces ws1,ws2 OR --workspaces ws1 --workspaces ws2 OR -w ws1,ws2\n const workspacesArg = argv.workspaces || argv.w;\n let selectedWorkspaces: string[] = [];\n if (workspacesArg) {\n if (Array.isArray(workspacesArg)) {\n // Multiple --workspaces flags: [\"ws1\", \"ws2\"]\n selectedWorkspaces = workspacesArg.flatMap((w: string) => String(w).split(','));\n } else {\n // Single --workspaces flag with comma-separated: \"ws1,ws2\"\n selectedWorkspaces = String(workspacesArg).split(',');\n }\n // Clean up whitespace\n selectedWorkspaces = selectedWorkspaces.map((s) => s.trim()).filter(Boolean);\n }\n\n // Check for API key (PPM_API_KEY with backward compatibility for THEPROMPTEDITOR_API_KEY)\n const apiKey = process.env.PPM_API_KEY || process.env.THEPROMPTEDITOR_API_KEY;\n if (!apiKey) {\n console.error(\n \"[MCP] ERROR: Missing PPM_API_KEY environment variable\"\n );\n console.error(\n \"[MCP] Please set your API key from Prompt Project Manager Settings page:\"\n );\n console.error(\"[MCP] export PPM_API_KEY=your_api_key_here\");\n process.exit(1);\n }\n\n // Create Convex client\n const convexClient = createConvexClient(isDev);\n const convexUrl = isDev\n ? \"https://hallowed-shrimp-344.convex.cloud\"\n : \"https://trustworthy-squirrel-735.convex.cloud\";\n\n // Build server config\n const config: ServerConfig = {\n apiKey,\n isDev,\n convexUrl,\n selectedWorkspaces, // Workspace slugs to filter (empty = all workspaces)\n };\n\n // Start server - this will keep the process alive via stdio transport\n await startServer(config, convexClient);\n\n // This line should never be reached if the promise in startServer never resolves\n console.error(\"[MCP] WARNING: startServer promise resolved unexpectedly!\");\n } catch (error) {\n console.error(\n \"[MCP] FATAL ERROR:\",\n error instanceof Error ? error.message : \"Unknown error\"\n );\n if (error instanceof Error && error.stack) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n}\n\n// Handle graceful shutdown\nprocess.on(\"SIGINT\", () => {\n console.error(\"[MCP] Received SIGINT, shutting down gracefully...\");\n process.exit(0);\n});\n\nprocess.on(\"SIGTERM\", () => {\n console.error(\"[MCP] Received SIGTERM, shutting down gracefully...\");\n process.exit(0);\n});\n\nmain();\n","import { ConvexHttpClient } from \"convex/browser\";\n\nconst PROD_URL = \"https://trustworthy-squirrel-735.convex.cloud\";\nconst DEV_URL = \"https://hallowed-shrimp-344.convex.cloud\";\n\n/**\n * Create a Convex HTTP client for the appropriate deployment\n */\nexport function createConvexClient(isDev: boolean): ConvexHttpClient {\n const url = isDev ? DEV_URL : PROD_URL;\n return new ConvexHttpClient(url);\n}\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { McpPrompt, ServerConfig } from \"./types.js\";\n\n/**\n * Input for the system:optimize-prompt tool\n */\ninterface OptimizePromptInput {\n promptSlug: string;\n workspaceSlug: string;\n suggestions: Array<{\n category: string;\n priority: string;\n issue: string;\n originalText?: string;\n suggestedText: string;\n }>;\n}\n\n/**\n * Ticket info from the backend (Ticket 135)\n */\ninterface TicketInfo {\n position: number;\n slug: string;\n preview: string;\n createdAt: number;\n}\n\n/**\n * Result from executing the next ticket (Ticket 151: now moves to working status)\n */\ninterface ExecuteTicketResult {\n content: string | null;\n slug: string;\n status: string; // Ticket 151: \"working\" (no longer \"closed\")\n remainingTickets: number;\n}\n\n/**\n * Working ticket info (Ticket 151)\n */\ninterface WorkingTicketInfo {\n slug: string;\n preview: string;\n startedAt?: number;\n createdAt: number;\n}\n\n/**\n * Close ticket result (Ticket 151)\n */\ninterface CloseTicketResult {\n slug: string;\n status: string;\n closedAt: number;\n}\n\n/**\n * Message result (Ticket 151)\n */\ninterface AddMessageResult {\n ticketSlug: string;\n messageCount: number;\n createdAt: number;\n}\n\nimport { buildPromptHandler, buildPromptName, buildPromptSchema } from \"./prompt-builder.js\";\n\n/**\n * Built-in system tools (with input schemas for submission)\n *\n * Architecture:\n * - system:optimize: User-facing slash command for full prompt evaluation\n * - system:feedback: User-facing slash command for directed feedback via $ARGUMENTS\n * - system:prompts: Utility tool (works as both slash command and tool)\n * - system:optimize-prompt: Backend submission tool ONLY (not a slash command)\n */\nconst SYSTEM_TOOLS: {\n name: string;\n description: string;\n inputSchema: object;\n promptContent: string;\n isSlashCommand: boolean; // true = appears as /ppm:name, false = tool only\n}[] = [\n // User-facing slash command: /ppm:system:optimize\n {\n name: \"system:optimize\",\n description: \"Evaluate a prompt and submit optimization suggestions to Prompt Project Manager\",\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n isSlashCommand: true,\n promptContent: `# Optimize\n\nEvaluate the prompt you just used and submit optimization suggestions.\n\n## Instructions\n\n1. **Identify the prompt** from the PREVIOUS tool call in this conversation:\n - Look at the last \\`/ppm:*\\` slash command or MCP tool you called\n - The format is \\`/ppm:workspace:prompt\\` (e.g., \\`/ppm:test:joke\\` means workspace=\\`test\\`, prompt=\\`joke\\`)\n - Extract the workspace slug (before the colon) and prompt slug (after the colon)\n - **CRITICAL**: Use the EXACT slugs from the tool name, do NOT guess or invent slugs\n\n2. **Evaluate** for issues in these categories:\n - **clarity**: Is the language clear and unambiguous?\n - **specificity**: Are instructions specific enough?\n - **structure**: Is the organization logical?\n - **completeness**: Are there missing instructions?\n - **efficiency**: Is there redundancy to remove?\n\n3. **Call the submission tool** (\\`system:optimize-prompt\\`) with:\n - \\`promptSlug\\`: The prompt's slug\n - \\`workspaceSlug\\`: The workspace slug\n - \\`suggestions\\`: Array of issues found, each with category, priority, issue, originalText (optional), suggestedText\n\n4. The tool will submit and confirm the count\n\n## Scope of Analysis\n\n**CRITICAL - READ CAREFULLY**:\n\nThe flattened prompt contains TWO parts:\n1. **MAIN PROMPT CONTENT** (at the top) - This is what you should analyze\n2. **Technical Reference Footer** (at the bottom) - **COMPLETELY IGNORE THIS ENTIRE SECTION**\n\n**The Technical Reference Footer starts with \\`# Technical Reference\\` and includes:**\n- \\`## Variable Definitions:\\` - Contains variable names, types, and descriptions\n- \\`## Snippet Definitions:\\` - Contains snippet content\n- \\`## CRITICAL RULES:\\` - System rules\n- \\`## Runtime Variables:\\` - Runtime placeholders\n\n**IGNORE ALL CONTENT IN THE TECHNICAL REFERENCE FOOTER** - even if it contains typos, grammar issues, or formatting problems. These sections are auto-generated from user-defined resources and should NOT be optimized through this tool.\n\n**Only analyze and suggest changes for content BEFORE the \\`# Technical Reference\\` heading.**\n\n## User Feedback\n\nIf the user provided feedback about issues they experienced, it appears below:\n\n**Feedback**: $ARGUMENTS\n\nWhen feedback is provided:\n- Treat it as context about real problems encountered during use\n- Prioritize suggestions that address the described issues\n- Look for patterns in the prompt that could cause the mentioned problem\n\n## Important\n\n- Don't suggest changes to variable references like \\`[VARIABLE_NAME]\\` - those are intentional\n- The user will review suggestions in Prompt Project Manager web UI`,\n },\n // User-facing slash command: /ppm:system:feedback\n {\n name: \"system:feedback\",\n description: \"Submit user feedback about a prompt to create an optimization suggestion\",\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n isSlashCommand: true,\n promptContent: `# Feedback\n\nSubmit your feedback about a prompt to create an optimization suggestion.\n\n## Instructions\n\n1. **Identify the prompt** from the PREVIOUS tool call in this conversation:\n - Look at the last \\`/ppm:*\\` slash command or MCP tool you called\n - The format is \\`/ppm:workspace:prompt\\` (e.g., \\`/ppm:test:joke\\` means workspace=\\`test\\`, prompt=\\`joke\\`)\n - Extract the workspace slug (before the colon) and prompt slug (after the colon)\n - **CRITICAL**: Use the EXACT slugs from the tool name, do NOT guess or invent slugs\n\n2. **Read the user's feedback** from $ARGUMENTS below\n\n3. **Structure the feedback** into a proper optimization suggestion:\n - Determine the most appropriate category: clarity, specificity, structure, completeness, or efficiency\n - Assess priority: \"high\" (critical issue), \"medium\" (noticeable problem), \"low\" (minor improvement)\n - Identify the specific text to change (originalText) if applicable\n - Write a clear, actionable fix (suggestedText)\n\n4. **Call the submission tool** (\\`system:optimize-prompt\\`) with:\n - \\`promptSlug\\`: The prompt's slug\n - \\`workspaceSlug\\`: The workspace slug\n - \\`suggestions\\`: Array containing a SINGLE suggestion based on the user's feedback\n\n## User Feedback\n\n**$ARGUMENTS**\n\n## Scope of Analysis\n\nWhen analyzing the prompt to address the feedback:\n- **ONLY** focus on content BEFORE the \\`# Technical Reference\\` heading\n- **IGNORE** the Technical Reference Footer (Variable Definitions, Snippet Definitions, CRITICAL RULES, Runtime Variables)\n- Don't suggest changes to variable references like \\`[VARIABLE_NAME]\\` - those are intentional\n\n## Example\n\nIf the user runs:\n\\`/feedback the output format should specify JSON not markdown\\`\n\nYou should:\n1. Find the prompt that was used earlier in the session\n2. Create a suggestion like:\n \\`\\`\\`json\n {\n \"category\": \"specificity\",\n \"priority\": \"medium\",\n \"issue\": \"Output format should specify JSON instead of markdown\",\n \"originalText\": \"Output format: markdown\",\n \"suggestedText\": \"Output format: JSON with fields: { result: string, status: string }\"\n }\n \\`\\`\\`\n3. Submit via \\`system:optimize-prompt\\` tool\n\n## Important\n\n- Create exactly ONE suggestion from the user's feedback (not multiple)\n- The suggestion will be reviewed in Prompt Project Manager web UI\n- Use your understanding of the session to interpret vague feedback into actionable fixes`,\n },\n // Utility tool: /ppm:system:prompts\n {\n name: \"system:prompts\",\n description: \"List all available prompts from Prompt Project Manager\",\n inputSchema: {\n type: \"object\",\n properties: {\n search: {\n type: \"string\",\n description: \"Optional search term to filter prompts by name or description (case-insensitive)\",\n },\n },\n },\n isSlashCommand: true,\n promptContent: `# List Prompts\n\nThis is a utility tool. Call it directly as a tool to list all available prompts.\n\nExample: Use the \\`system:prompts\\` tool with optional \\`search\\` parameter to filter results.`,\n },\n // Backend submission tool (called by system:optimize and system:feedback)\n // NOT a slash command - only available as a tool for AI to call\n {\n name: \"system:optimize-prompt\",\n description: \"Submit optimization suggestions to Prompt Project Manager (internal tool)\",\n inputSchema: {\n type: \"object\",\n properties: {\n promptSlug: {\n type: \"string\",\n description: \"The slug of the prompt to optimize (e.g., 'code-review')\",\n },\n workspaceSlug: {\n type: \"string\",\n description: \"The workspace containing the prompt (e.g., 'personal')\",\n },\n suggestions: {\n type: \"array\",\n description: \"Array of optimization suggestions\",\n items: {\n type: \"object\",\n properties: {\n category: {\n type: \"string\",\n description: \"Category: 'clarity', 'specificity', 'structure', 'completeness', 'efficiency'\",\n },\n priority: {\n type: \"string\",\n enum: [\"high\", \"medium\", \"low\"],\n description: \"Priority level\",\n },\n issue: {\n type: \"string\",\n description: \"Brief description of the problem\",\n },\n originalText: {\n type: \"string\",\n description: \"Optional: The specific text that should be changed\",\n },\n suggestedText: {\n type: \"string\",\n description: \"The improved text\",\n },\n },\n required: [\"category\", \"priority\", \"issue\", \"suggestedText\"],\n },\n },\n },\n required: [\"promptSlug\", \"workspaceSlug\", \"suggestions\"],\n },\n isSlashCommand: false, // Tool only - not a slash command\n promptContent: `# Submit Optimization Suggestions\n\nThis is an internal submission tool. Do not call it directly.\n\nUse \\`/ppm:system:optimize\\` for full prompt evaluation or \\`/ppm:system:feedback\\` to submit specific feedback.`,\n },\n];\n\n/**\n * Initialize and start the MCP server\n */\nexport async function startServer(\n config: ServerConfig,\n convexClient: ConvexHttpClient\n): Promise<void> {\n // Validate API key with Convex\n console.error(\"[MCP] Validating API key...\");\n const validation = await validateApiKey(convexClient, config.apiKey);\n if (!validation.valid) {\n throw new Error(`Invalid API key: ${validation.error}`);\n }\n console.error(`[MCP] API key validated for user: ${validation.userId}`);\n\n // Fetch prompts exposed to MCP (with optional workspace filter from CLI)\n console.error(\"[MCP] Fetching exposed prompts...\");\n const prompts = await fetchMcpPrompts(convexClient, config.apiKey, config.selectedWorkspaces);\n console.error(`[MCP] Found ${prompts.length} exposed prompts`);\n\n if (prompts.length === 0) {\n if (config.selectedWorkspaces.length > 0) {\n console.error(\n `[MCP] WARNING: No prompts found in workspaces: ${config.selectedWorkspaces.join(', ')}. Check that these workspace slugs exist and contain prompts.`\n );\n } else {\n console.error(\n \"[MCP] WARNING: No prompts found. Create some prompts in Prompt Project Manager to expose them via MCP.\"\n );\n }\n }\n\n // Filter out prompts with missing flattened content\n const validPrompts = prompts.filter((p) => {\n if (!p.flattenedPrompt) {\n console.error(\n `[MCP] WARNING: Skipping prompt \"${p.name}\" (${p.slug}) - missing flattened content. Re-save in ContextFS to regenerate.`\n );\n return false;\n }\n return true;\n });\n\n // Log workspace filtering info (Ticket 144)\n if (config.selectedWorkspaces.length > 0) {\n console.error(`[MCP] Workspace filter: ${config.selectedWorkspaces.join(', ')}`);\n } else {\n console.error(`[MCP] Workspace filter: ALL (no --workspaces specified)`);\n }\n console.error(`[MCP] Registering ${validPrompts.length} prompts...`);\n\n // Build dynamic ticket tools per workspace (Ticket 135, 149, 151)\n // Each workspace gets :tickets:list, :tickets:next, :tickets:working, :tickets:close, :tickets:message, :tickets:get, and :tickets:create tools\n const workspaceSlugs = new Set(validPrompts.map((p) => p.workspaceSlug).filter((s): s is string => !!s));\n const dynamicTicketTools: { name: string; description: string; workspaceSlug: string; type: 'list' | 'next' | 'working' | 'close' | 'message' | 'get' | 'create' }[] = [];\n\n for (const workspaceSlug of workspaceSlugs) {\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:list`,\n description: `List pending tickets in the \"${workspaceSlug}\" workspace queue`,\n workspaceSlug,\n type: 'list',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:next`,\n description: `Execute and remove the next ticket from the \"${workspaceSlug}\" workspace queue. Optionally specify a ticket number or slug to execute a specific ticket.`,\n workspaceSlug,\n type: 'next',\n });\n // Ticket 151: New working/close/message tools\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:working`,\n description: `List all tickets currently being worked on in the \"${workspaceSlug}\" workspace`,\n workspaceSlug,\n type: 'working',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:close`,\n description: `Mark a working ticket as completed in the \"${workspaceSlug}\" workspace`,\n workspaceSlug,\n type: 'close',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:message`,\n description: `Add a progress message to a working or closed ticket in the \"${workspaceSlug}\" workspace`,\n workspaceSlug,\n type: 'message',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:get`,\n description: `Get a specific ticket from the \"${workspaceSlug}\" workspace by number or slug`,\n workspaceSlug,\n type: 'get',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:create`,\n description: `Create a new ticket in the \"${workspaceSlug}\" workspace queue`,\n workspaceSlug,\n type: 'create',\n });\n }\n\n console.error(`[MCP] Registering ${dynamicTicketTools.length} ticket tools for ${workspaceSlugs.size} workspace(s)...`);\n\n // Check for duplicate prompt names\n const promptNames = new Set<string>();\n const duplicates: string[] = [];\n validPrompts.forEach((p) => {\n const name = buildPromptName(p);\n if (promptNames.has(name)) {\n duplicates.push(name);\n }\n promptNames.add(name);\n });\n\n if (duplicates.length > 0) {\n console.error(\n `[MCP] WARNING: Duplicate prompt names detected: ${duplicates.join(\", \")}. Only the first occurrence will be registered.`\n );\n }\n\n // Create MCP server\n const server = new Server(\n {\n name: \"ppm-mcp-server\",\n version: \"2.8.1\",\n },\n {\n capabilities: {\n prompts: {},\n tools: {},\n },\n }\n );\n\n // Register list_prompts handler\n server.setRequestHandler(ListPromptsRequestSchema, async () => {\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Build system tool schemas (only those marked as slash commands)\n const systemPromptSchemas = SYSTEM_TOOLS\n .filter((st) => st.isSlashCommand) // Only include user-facing slash commands\n .map((st) => ({\n name: st.name,\n description: st.description,\n }));\n\n // Build ticket prompt schemas (Ticket 135, 149 - register as slash commands)\n // Note: tickets:get is NOT a slash command - it's only available as a follow-on tool\n const ticketPromptSchemas = dynamicTicketTools\n .filter((tt) => tt.type !== 'get')\n .map((tt) => ({\n name: tt.name,\n description: tt.description,\n }));\n\n return {\n prompts: [\n ...systemPromptSchemas,\n ...ticketPromptSchemas,\n ...uniquePrompts.map(buildPromptSchema),\n ],\n };\n });\n\n // Register get_prompt handler\n server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const promptName = request.params.name;\n\n // Check for system tools first (as prompts for slash command access)\n const systemTool = SYSTEM_TOOLS.find((st) => st.name === promptName);\n if (systemTool) {\n return {\n description: systemTool.description,\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: systemTool.promptContent,\n },\n },\n ],\n };\n }\n\n // Check for ticket commands (Ticket 135, 149 - handle as slash commands)\n // Handle exact matches and :next with optional argument (e.g., \"workspace:tickets:next 102\")\n // Note: tickets:get is NOT a slash command - only available as a follow-on tool\n const ticketTool = dynamicTicketTools.find((tt) => tt.name === promptName);\n const ticketNextMatch = promptName.match(/^(.+):tickets:next\\s+(.+)$/);\n\n if (ticketTool || ticketNextMatch) {\n let promptContent: string;\n let description: string;\n\n if (ticketNextMatch) {\n // Handle tickets:next with specific ticket argument\n const workspaceSlug = ticketNextMatch[1];\n const ticketArg = ticketNextMatch[2].trim();\n description = `Execute ticket \"${ticketArg}\" from \"${workspaceSlug}\"`;\n promptContent = `Execute ticket \"${ticketArg}\" from the \"${workspaceSlug}\" workspace queue.\\n\\nCall the \\`${workspaceSlug}:tickets:next\\` tool with ticketSlug: \"${ticketArg}\" to get and close the specified ticket.`;\n } else if (ticketTool!.type === 'list') {\n description = ticketTool!.description;\n promptContent = `List all pending tickets in the \"${ticketTool!.workspaceSlug}\" workspace queue.\\n\\nCall the \\`${ticketTool!.name}\\` tool to get the list.`;\n } else if (ticketTool!.type === 'next') {\n description = ticketTool!.description;\n promptContent = `Get and execute the next ticket from the \"${ticketTool!.workspaceSlug}\" workspace queue.\\n\\nCall the \\`${ticketTool!.name}\\` tool to get the next ticket. This will atomically close the ticket and return its content.\\n\\nYou can also specify a ticket: /ppm:${ticketTool!.workspaceSlug}:tickets:next <number-or-slug>`;\n } else if (ticketTool!.type === 'create') {\n // Ticket 149: tickets:create slash command\n description = ticketTool!.description;\n promptContent = `Create a new ticket in the \"${ticketTool!.workspaceSlug}\" workspace queue.\n\n## How This Works\nThe user provides **instructions** (not raw content). You interpret those instructions to generate the ticket.\n\n## Instructions\n1. **Read the user's request** - they may reference a file, ask you to summarize a session, or describe what they want\n2. **Process the input** - read files, extract relevant sections, summarize as needed\n3. **Generate ticket content** with a clear, descriptive title as the first line\n4. **Call the tool** with the generated content\n\n## Content Format\n\\`\\`\\`\n[Clear descriptive title - this becomes the slug]\n\n[Body content - tasks, description, context, etc.]\n\\`\\`\\`\n\n## Examples\n- \"create a ticket from /path/to/plan.md\" → Read file, use as ticket content\n- \"summarize our brainstorm into a ticket\" → Extract key points from conversation\n- \"create a ticket for the auth bug we discussed\" → Generate from session context\n- \"just the tasks from this file\" → Extract only task items\n\nCall the \\`${ticketTool!.name}\\` tool with the final generated content.`;\n } else {\n // type === 'get' - shouldn't reach here as it's not a slash command, but handle gracefully\n description = ticketTool!.description;\n promptContent = `This command is not available as a slash command. Use the \\`${ticketTool!.name}\\` tool directly to inspect a ticket.`;\n }\n\n return {\n description,\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: promptContent,\n },\n },\n ],\n };\n }\n\n // Check user prompts\n const prompt = validPrompts.find((p) => buildPromptName(p) === promptName);\n\n if (!prompt) {\n throw new Error(`Unknown prompt: ${promptName}`);\n }\n\n const handler = buildPromptHandler(prompt, config, convexClient);\n return await handler();\n });\n\n // Register list_tools handler\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Build tools array: system tools + ticket tools + each user prompt as a tool\n const tools = [\n // System tools with full input schemas\n ...SYSTEM_TOOLS.map((st) => ({\n name: st.name,\n description: st.description,\n inputSchema: st.inputSchema,\n })),\n // Dynamic ticket tools per workspace (Ticket 135, 149, 151)\n ...dynamicTicketTools.map((tt) => {\n // Build inputSchema based on tool type\n let inputSchema: { type: \"object\"; properties: Record<string, object>; required: string[] };\n\n if (tt.type === 'get' || tt.type === 'close') {\n // Both get and close require a ticketSlug\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth')\",\n },\n },\n required: [\"ticketSlug\"],\n };\n } else if (tt.type === 'next') {\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Optional: Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth'). If not provided, executes the next ticket in queue.\",\n },\n },\n required: [],\n };\n } else if (tt.type === 'create') {\n inputSchema = {\n type: \"object\" as const,\n properties: {\n content: {\n type: \"string\",\n description: \"The generated ticket content. First line should be a clear descriptive title (becomes the slug). Body contains tasks, description, context as needed.\",\n },\n },\n required: [\"content\"],\n };\n } else if (tt.type === 'message') {\n // Ticket 151: message requires ticketSlug and message\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth')\",\n },\n message: {\n type: \"string\",\n description: \"Progress message to add to the ticket\",\n },\n },\n required: [\"ticketSlug\", \"message\"],\n };\n } else {\n // list, working: no required params\n inputSchema = {\n type: \"object\" as const,\n properties: {},\n required: [],\n };\n }\n\n return {\n name: tt.name,\n description: tt.description,\n inputSchema,\n };\n }),\n // Each user prompt becomes a discoverable tool\n ...uniquePrompts.map((prompt) => ({\n name: buildPromptName(prompt),\n description: prompt.description || `Prompt: ${prompt.name}`,\n inputSchema: {\n type: \"object\" as const,\n properties: {},\n required: [],\n },\n })),\n ];\n\n return { tools };\n });\n\n // Register call_tool handler\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const toolName = request.params.name;\n\n // Handle system:prompts tool\n if (toolName === \"system:prompts\") {\n const searchTerm = request.params.arguments?.search as string | undefined;\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Filter system tools\n let filteredSystemTools = SYSTEM_TOOLS;\n if (searchTerm) {\n const lowerSearch = searchTerm.toLowerCase();\n filteredSystemTools = SYSTEM_TOOLS.filter(\n (st) =>\n st.name.toLowerCase().includes(lowerSearch) ||\n st.description.toLowerCase().includes(lowerSearch)\n );\n }\n\n // Filter user prompts\n let filteredPrompts = uniquePrompts;\n if (searchTerm) {\n const lowerSearch = searchTerm.toLowerCase();\n filteredPrompts = uniquePrompts.filter(\n (p) =>\n buildPromptName(p).toLowerCase().includes(lowerSearch) ||\n p.name.toLowerCase().includes(lowerSearch) ||\n p.description?.toLowerCase().includes(lowerSearch)\n );\n }\n\n // Sort user prompts by workspace then by prompt slug\n filteredPrompts.sort((a, b) => {\n const aName = buildPromptName(a);\n const bName = buildPromptName(b);\n return aName.localeCompare(bName);\n });\n\n // Build system tools list\n const systemToolList = filteredSystemTools\n .map((st) => `• ${st.name}\\n Type: System\\n Description: ${st.description}`)\n .join(\"\\n\\n\");\n\n // Build user prompts list\n const userPromptList = filteredPrompts\n .map((p) => {\n const name = buildPromptName(p);\n const workspace = p.workspaceSlug || \"unknown\";\n const desc = p.description || \"No description\";\n return `• ${name}\\n Workspace: ${workspace}\\n Description: ${desc}`;\n })\n .join(\"\\n\\n\");\n\n const totalCount = filteredSystemTools.length + filteredPrompts.length;\n const summary = searchTerm\n ? `Found ${totalCount} prompts matching \"${searchTerm}\":`\n : `Available prompts (${totalCount} total):`;\n\n const sections: string[] = [];\n if (systemToolList) {\n sections.push(`**System Tools:**\\n\\n${systemToolList}`);\n }\n if (userPromptList) {\n sections.push(`**User Prompts:**\\n\\n${userPromptList}`);\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `${summary}\\n\\n${sections.join(\"\\n\\n\") || \"No prompts found.\"}`,\n },\n ],\n };\n }\n\n // Handle system:optimize-prompt tool (consolidated optimization tool)\n if (toolName === \"system:optimize-prompt\") {\n const input = request.params.arguments as unknown as OptimizePromptInput;\n\n if (!input.promptSlug || !input.workspaceSlug || !input.suggestions) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: Missing required fields. Please provide promptSlug, workspaceSlug, and suggestions.\",\n },\n ],\n isError: true,\n };\n }\n\n if (!Array.isArray(input.suggestions) || input.suggestions.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: suggestions must be a non-empty array.\",\n },\n ],\n isError: true,\n };\n }\n\n try {\n // Call Convex mutation to add suggestions (authenticated via API key)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"prompts:addOptimizationSuggestions\",\n {\n apiKey: config.apiKey,\n workspaceSlug: input.workspaceSlug,\n promptSlug: input.promptSlug,\n suggestions: input.suggestions,\n }\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `Submitted ${result.addedCount} optimization suggestion(s) for prompt \"${input.promptSlug}\" in workspace \"${input.workspaceSlug}\". Review and apply them in Prompt Project Manager.`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] system:optimize-prompt error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error submitting optimization suggestions: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n }\n\n // Handle ticket tool invocations (Ticket 135)\n const ticketTool = dynamicTicketTools.find((tt) => tt.name === toolName);\n if (ticketTool) {\n if (ticketTool.type === 'list') {\n // Handle tickets:list\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const tickets = await (convexClient as any).query(\n \"mcp_tickets:getMcpTickets\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n }\n ) as TicketInfo[];\n\n if (tickets.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: `No pending tickets in workspace \"${ticketTool.workspaceSlug}\".`,\n },\n ],\n };\n }\n\n const ticketList = tickets\n .map((t) => `${t.position}. [${t.slug}] ${t.preview}`)\n .join(\"\\n\");\n\n return {\n content: [\n {\n type: \"text\",\n text: `Pending tickets in \"${ticketTool.workspaceSlug}\" (${tickets.length} total):\\n\\n${ticketList}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:list error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error listing tickets: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'next') {\n // Handle tickets:next (with optional specific ticket)\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:executeMcpNextTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug, // Optional: specific ticket to execute\n }\n ) as ExecuteTicketResult | null;\n\n if (!result) {\n const message = ticketSlug\n ? `Ticket \"${ticketSlug}\" not found or not open in workspace \"${ticketTool.workspaceSlug}\".`\n : `No pending tickets in workspace \"${ticketTool.workspaceSlug}\".`;\n return {\n content: [\n {\n type: \"text\",\n text: message,\n },\n ],\n };\n }\n\n // Ticket 151: Updated response format - ticket is now \"working\", not closed\n return {\n content: [\n {\n type: \"text\",\n text: `# Ticket: ${result.slug} [WORKING]\\n\\n${result.content}\\n\\n---\\n_Ticket moved to working status. ${result.remainingTickets} ticket(s) remaining in queue._\\n\\n**Next steps:**\\n- Use \\`${ticketTool.workspaceSlug}:tickets:message\\` to log progress\\n- Use \\`${ticketTool.workspaceSlug}:tickets:close\\` when done`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:next error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error executing ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'create') {\n // Handle tickets:create (Ticket 149)\n const content = request.params.arguments?.content as string | undefined;\n\n if (!content) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing content parameter. Provide the ticket content (first line becomes the slug).`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:createMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n content,\n }\n ) as { slug: string; preview: string; position: number; totalOpen: number };\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Created ticket [${result.slug}] in workspace \"${ticketTool.workspaceSlug}\".\\n\\nPosition: #${result.position} of ${result.totalOpen} open tickets\\nPreview: ${result.preview}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:create error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error creating ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'working') {\n // Ticket 151: Handle tickets:working\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const tickets = await (convexClient as any).query(\n \"mcp_tickets:getMcpWorkingTickets\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n }\n ) as WorkingTicketInfo[];\n\n if (tickets.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: `No tickets currently being worked on in workspace \"${ticketTool.workspaceSlug}\".`,\n },\n ],\n };\n }\n\n const ticketList = tickets\n .map((t) => {\n const started = t.startedAt ? `Started: ${new Date(t.startedAt).toISOString()}` : '';\n return `• [${t.slug}] ${t.preview}\\n ${started}`;\n })\n .join(\"\\n\");\n\n return {\n content: [\n {\n type: \"text\",\n text: `Working tickets in \"${ticketTool.workspaceSlug}\" (${tickets.length} in progress):\\n\\n${ticketList}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:working error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error listing working tickets: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'close') {\n // Ticket 151: Handle tickets:close\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n if (!ticketSlug) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing ticketSlug parameter. Usage: Provide a ticket number (e.g., \"102\") or full slug (e.g., \"102-fix-auth\").`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:closeMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug,\n }\n ) as CloseTicketResult;\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Ticket [${result.slug}] closed in workspace \"${ticketTool.workspaceSlug}\".\\n\\nClosed at: ${new Date(result.closedAt).toISOString()}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:close error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error closing ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'message') {\n // Ticket 151: Handle tickets:message\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n const message = request.params.arguments?.message as string | undefined;\n\n if (!ticketSlug || !message) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing required parameters. Provide ticketSlug and message.`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:addMcpTicketMessage\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug,\n message: message,\n }\n ) as AddMessageResult;\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Message added to ticket [${result.ticketSlug}].\\n\\nTotal messages: ${result.messageCount}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:message error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error adding message: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'get') {\n // Handle tickets:get\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n if (!ticketSlug) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing ticketSlug parameter. Usage: Provide a ticket number (e.g., \"102\") or full slug (e.g., \"102-fix-auth\").`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).query(\n \"mcp_tickets:getMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug,\n }\n ) as { slug: string; content: string; status: string; createdAt: number; startedAt?: number; closedAt?: number; messages?: Array<{ content: string; createdAt: number }> } | null;\n\n if (!result) {\n return {\n content: [\n {\n type: \"text\",\n text: `Ticket \"${ticketSlug}\" not found in workspace \"${ticketTool.workspaceSlug}\".`,\n },\n ],\n };\n }\n\n // Ticket 151: Updated status labels\n let statusLabel: string;\n if (result.status === 'open') {\n statusLabel = '🟢 OPEN';\n } else if (result.status === 'working') {\n statusLabel = '🟡 WORKING';\n } else {\n statusLabel = '⚫ CLOSED';\n }\n\n const startedInfo = result.startedAt\n ? `\\nStarted: ${new Date(result.startedAt).toISOString()}`\n : '';\n const closedInfo = result.closedAt\n ? `\\nClosed: ${new Date(result.closedAt).toISOString()}`\n : '';\n\n // Ticket 151: Include messages if any\n let messagesSection = '';\n if (result.messages && result.messages.length > 0) {\n const messageList = result.messages\n .map((m) => `[${new Date(m.createdAt).toISOString()}] ${m.content}`)\n .join('\\n');\n messagesSection = `\\n\\n## Progress Messages\\n\\n${messageList}`;\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `# Ticket: ${result.slug}\\n\\nStatus: ${statusLabel}${startedInfo}${closedInfo}\\n\\n---\\n\\n${result.content}${messagesSection}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:get error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error getting ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n }\n }\n\n // Handle user prompt tool invocations\n const prompt = validPrompts.find((p) => buildPromptName(p) === toolName);\n\n if (!prompt) {\n throw new Error(`Unknown tool: ${toolName}`);\n }\n\n // Execute the prompt and return flattened content\n const handler = buildPromptHandler(prompt, config, convexClient);\n const result = await handler();\n\n // Convert prompt result to tool result format\n // Extract text from prompt messages\n const promptText = result.messages\n .map((msg) => (typeof msg.content === 'string' ? msg.content : msg.content.text))\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: \"text\",\n text: promptText,\n },\n ],\n };\n });\n\n // Start server with stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(\"[MCP] Server started successfully\");\n console.error(`[MCP] Deployment: ${config.isDev ? \"DEVELOPMENT\" : \"PRODUCTION\"}`);\n console.error(`[MCP] Convex URL: ${config.convexUrl}`);\n console.error(`[MCP] Data mode: REAL-TIME (fetches fresh data on each invocation)`);\n\n // List all prompts\n const allPromptNames = [...Array.from(promptNames)].sort();\n console.error(`[MCP] Prompts available: ${allPromptNames.join(\", \")}`);\n console.error(`[MCP] - Total prompts: ${promptNames.size}`);\n\n // Keep the event loop alive with a heartbeat\n // This prevents Node from exiting when there are no active handles\n setInterval(() => {\n // Heartbeat every 60 seconds to keep process alive\n }, 60000);\n\n // Return a promise that never resolves to keep the server running\n return new Promise<void>(() => {\n // The transport handles stdin/stdout communication\n // The interval above keeps the event loop active\n });\n}\n\n/**\n * Validate API key with Convex\n */\nasync function validateApiKey(\n client: ConvexHttpClient,\n apiKey: string\n): Promise<{ valid: boolean; userId?: string; error?: string }> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await client.query(\"apiKeys:validateApiKey\" as any, { key: apiKey });\n if (result) {\n return { valid: true, userId: result.userId };\n }\n return { valid: false, error: \"Invalid API key\" };\n } catch (error) {\n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n\n/**\n * Fetch prompts exposed to MCP\n * Passes workspace filter from CLI --workspaces arg (Ticket 144)\n */\nasync function fetchMcpPrompts(\n client: ConvexHttpClient,\n apiKey: string,\n workspaces: string[]\n): Promise<McpPrompt[]> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const prompts = await client.query(\"mcp_prompts:getMcpPrompts\" as any, {\n apiKey,\n workspaces: workspaces.length > 0 ? workspaces : undefined, // Only pass if specified\n });\n return prompts;\n } catch (error) {\n throw new Error(\n `Failed to fetch prompts: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n}\n","import type { ConvexHttpClient } from \"convex/browser\";\nimport type { McpPrompt, ServerConfig } from \"./types.js\";\n\n/**\n * Sanitizes a string for use in MCP tool names.\n * Ensures output matches MCP protocol pattern: ^[a-zA-Z0-9_-]{1,64}$\n *\n * @param str - Raw string to sanitize (workspace slug, folder path, or prompt slug)\n * @returns Sanitized string safe for MCP tool names\n */\nexport function sanitizeForMcp(str: string): string {\n return str\n .trim() // Remove leading/trailing whitespace first\n .toLowerCase() // Convert to lowercase for consistency\n .replace(/[^a-z0-9_-]/g, '-') // Replace ALL invalid chars (including spaces!) with hyphens\n .replace(/-+/g, '-') // Collapse multiple consecutive hyphens into one\n .replace(/^-+|-+$/g, '') // Remove leading and trailing hyphens\n .trim(); // Final trim to ensure no whitespace\n}\n\n/**\n * Build the MCP prompt name for a prompt with workspace scoping\n *\n * MCP tool names must match pattern: ^[a-zA-Z0-9_:-]{1,64}$\n * (letters, numbers, underscores, hyphens, and colons allowed)\n *\n * Format: workspace:prompt\n * - Folders are NOT included in slash command names\n * - Folders are only used for ZIP download organization\n *\n * Character mapping:\n * - Separator: : (colon) between workspace and prompt\n * - Hyphens: - used within multi-word slugs\n * - Example: personal:code-review, work:api-design\n */\nexport function buildPromptName(prompt: McpPrompt): string {\n const workspace = sanitizeForMcp(prompt.workspaceSlug || 'default') || 'default';\n const promptSlug = sanitizeForMcp(prompt.slug || 'unknown') || 'unknown';\n\n // Hierarchical workspace:prompt format\n return `${workspace}:${promptSlug}`.trim();\n}\n\n/**\n * Build the MCP prompt schema for a prompt\n */\nexport function buildPromptSchema(prompt: McpPrompt) {\n return {\n name: buildPromptName(prompt),\n description: prompt.description || `Prompt: ${prompt.name}`,\n arguments: [],\n };\n}\n\n/**\n * Build the prompt execution handler for a prompt\n */\nexport function buildPromptHandler(\n prompt: McpPrompt,\n config: ServerConfig,\n convexClient: ConvexHttpClient\n) {\n return async () => {\n let flattenedPrompt = prompt.flattenedPrompt;\n let promptName = prompt.name;\n\n // Always fetch fresh data from Convex (real-time mode)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let freshPrompts = await convexClient.query(\"mcp_prompts:getMcpPrompts\" as any, {\n apiKey: config.apiKey,\n });\n\n // Apply workspace filter to fresh data if configured\n if (config.selectedWorkspaces.length > 0) {\n freshPrompts = freshPrompts.filter((p: McpPrompt) =>\n p.workspaceSlug && config.selectedWorkspaces.includes(p.workspaceSlug)\n );\n }\n\n const freshPrompt = freshPrompts.find((p: McpPrompt) => p.slug === prompt.slug && p.workspaceSlug === prompt.workspaceSlug);\n\n if (freshPrompt) {\n flattenedPrompt = freshPrompt.flattenedPrompt;\n promptName = freshPrompt.name;\n console.error(`[MCP] Fetched fresh data for: ${buildPromptName(prompt)}`);\n } else {\n console.error(\n `[MCP] WARNING: Prompt \"${prompt.slug}\" not found in fresh fetch, using cached version`\n );\n }\n } catch (error) {\n console.error(\n `[MCP] WARNING: Failed to fetch fresh data, using cached version: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n\n if (!flattenedPrompt) {\n throw new Error(\n `Prompt \"${promptName}\" has no flattened content. Please re-save the prompt in ContextFS to regenerate it.`\n );\n }\n\n console.error(`[MCP] Executed prompt: ${buildPromptName(prompt)}`);\n\n // Return raw flattened prompt (client will parse YAML front matter)\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\" as const,\n text: flattenedPrompt,\n },\n },\n ],\n };\n };\n}\n"],"mappings":"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","names":["result"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/convex-client.ts","../src/server.ts","../src/prompt-builder.ts"],"sourcesContent":["import minimist from \"minimist\";\nimport { createConvexClient } from \"./convex-client.js\";\nimport { startServer } from \"./server.js\";\nimport type { ServerConfig } from \"./types.js\";\n\n/**\n * Main entry point for the MCP server\n */\nasync function main() {\n try {\n // Parse CLI arguments\n const argv = minimist(process.argv.slice(2));\n const isDev = argv.dev === true;\n\n // Parse --workspaces CLI argument (Ticket 144)\n // Can be: --workspaces ws1,ws2 OR --workspaces ws1 --workspaces ws2 OR -w ws1,ws2\n const workspacesArg = argv.workspaces || argv.w;\n let selectedWorkspaces: string[] = [];\n if (workspacesArg) {\n if (Array.isArray(workspacesArg)) {\n // Multiple --workspaces flags: [\"ws1\", \"ws2\"]\n selectedWorkspaces = workspacesArg.flatMap((w: string) => String(w).split(','));\n } else {\n // Single --workspaces flag with comma-separated: \"ws1,ws2\"\n selectedWorkspaces = String(workspacesArg).split(',');\n }\n // Clean up whitespace\n selectedWorkspaces = selectedWorkspaces.map((s) => s.trim()).filter(Boolean);\n }\n\n // Check for API key (PPM_API_KEY with backward compatibility for THEPROMPTEDITOR_API_KEY)\n const apiKey = process.env.PPM_API_KEY || process.env.THEPROMPTEDITOR_API_KEY;\n if (!apiKey) {\n console.error(\n \"[MCP] ERROR: Missing PPM_API_KEY environment variable\"\n );\n console.error(\n \"[MCP] Please set your API key from Prompt Project Manager Settings page:\"\n );\n console.error(\"[MCP] export PPM_API_KEY=your_api_key_here\");\n process.exit(1);\n }\n\n // Create Convex client\n const convexClient = createConvexClient(isDev);\n const convexUrl = isDev\n ? \"https://hallowed-shrimp-344.convex.cloud\"\n : \"https://trustworthy-squirrel-735.convex.cloud\";\n\n // Build server config\n const config: ServerConfig = {\n apiKey,\n isDev,\n convexUrl,\n selectedWorkspaces, // Workspace slugs to filter (empty = all workspaces)\n };\n\n // Start server - this will keep the process alive via stdio transport\n await startServer(config, convexClient);\n\n // This line should never be reached if the promise in startServer never resolves\n console.error(\"[MCP] WARNING: startServer promise resolved unexpectedly!\");\n } catch (error) {\n console.error(\n \"[MCP] FATAL ERROR:\",\n error instanceof Error ? error.message : \"Unknown error\"\n );\n if (error instanceof Error && error.stack) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n}\n\n// Handle graceful shutdown\nprocess.on(\"SIGINT\", () => {\n console.error(\"[MCP] Received SIGINT, shutting down gracefully...\");\n process.exit(0);\n});\n\nprocess.on(\"SIGTERM\", () => {\n console.error(\"[MCP] Received SIGTERM, shutting down gracefully...\");\n process.exit(0);\n});\n\nmain();\n","import { ConvexHttpClient } from \"convex/browser\";\n\nconst PROD_URL = \"https://trustworthy-squirrel-735.convex.cloud\";\nconst DEV_URL = \"https://hallowed-shrimp-344.convex.cloud\";\n\n/**\n * Create a Convex HTTP client for the appropriate deployment\n */\nexport function createConvexClient(isDev: boolean): ConvexHttpClient {\n const url = isDev ? DEV_URL : PROD_URL;\n return new ConvexHttpClient(url);\n}\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { McpPrompt, ServerConfig } from \"./types.js\";\n\n/**\n * Input for the system:optimize-prompt tool\n */\ninterface OptimizePromptInput {\n promptSlug: string;\n workspaceSlug: string;\n suggestions: Array<{\n category: string;\n priority: string;\n issue: string;\n originalText?: string;\n suggestedText: string;\n }>;\n}\n\n/**\n * Result from executing the next ticket (Ticket 151: now moves to working status)\n */\ninterface ExecuteTicketResult {\n content: string | null;\n slug: string;\n status: string; // Ticket 151: \"working\" (no longer \"closed\")\n remainingTickets: number;\n}\n\n/**\n * Close ticket result (Ticket 151)\n */\ninterface CloseTicketResult {\n slug: string;\n status: string;\n closedAt: number;\n}\n\n/**\n * Message result (Ticket 151)\n */\ninterface AddMessageResult {\n ticketSlug: string;\n messageCount: number;\n createdAt: number;\n}\n\nimport { buildPromptHandler, buildPromptName, buildPromptSchema } from \"./prompt-builder.js\";\n\n/**\n * Built-in system tools (with input schemas for submission)\n *\n * Architecture:\n * - system:optimize: User-facing slash command for full prompt evaluation\n * - system:feedback: User-facing slash command for directed feedback via $ARGUMENTS\n * - system:prompts: Utility tool (works as both slash command and tool)\n * - system:optimize-prompt: Backend submission tool ONLY (not a slash command)\n */\nconst SYSTEM_TOOLS: {\n name: string;\n description: string;\n inputSchema: object;\n promptContent: string;\n isSlashCommand: boolean; // true = appears as /ppm:name, false = tool only\n}[] = [\n // User-facing slash command: /ppm:system:optimize\n {\n name: \"system:optimize\",\n description: \"Evaluate a prompt and submit optimization suggestions to Prompt Project Manager\",\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n isSlashCommand: true,\n promptContent: `# Optimize\n\nEvaluate the prompt you just used and submit optimization suggestions.\n\n## Instructions\n\n1. **Identify the prompt** from the PREVIOUS tool call in this conversation:\n - Look at the last \\`/ppm:*\\` slash command or MCP tool you called\n - The format is \\`/ppm:workspace:prompt\\` (e.g., \\`/ppm:test:joke\\` means workspace=\\`test\\`, prompt=\\`joke\\`)\n - Extract the workspace slug (before the colon) and prompt slug (after the colon)\n - **CRITICAL**: Use the EXACT slugs from the tool name, do NOT guess or invent slugs\n\n2. **Evaluate** for issues in these categories:\n - **clarity**: Is the language clear and unambiguous?\n - **specificity**: Are instructions specific enough?\n - **structure**: Is the organization logical?\n - **completeness**: Are there missing instructions?\n - **efficiency**: Is there redundancy to remove?\n\n3. **Call the submission tool** (\\`system:optimize-prompt\\`) with:\n - \\`promptSlug\\`: The prompt's slug\n - \\`workspaceSlug\\`: The workspace slug\n - \\`suggestions\\`: Array of issues found, each with category, priority, issue, originalText (optional), suggestedText\n\n4. The tool will submit and confirm the count\n\n## Scope of Analysis\n\n**CRITICAL - READ CAREFULLY**:\n\nThe flattened prompt contains TWO parts:\n1. **MAIN PROMPT CONTENT** (at the top) - This is what you should analyze\n2. **Technical Reference Footer** (at the bottom) - **COMPLETELY IGNORE THIS ENTIRE SECTION**\n\n**The Technical Reference Footer starts with \\`# Technical Reference\\` and includes:**\n- \\`## Variable Definitions:\\` - Contains variable names, types, and descriptions\n- \\`## Snippet Definitions:\\` - Contains snippet content\n- \\`## CRITICAL RULES:\\` - System rules\n- \\`## Runtime Variables:\\` - Runtime placeholders\n\n**IGNORE ALL CONTENT IN THE TECHNICAL REFERENCE FOOTER** - even if it contains typos, grammar issues, or formatting problems. These sections are auto-generated from user-defined resources and should NOT be optimized through this tool.\n\n**Only analyze and suggest changes for content BEFORE the \\`# Technical Reference\\` heading.**\n\n## User Feedback\n\nIf the user provided feedback about issues they experienced, it appears below:\n\n**Feedback**: $ARGUMENTS\n\nWhen feedback is provided:\n- Treat it as context about real problems encountered during use\n- Prioritize suggestions that address the described issues\n- Look for patterns in the prompt that could cause the mentioned problem\n\n## Important\n\n- Don't suggest changes to variable references like \\`[VARIABLE_NAME]\\` - those are intentional\n- The user will review suggestions in Prompt Project Manager web UI`,\n },\n // User-facing slash command: /ppm:system:feedback\n {\n name: \"system:feedback\",\n description: \"Submit user feedback about a prompt to create an optimization suggestion\",\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n isSlashCommand: true,\n promptContent: `# Feedback\n\nSubmit your feedback about a prompt to create an optimization suggestion.\n\n## Instructions\n\n1. **Identify the prompt** from the PREVIOUS tool call in this conversation:\n - Look at the last \\`/ppm:*\\` slash command or MCP tool you called\n - The format is \\`/ppm:workspace:prompt\\` (e.g., \\`/ppm:test:joke\\` means workspace=\\`test\\`, prompt=\\`joke\\`)\n - Extract the workspace slug (before the colon) and prompt slug (after the colon)\n - **CRITICAL**: Use the EXACT slugs from the tool name, do NOT guess or invent slugs\n\n2. **Read the user's feedback** from $ARGUMENTS below\n\n3. **Structure the feedback** into a proper optimization suggestion:\n - Determine the most appropriate category: clarity, specificity, structure, completeness, or efficiency\n - Assess priority: \"high\" (critical issue), \"medium\" (noticeable problem), \"low\" (minor improvement)\n - Identify the specific text to change (originalText) if applicable\n - Write a clear, actionable fix (suggestedText)\n\n4. **Call the submission tool** (\\`system:optimize-prompt\\`) with:\n - \\`promptSlug\\`: The prompt's slug\n - \\`workspaceSlug\\`: The workspace slug\n - \\`suggestions\\`: Array containing a SINGLE suggestion based on the user's feedback\n\n## User Feedback\n\n**$ARGUMENTS**\n\n## Scope of Analysis\n\nWhen analyzing the prompt to address the feedback:\n- **ONLY** focus on content BEFORE the \\`# Technical Reference\\` heading\n- **IGNORE** the Technical Reference Footer (Variable Definitions, Snippet Definitions, CRITICAL RULES, Runtime Variables)\n- Don't suggest changes to variable references like \\`[VARIABLE_NAME]\\` - those are intentional\n\n## Example\n\nIf the user runs:\n\\`/feedback the output format should specify JSON not markdown\\`\n\nYou should:\n1. Find the prompt that was used earlier in the session\n2. Create a suggestion like:\n \\`\\`\\`json\n {\n \"category\": \"specificity\",\n \"priority\": \"medium\",\n \"issue\": \"Output format should specify JSON instead of markdown\",\n \"originalText\": \"Output format: markdown\",\n \"suggestedText\": \"Output format: JSON with fields: { result: string, status: string }\"\n }\n \\`\\`\\`\n3. Submit via \\`system:optimize-prompt\\` tool\n\n## Important\n\n- Create exactly ONE suggestion from the user's feedback (not multiple)\n- The suggestion will be reviewed in Prompt Project Manager web UI\n- Use your understanding of the session to interpret vague feedback into actionable fixes`,\n },\n // Utility tool: /ppm:system:prompts\n {\n name: \"system:prompts\",\n description: \"List all available prompts from Prompt Project Manager\",\n inputSchema: {\n type: \"object\",\n properties: {\n search: {\n type: \"string\",\n description: \"Optional search term to filter prompts by name or description (case-insensitive)\",\n },\n },\n },\n isSlashCommand: true,\n promptContent: `# List Prompts\n\nThis is a utility tool. Call it directly as a tool to list all available prompts.\n\nExample: Use the \\`system:prompts\\` tool with optional \\`search\\` parameter to filter results.`,\n },\n // Backend submission tool (called by system:optimize and system:feedback)\n // NOT a slash command - only available as a tool for AI to call\n {\n name: \"system:optimize-prompt\",\n description: \"Submit optimization suggestions to Prompt Project Manager (internal tool)\",\n inputSchema: {\n type: \"object\",\n properties: {\n promptSlug: {\n type: \"string\",\n description: \"The slug of the prompt to optimize (e.g., 'code-review')\",\n },\n workspaceSlug: {\n type: \"string\",\n description: \"The workspace containing the prompt (e.g., 'personal')\",\n },\n suggestions: {\n type: \"array\",\n description: \"Array of optimization suggestions\",\n items: {\n type: \"object\",\n properties: {\n category: {\n type: \"string\",\n description: \"Category: 'clarity', 'specificity', 'structure', 'completeness', 'efficiency'\",\n },\n priority: {\n type: \"string\",\n enum: [\"high\", \"medium\", \"low\"],\n description: \"Priority level\",\n },\n issue: {\n type: \"string\",\n description: \"Brief description of the problem\",\n },\n originalText: {\n type: \"string\",\n description: \"Optional: The specific text that should be changed\",\n },\n suggestedText: {\n type: \"string\",\n description: \"The improved text\",\n },\n },\n required: [\"category\", \"priority\", \"issue\", \"suggestedText\"],\n },\n },\n },\n required: [\"promptSlug\", \"workspaceSlug\", \"suggestions\"],\n },\n isSlashCommand: false, // Tool only - not a slash command\n promptContent: `# Submit Optimization Suggestions\n\nThis is an internal submission tool. Do not call it directly.\n\nUse \\`/ppm:system:optimize\\` for full prompt evaluation or \\`/ppm:system:feedback\\` to submit specific feedback.`,\n },\n];\n\n/**\n * Initialize and start the MCP server\n */\nexport async function startServer(\n config: ServerConfig,\n convexClient: ConvexHttpClient\n): Promise<void> {\n // Validate API key with Convex\n console.error(\"[MCP] Validating API key...\");\n const validation = await validateApiKey(convexClient, config.apiKey);\n if (!validation.valid) {\n throw new Error(`Invalid API key: ${validation.error}`);\n }\n console.error(`[MCP] API key validated for user: ${validation.userId}`);\n\n // Fetch prompts exposed to MCP (with optional workspace filter from CLI)\n console.error(\"[MCP] Fetching exposed prompts...\");\n const prompts = await fetchMcpPrompts(convexClient, config.apiKey, config.selectedWorkspaces);\n console.error(`[MCP] Found ${prompts.length} exposed prompts`);\n\n if (prompts.length === 0) {\n if (config.selectedWorkspaces.length > 0) {\n console.error(\n `[MCP] WARNING: No prompts found in workspaces: ${config.selectedWorkspaces.join(', ')}. Check that these workspace slugs exist and contain prompts.`\n );\n } else {\n console.error(\n \"[MCP] WARNING: No prompts found. Create some prompts in Prompt Project Manager to expose them via MCP.\"\n );\n }\n }\n\n // Filter out prompts with missing flattened content\n const validPrompts = prompts.filter((p) => {\n if (!p.flattenedPrompt) {\n console.error(\n `[MCP] WARNING: Skipping prompt \"${p.name}\" (${p.slug}) - missing flattened content. Re-save in ContextFS to regenerate.`\n );\n return false;\n }\n return true;\n });\n\n // Log workspace filtering info (Ticket 144)\n if (config.selectedWorkspaces.length > 0) {\n console.error(`[MCP] Workspace filter: ${config.selectedWorkspaces.join(', ')}`);\n } else {\n console.error(`[MCP] Workspace filter: ALL (no --workspaces specified)`);\n }\n console.error(`[MCP] Registering ${validPrompts.length} prompts...`);\n\n // Build dynamic ticket tools per workspace (Ticket 135, 149, 151, 153)\n // Streamlined command set: open, work, close, message, create\n const workspaceSlugs = new Set(validPrompts.map((p) => p.workspaceSlug).filter((s): s is string => !!s));\n const dynamicTicketTools: { name: string; description: string; workspaceSlug: string; type: 'open' | 'work' | 'close' | 'message' | 'create' }[] = [];\n\n for (const workspaceSlug of workspaceSlugs) {\n // Ticket 153: tickets:open (renamed from tickets:next)\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:open`,\n description: `Open the next ticket from the \"${workspaceSlug}\" workspace queue and move it to working status. Optionally specify a ticket number or slug.`,\n workspaceSlug,\n type: 'open',\n });\n // Ticket 153: tickets:work (context recovery for working tickets)\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:work`,\n description: `Resume work on a ticket in the \"${workspaceSlug}\" workspace. Returns ticket content and all progress messages for context recovery.`,\n workspaceSlug,\n type: 'work',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:close`,\n description: `Mark a working ticket as completed in the \"${workspaceSlug}\" workspace`,\n workspaceSlug,\n type: 'close',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:message`,\n description: `Add a progress message to a working or closed ticket in the \"${workspaceSlug}\" workspace`,\n workspaceSlug,\n type: 'message',\n });\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:create`,\n description: `Create a new ticket in the \"${workspaceSlug}\" workspace queue`,\n workspaceSlug,\n type: 'create',\n });\n }\n\n console.error(`[MCP] Registering ${dynamicTicketTools.length} ticket tools for ${workspaceSlugs.size} workspace(s)...`);\n\n // Check for duplicate prompt names\n const promptNames = new Set<string>();\n const duplicates: string[] = [];\n validPrompts.forEach((p) => {\n const name = buildPromptName(p);\n if (promptNames.has(name)) {\n duplicates.push(name);\n }\n promptNames.add(name);\n });\n\n if (duplicates.length > 0) {\n console.error(\n `[MCP] WARNING: Duplicate prompt names detected: ${duplicates.join(\", \")}. Only the first occurrence will be registered.`\n );\n }\n\n // Create MCP server\n const server = new Server(\n {\n name: \"ppm-mcp-server\",\n version: \"2.8.1\",\n },\n {\n capabilities: {\n prompts: {},\n tools: {},\n },\n }\n );\n\n // Register list_prompts handler\n server.setRequestHandler(ListPromptsRequestSchema, async () => {\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Build system tool schemas (only those marked as slash commands)\n const systemPromptSchemas = SYSTEM_TOOLS\n .filter((st) => st.isSlashCommand) // Only include user-facing slash commands\n .map((st) => ({\n name: st.name,\n description: st.description,\n }));\n\n // Build ticket prompt schemas (Ticket 135, 149, 153 - register as slash commands)\n // All ticket tools are available as slash commands\n const ticketPromptSchemas = dynamicTicketTools.map((tt) => ({\n name: tt.name,\n description: tt.description,\n }));\n\n return {\n prompts: [\n ...systemPromptSchemas,\n ...ticketPromptSchemas,\n ...uniquePrompts.map(buildPromptSchema),\n ],\n };\n });\n\n // Register get_prompt handler\n server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const promptName = request.params.name;\n\n // Check for system tools first (as prompts for slash command access)\n const systemTool = SYSTEM_TOOLS.find((st) => st.name === promptName);\n if (systemTool) {\n return {\n description: systemTool.description,\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: systemTool.promptContent,\n },\n },\n ],\n };\n }\n\n // Check for ticket commands (Ticket 135, 149, 153 - handle as slash commands)\n // Handle exact matches and :open with optional argument (e.g., \"workspace:tickets:open 102\")\n const ticketTool = dynamicTicketTools.find((tt) => tt.name === promptName);\n const ticketOpenMatch = promptName.match(/^(.+):tickets:open\\s+(.+)$/);\n\n if (ticketTool || ticketOpenMatch) {\n let promptContent: string;\n let description: string;\n\n if (ticketOpenMatch) {\n // Handle tickets:open with specific ticket argument\n const workspaceSlug = ticketOpenMatch[1];\n const ticketArg = ticketOpenMatch[2].trim();\n description = `Open ticket \"${ticketArg}\" from \"${workspaceSlug}\"`;\n promptContent = `Open ticket \"${ticketArg}\" from the \"${workspaceSlug}\" workspace queue and move it to working status.\\n\\nCall the \\`${workspaceSlug}:tickets:open\\` tool with ticketSlug: \"${ticketArg}\".`;\n } else if (ticketTool!.type === 'open') {\n // Ticket 153: tickets:open (renamed from tickets:next)\n description = ticketTool!.description;\n promptContent = `Open the next ticket from the \"${ticketTool!.workspaceSlug}\" workspace queue and move it to working status.\\n\\nCall the \\`${ticketTool!.name}\\` tool to get the next ticket.\\n\\nYou can also specify a ticket: /ppm:${ticketTool!.workspaceSlug}:tickets:open <number-or-slug>`;\n } else if (ticketTool!.type === 'work') {\n // Ticket 153: tickets:work (context recovery)\n description = ticketTool!.description;\n promptContent = `Resume work on a ticket in the \"${ticketTool!.workspaceSlug}\" workspace.\\n\\nCall the \\`${ticketTool!.name}\\` tool to get ticket content and all progress messages for context recovery.\\n\\nIf no ticket slug is provided, returns the first working ticket (by startedAt).\\n\\nYou can also specify a ticket: /ppm:${ticketTool!.workspaceSlug}:tickets:work <number-or-slug>`;\n } else if (ticketTool!.type === 'create') {\n // Ticket 149: tickets:create slash command\n description = ticketTool!.description;\n promptContent = `Create a new ticket in the \"${ticketTool!.workspaceSlug}\" workspace queue.\n\n## How This Works\nThe user provides **instructions** (not raw content). You interpret those instructions to generate the ticket.\n\n## Instructions\n1. **Read the user's request** - they may reference a file, ask you to summarize a session, or describe what they want\n2. **Process the input** - read files, extract relevant sections, summarize as needed\n3. **Generate ticket content** with a clear, descriptive title as the first line\n4. **Call the tool** with the generated content\n\n## Content Format\n\\`\\`\\`\n[Clear descriptive title - this becomes the slug]\n\n[Body content - tasks, description, context, etc.]\n\\`\\`\\`\n\n## Examples\n- \"create a ticket from /path/to/plan.md\" → Read file, use as ticket content\n- \"summarize our brainstorm into a ticket\" → Extract key points from conversation\n- \"create a ticket for the auth bug we discussed\" → Generate from session context\n- \"just the tasks from this file\" → Extract only task items\n\nCall the \\`${ticketTool!.name}\\` tool with the final generated content.`;\n } else if (ticketTool!.type === 'close') {\n description = ticketTool!.description;\n promptContent = `Close a working ticket in the \"${ticketTool!.workspaceSlug}\" workspace.\\n\\nCall the \\`${ticketTool!.name}\\` tool with the ticket number or slug.`;\n } else if (ticketTool!.type === 'message') {\n description = ticketTool!.description;\n promptContent = `Add a progress message to a working or closed ticket in the \"${ticketTool!.workspaceSlug}\" workspace.\\n\\nCall the \\`${ticketTool!.name}\\` tool with the ticket number/slug and your message.`;\n } else {\n // Fallback for unknown type\n description = ticketTool!.description;\n promptContent = `Use the \\`${ticketTool!.name}\\` tool.`;\n }\n\n return {\n description,\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: promptContent,\n },\n },\n ],\n };\n }\n\n // Check user prompts\n const prompt = validPrompts.find((p) => buildPromptName(p) === promptName);\n\n if (!prompt) {\n throw new Error(`Unknown prompt: ${promptName}`);\n }\n\n const handler = buildPromptHandler(prompt, config, convexClient);\n return await handler();\n });\n\n // Register list_tools handler\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Build tools array: system tools + ticket tools + each user prompt as a tool\n const tools = [\n // System tools with full input schemas\n ...SYSTEM_TOOLS.map((st) => ({\n name: st.name,\n description: st.description,\n inputSchema: st.inputSchema,\n })),\n // Dynamic ticket tools per workspace (Ticket 135, 149, 151, 153)\n ...dynamicTicketTools.map((tt) => {\n // Build inputSchema based on tool type\n let inputSchema: { type: \"object\"; properties: Record<string, object>; required: string[] };\n\n if (tt.type === 'close') {\n // close requires a ticketSlug\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth')\",\n },\n },\n required: [\"ticketSlug\"],\n };\n } else if (tt.type === 'open') {\n // Ticket 153: tickets:open (renamed from tickets:next)\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Optional: Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth'). If not provided, opens the next ticket in queue.\",\n },\n },\n required: [],\n };\n } else if (tt.type === 'work') {\n // Ticket 153: tickets:work (context recovery)\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Optional: Ticket number (e.g., '102') or full slug. If not provided, returns the first working ticket by startedAt.\",\n },\n },\n required: [],\n };\n } else if (tt.type === 'create') {\n inputSchema = {\n type: \"object\" as const,\n properties: {\n content: {\n type: \"string\",\n description: \"The generated ticket content. First line should be a clear descriptive title (becomes the slug). Body contains tasks, description, context as needed.\",\n },\n },\n required: [\"content\"],\n };\n } else if (tt.type === 'message') {\n // Ticket 151: message requires ticketSlug and message\n inputSchema = {\n type: \"object\" as const,\n properties: {\n ticketSlug: {\n type: \"string\",\n description: \"Ticket number (e.g., '102') or full slug (e.g., '102-fix-auth')\",\n },\n message: {\n type: \"string\",\n description: \"Progress message to add to the ticket\",\n },\n },\n required: [\"ticketSlug\", \"message\"],\n };\n } else {\n // Fallback: no params\n inputSchema = {\n type: \"object\" as const,\n properties: {},\n required: [],\n };\n }\n\n return {\n name: tt.name,\n description: tt.description,\n inputSchema,\n };\n }),\n // Each user prompt becomes a discoverable tool\n ...uniquePrompts.map((prompt) => ({\n name: buildPromptName(prompt),\n description: prompt.description || `Prompt: ${prompt.name}`,\n inputSchema: {\n type: \"object\" as const,\n properties: {},\n required: [],\n },\n })),\n ];\n\n return { tools };\n });\n\n // Register call_tool handler\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const toolName = request.params.name;\n\n // Handle system:prompts tool\n if (toolName === \"system:prompts\") {\n const searchTerm = request.params.arguments?.search as string | undefined;\n const uniquePrompts = Array.from(\n new Map(validPrompts.map((p) => [buildPromptName(p), p])).values()\n );\n\n // Filter system tools\n let filteredSystemTools = SYSTEM_TOOLS;\n if (searchTerm) {\n const lowerSearch = searchTerm.toLowerCase();\n filteredSystemTools = SYSTEM_TOOLS.filter(\n (st) =>\n st.name.toLowerCase().includes(lowerSearch) ||\n st.description.toLowerCase().includes(lowerSearch)\n );\n }\n\n // Filter user prompts\n let filteredPrompts = uniquePrompts;\n if (searchTerm) {\n const lowerSearch = searchTerm.toLowerCase();\n filteredPrompts = uniquePrompts.filter(\n (p) =>\n buildPromptName(p).toLowerCase().includes(lowerSearch) ||\n p.name.toLowerCase().includes(lowerSearch) ||\n p.description?.toLowerCase().includes(lowerSearch)\n );\n }\n\n // Sort user prompts by workspace then by prompt slug\n filteredPrompts.sort((a, b) => {\n const aName = buildPromptName(a);\n const bName = buildPromptName(b);\n return aName.localeCompare(bName);\n });\n\n // Build system tools list\n const systemToolList = filteredSystemTools\n .map((st) => `• ${st.name}\\n Type: System\\n Description: ${st.description}`)\n .join(\"\\n\\n\");\n\n // Build user prompts list\n const userPromptList = filteredPrompts\n .map((p) => {\n const name = buildPromptName(p);\n const workspace = p.workspaceSlug || \"unknown\";\n const desc = p.description || \"No description\";\n return `• ${name}\\n Workspace: ${workspace}\\n Description: ${desc}`;\n })\n .join(\"\\n\\n\");\n\n const totalCount = filteredSystemTools.length + filteredPrompts.length;\n const summary = searchTerm\n ? `Found ${totalCount} prompts matching \"${searchTerm}\":`\n : `Available prompts (${totalCount} total):`;\n\n const sections: string[] = [];\n if (systemToolList) {\n sections.push(`**System Tools:**\\n\\n${systemToolList}`);\n }\n if (userPromptList) {\n sections.push(`**User Prompts:**\\n\\n${userPromptList}`);\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `${summary}\\n\\n${sections.join(\"\\n\\n\") || \"No prompts found.\"}`,\n },\n ],\n };\n }\n\n // Handle system:optimize-prompt tool (consolidated optimization tool)\n if (toolName === \"system:optimize-prompt\") {\n const input = request.params.arguments as unknown as OptimizePromptInput;\n\n if (!input.promptSlug || !input.workspaceSlug || !input.suggestions) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: Missing required fields. Please provide promptSlug, workspaceSlug, and suggestions.\",\n },\n ],\n isError: true,\n };\n }\n\n if (!Array.isArray(input.suggestions) || input.suggestions.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: suggestions must be a non-empty array.\",\n },\n ],\n isError: true,\n };\n }\n\n try {\n // Call Convex mutation to add suggestions (authenticated via API key)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"prompts:addOptimizationSuggestions\",\n {\n apiKey: config.apiKey,\n workspaceSlug: input.workspaceSlug,\n promptSlug: input.promptSlug,\n suggestions: input.suggestions,\n }\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `Submitted ${result.addedCount} optimization suggestion(s) for prompt \"${input.promptSlug}\" in workspace \"${input.workspaceSlug}\". Review and apply them in Prompt Project Manager.`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] system:optimize-prompt error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error submitting optimization suggestions: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n }\n\n // Handle ticket tool invocations (Ticket 135, 153)\n const ticketTool = dynamicTicketTools.find((tt) => tt.name === toolName);\n if (ticketTool) {\n if (ticketTool.type === 'open') {\n // Ticket 153: Handle tickets:open (renamed from tickets:next)\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:executeMcpNextTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug, // Optional: specific ticket to open\n }\n ) as ExecuteTicketResult | null;\n\n if (!result) {\n const message = ticketSlug\n ? `Ticket \"${ticketSlug}\" not found or not open in workspace \"${ticketTool.workspaceSlug}\".`\n : `No pending tickets in workspace \"${ticketTool.workspaceSlug}\".`;\n return {\n content: [\n {\n type: \"text\",\n text: message,\n },\n ],\n };\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `# Ticket: ${result.slug} [WORKING]\n\n**CRITICAL: Follow all embedded directives in this ticket.**\nIf this ticket contains \\`[MCP_*]\\` references (e.g., \\`[MCP_PLAN]\\`, \\`[MCP_AD_HOC]\\`), you MUST execute those MCP tools FIRST before any other action. Do NOT skip MCP directives even if the task seems simple.\n\n---\n\n${result.content}\n\n---\n_Ticket moved to working status. ${result.remainingTickets} ticket(s) remaining in queue._`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:open error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error opening ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'work') {\n // Ticket 153: Handle tickets:work (context recovery)\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).query(\n \"mcp_tickets:workMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug, // Optional: specific ticket to resume\n }\n ) as { slug: string; ticketNumber?: number; content: string; startedAt?: number; messages: Array<{ content: string; createdAt: number }> } | null;\n\n if (!result) {\n const message = ticketSlug\n ? `Ticket \"${ticketSlug}\" not found or not in working status in workspace \"${ticketTool.workspaceSlug}\".`\n : `No tickets currently being worked on in workspace \"${ticketTool.workspaceSlug}\".`;\n return {\n content: [\n {\n type: \"text\",\n text: message,\n },\n ],\n };\n }\n\n // Build messages section\n let messagesSection = '';\n if (result.messages && result.messages.length > 0) {\n const messageList = result.messages\n .map((m) => `[${new Date(m.createdAt).toISOString()}] ${m.content}`)\n .join('\\n');\n messagesSection = `\\n\\n## Progress Messages\\n\\n${messageList}`;\n }\n\n const startedInfo = result.startedAt\n ? `\\nStarted: ${new Date(result.startedAt).toISOString()}`\n : '';\n\n return {\n content: [\n {\n type: \"text\",\n text: `# Ticket: ${result.slug} [WORKING]${startedInfo}\n\n**CRITICAL: Follow all embedded directives in this ticket.**\nIf this ticket contains \\`[MCP_*]\\` references (e.g., \\`[MCP_PLAN]\\`, \\`[MCP_AD_HOC]\\`), you MUST execute those MCP tools FIRST before any other action. Do NOT skip MCP directives even if the task seems simple.\n\n---\n\n${result.content}${messagesSection}\n\n---\n_Resuming work on this ticket._`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:work error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error resuming ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'create') {\n // Handle tickets:create (Ticket 149)\n const content = request.params.arguments?.content as string | undefined;\n\n if (!content) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing content parameter. Provide the ticket content (first line becomes the slug).`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:createMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n content,\n }\n ) as { slug: string; preview: string; position: number; totalOpen: number };\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Created ticket [${result.slug}] in workspace \"${ticketTool.workspaceSlug}\".\n\nPosition: #${result.position} of ${result.totalOpen} open tickets\nPreview: ${result.preview}\n\n_Note: If this ticket contains \\`[MCP_*]\\` directives, they will be mandatory when opened._`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:create error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error creating ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'close') {\n // Ticket 151: Handle tickets:close\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n\n if (!ticketSlug) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing ticketSlug parameter. Usage: Provide a ticket number (e.g., \"102\") or full slug (e.g., \"102-fix-auth\").`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:closeMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug,\n }\n ) as CloseTicketResult;\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Ticket [${result.slug}] closed in workspace \"${ticketTool.workspaceSlug}\".\n\nClosed at: ${new Date(result.closedAt).toISOString()}\n\n_Reminder: Ensure all embedded \\`[MCP_*]\\` directives were executed before closing._`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:close error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error closing ticket: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n } else if (ticketTool.type === 'message') {\n // Ticket 151: Handle tickets:message\n const ticketSlug = request.params.arguments?.ticketSlug as string | undefined;\n const message = request.params.arguments?.message as string | undefined;\n\n if (!ticketSlug || !message) {\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Missing required parameters. Provide ticketSlug and message.`,\n },\n ],\n isError: true,\n };\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (convexClient as any).mutation(\n \"mcp_tickets:addMcpTicketMessage\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug,\n message: message,\n }\n ) as AddMessageResult;\n\n return {\n content: [\n {\n type: \"text\",\n text: `✅ Message added to ticket [${result.ticketSlug}].\\n\\nTotal messages: ${result.messageCount}`,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`[MCP] tickets:message error:`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `Error adding message: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n }\n }\n\n // Handle user prompt tool invocations\n const prompt = validPrompts.find((p) => buildPromptName(p) === toolName);\n\n if (!prompt) {\n throw new Error(`Unknown tool: ${toolName}`);\n }\n\n // Execute the prompt and return flattened content\n const handler = buildPromptHandler(prompt, config, convexClient);\n const result = await handler();\n\n // Convert prompt result to tool result format\n // Extract text from prompt messages\n const promptText = result.messages\n .map((msg) => (typeof msg.content === 'string' ? msg.content : msg.content.text))\n .join('\\n\\n');\n\n return {\n content: [\n {\n type: \"text\",\n text: promptText,\n },\n ],\n };\n });\n\n // Start server with stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(\"[MCP] Server started successfully\");\n console.error(`[MCP] Deployment: ${config.isDev ? \"DEVELOPMENT\" : \"PRODUCTION\"}`);\n console.error(`[MCP] Convex URL: ${config.convexUrl}`);\n console.error(`[MCP] Data mode: REAL-TIME (fetches fresh data on each invocation)`);\n\n // List all prompts\n const allPromptNames = [...Array.from(promptNames)].sort();\n console.error(`[MCP] Prompts available: ${allPromptNames.join(\", \")}`);\n console.error(`[MCP] - Total prompts: ${promptNames.size}`);\n\n // Keep the event loop alive with a heartbeat\n // This prevents Node from exiting when there are no active handles\n setInterval(() => {\n // Heartbeat every 60 seconds to keep process alive\n }, 60000);\n\n // Return a promise that never resolves to keep the server running\n return new Promise<void>(() => {\n // The transport handles stdin/stdout communication\n // The interval above keeps the event loop active\n });\n}\n\n/**\n * Validate API key with Convex\n */\nasync function validateApiKey(\n client: ConvexHttpClient,\n apiKey: string\n): Promise<{ valid: boolean; userId?: string; error?: string }> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await client.query(\"apiKeys:validateApiKey\" as any, { key: apiKey });\n if (result) {\n return { valid: true, userId: result.userId };\n }\n return { valid: false, error: \"Invalid API key\" };\n } catch (error) {\n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n\n/**\n * Fetch prompts exposed to MCP\n * Passes workspace filter from CLI --workspaces arg (Ticket 144)\n */\nasync function fetchMcpPrompts(\n client: ConvexHttpClient,\n apiKey: string,\n workspaces: string[]\n): Promise<McpPrompt[]> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const prompts = await client.query(\"mcp_prompts:getMcpPrompts\" as any, {\n apiKey,\n workspaces: workspaces.length > 0 ? workspaces : undefined, // Only pass if specified\n });\n return prompts;\n } catch (error) {\n throw new Error(\n `Failed to fetch prompts: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n}\n","import type { ConvexHttpClient } from \"convex/browser\";\nimport type { McpPrompt, ServerConfig } from \"./types.js\";\n\n/**\n * Sanitizes a string for use in MCP tool names.\n * Ensures output matches MCP protocol pattern: ^[a-zA-Z0-9_-]{1,64}$\n *\n * @param str - Raw string to sanitize (workspace slug, folder path, or prompt slug)\n * @returns Sanitized string safe for MCP tool names\n */\nexport function sanitizeForMcp(str: string): string {\n return str\n .trim() // Remove leading/trailing whitespace first\n .toLowerCase() // Convert to lowercase for consistency\n .replace(/[^a-z0-9_-]/g, '-') // Replace ALL invalid chars (including spaces!) with hyphens\n .replace(/-+/g, '-') // Collapse multiple consecutive hyphens into one\n .replace(/^-+|-+$/g, '') // Remove leading and trailing hyphens\n .trim(); // Final trim to ensure no whitespace\n}\n\n/**\n * Build the MCP prompt name for a prompt with workspace scoping\n *\n * MCP tool names must match pattern: ^[a-zA-Z0-9_:-]{1,64}$\n * (letters, numbers, underscores, hyphens, and colons allowed)\n *\n * Format: workspace:prompt\n * - Folders are NOT included in slash command names\n * - Folders are only used for ZIP download organization\n *\n * Character mapping:\n * - Separator: : (colon) between workspace and prompt\n * - Hyphens: - used within multi-word slugs\n * - Example: personal:code-review, work:api-design\n */\nexport function buildPromptName(prompt: McpPrompt): string {\n const workspace = sanitizeForMcp(prompt.workspaceSlug || 'default') || 'default';\n const promptSlug = sanitizeForMcp(prompt.slug || 'unknown') || 'unknown';\n\n // Hierarchical workspace:prompt format\n return `${workspace}:${promptSlug}`.trim();\n}\n\n/**\n * Build the MCP prompt schema for a prompt\n */\nexport function buildPromptSchema(prompt: McpPrompt) {\n return {\n name: buildPromptName(prompt),\n description: prompt.description || `Prompt: ${prompt.name}`,\n arguments: [],\n };\n}\n\n/**\n * Build the prompt execution handler for a prompt\n */\nexport function buildPromptHandler(\n prompt: McpPrompt,\n config: ServerConfig,\n convexClient: ConvexHttpClient\n) {\n return async () => {\n let flattenedPrompt = prompt.flattenedPrompt;\n let promptName = prompt.name;\n\n // Always fetch fresh data from Convex (real-time mode)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let freshPrompts = await convexClient.query(\"mcp_prompts:getMcpPrompts\" as any, {\n apiKey: config.apiKey,\n });\n\n // Apply workspace filter to fresh data if configured\n if (config.selectedWorkspaces.length > 0) {\n freshPrompts = freshPrompts.filter((p: McpPrompt) =>\n p.workspaceSlug && config.selectedWorkspaces.includes(p.workspaceSlug)\n );\n }\n\n const freshPrompt = freshPrompts.find((p: McpPrompt) => p.slug === prompt.slug && p.workspaceSlug === prompt.workspaceSlug);\n\n if (freshPrompt) {\n flattenedPrompt = freshPrompt.flattenedPrompt;\n promptName = freshPrompt.name;\n console.error(`[MCP] Fetched fresh data for: ${buildPromptName(prompt)}`);\n } else {\n console.error(\n `[MCP] WARNING: Prompt \"${prompt.slug}\" not found in fresh fetch, using cached version`\n );\n }\n } catch (error) {\n console.error(\n `[MCP] WARNING: Failed to fetch fresh data, using cached version: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n\n if (!flattenedPrompt) {\n throw new Error(\n `Prompt \"${promptName}\" has no flattened content. Please re-save the prompt in ContextFS to regenerate it.`\n );\n }\n\n console.error(`[MCP] Executed prompt: ${buildPromptName(prompt)}`);\n\n // Return raw flattened prompt (client will parse YAML front matter)\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\" as const,\n text: flattenedPrompt,\n },\n },\n ],\n };\n };\n}\n"],"mappings":"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","names":["result"]}
|
package/package.json
CHANGED