@promptprojectmanager/mcp-server 2.8.2 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +107 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
ListPromptsRequestSchema,
|
|
22
22
|
ListToolsRequestSchema
|
|
23
23
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
24
|
+
import * as fs from "fs";
|
|
25
|
+
import * as path from "path";
|
|
24
26
|
|
|
25
27
|
// src/prompt-builder.ts
|
|
26
28
|
function sanitizeForMcp(str) {
|
|
@@ -352,10 +354,10 @@ async function startServer(config, convexClient) {
|
|
|
352
354
|
type: "list"
|
|
353
355
|
});
|
|
354
356
|
dynamicTicketTools.push({
|
|
355
|
-
name: `${workspaceSlug}:tickets:
|
|
356
|
-
description: `
|
|
357
|
+
name: `${workspaceSlug}:tickets:work`,
|
|
358
|
+
description: `Start work on a ticket with local session files in the "${workspaceSlug}" workspace. Optionally specify a ticket number or slug.`,
|
|
357
359
|
workspaceSlug,
|
|
358
|
-
type: "
|
|
360
|
+
type: "work"
|
|
359
361
|
});
|
|
360
362
|
dynamicTicketTools.push({
|
|
361
363
|
name: `${workspaceSlug}:tickets:working`,
|
|
@@ -371,7 +373,7 @@ async function startServer(config, convexClient) {
|
|
|
371
373
|
});
|
|
372
374
|
dynamicTicketTools.push({
|
|
373
375
|
name: `${workspaceSlug}:tickets:message`,
|
|
374
|
-
description: `Add a progress message to a working ticket in the "${workspaceSlug}" workspace`,
|
|
376
|
+
description: `Add a progress message to a working or closed ticket in the "${workspaceSlug}" workspace`,
|
|
375
377
|
workspaceSlug,
|
|
376
378
|
type: "message"
|
|
377
379
|
});
|
|
@@ -453,29 +455,29 @@ async function startServer(config, convexClient) {
|
|
|
453
455
|
};
|
|
454
456
|
}
|
|
455
457
|
const ticketTool = dynamicTicketTools.find((tt) => tt.name === promptName);
|
|
456
|
-
const
|
|
457
|
-
if (ticketTool ||
|
|
458
|
+
const ticketWorkMatch = promptName.match(/^(.+):tickets:work\s+(.+)$/);
|
|
459
|
+
if (ticketTool || ticketWorkMatch) {
|
|
458
460
|
let promptContent;
|
|
459
461
|
let description;
|
|
460
|
-
if (
|
|
461
|
-
const workspaceSlug =
|
|
462
|
-
const ticketArg =
|
|
463
|
-
description = `
|
|
464
|
-
promptContent = `
|
|
462
|
+
if (ticketWorkMatch) {
|
|
463
|
+
const workspaceSlug = ticketWorkMatch[1];
|
|
464
|
+
const ticketArg = ticketWorkMatch[2].trim();
|
|
465
|
+
description = `Start work on ticket "${ticketArg}" from "${workspaceSlug}"`;
|
|
466
|
+
promptContent = `Start work on ticket "${ticketArg}" from the "${workspaceSlug}" workspace queue.
|
|
465
467
|
|
|
466
|
-
Call the \`${workspaceSlug}:tickets:
|
|
468
|
+
Call the \`${workspaceSlug}:tickets:work\` tool with ticketSlug: "${ticketArg}" to start working on the specified ticket.`;
|
|
467
469
|
} else if (ticketTool.type === "list") {
|
|
468
470
|
description = ticketTool.description;
|
|
469
471
|
promptContent = `List all pending tickets in the "${ticketTool.workspaceSlug}" workspace queue.
|
|
470
472
|
|
|
471
473
|
Call the \`${ticketTool.name}\` tool to get the list.`;
|
|
472
|
-
} else if (ticketTool.type === "
|
|
474
|
+
} else if (ticketTool.type === "work") {
|
|
473
475
|
description = ticketTool.description;
|
|
474
|
-
promptContent = `
|
|
476
|
+
promptContent = `Start work on the next ticket from the "${ticketTool.workspaceSlug}" workspace queue.
|
|
475
477
|
|
|
476
|
-
Call the \`${ticketTool.name}\` tool to get the next ticket.
|
|
478
|
+
Call the \`${ticketTool.name}\` tool to get the next ticket and move it to working status. Local session files will be created if PPM directory is configured.
|
|
477
479
|
|
|
478
|
-
You can also specify a ticket: /ppm:${ticketTool.workspaceSlug}:tickets:
|
|
480
|
+
You can also specify a ticket: /ppm:${ticketTool.workspaceSlug}:tickets:work <number-or-slug>`;
|
|
479
481
|
} else if (ticketTool.type === "create") {
|
|
480
482
|
description = ticketTool.description;
|
|
481
483
|
promptContent = `Create a new ticket in the "${ticketTool.workspaceSlug}" workspace queue.
|
|
@@ -538,7 +540,7 @@ 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
546
|
if (tt.type === "get" || tt.type === "close") {
|
|
@@ -552,13 +554,13 @@ 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 === "work") {
|
|
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, starts work on next ticket in queue."
|
|
562
564
|
}
|
|
563
565
|
},
|
|
564
566
|
required: []
|
|
@@ -777,19 +779,19 @@ ${ticketList}`
|
|
|
777
779
|
isError: true
|
|
778
780
|
};
|
|
779
781
|
}
|
|
780
|
-
} else if (ticketTool.type === "
|
|
782
|
+
} else if (ticketTool.type === "work") {
|
|
781
783
|
const ticketSlug = request.params.arguments?.ticketSlug;
|
|
782
784
|
try {
|
|
783
785
|
const result2 = await convexClient.mutation(
|
|
784
|
-
"mcp_tickets:
|
|
786
|
+
"mcp_tickets:workMcpTicket",
|
|
785
787
|
{
|
|
786
788
|
apiKey: config.apiKey,
|
|
787
789
|
workspaceSlug: ticketTool.workspaceSlug,
|
|
788
790
|
ticketSlug
|
|
789
|
-
// Optional: specific ticket to
|
|
791
|
+
// Optional: specific ticket to work on
|
|
790
792
|
}
|
|
791
793
|
);
|
|
792
|
-
if (!result2) {
|
|
794
|
+
if (!result2 || !result2.content) {
|
|
793
795
|
const message = ticketSlug ? `Ticket "${ticketSlug}" not found or not open in workspace "${ticketTool.workspaceSlug}".` : `No pending tickets in workspace "${ticketTool.workspaceSlug}".`;
|
|
794
796
|
return {
|
|
795
797
|
content: [
|
|
@@ -800,31 +802,80 @@ ${ticketList}`
|
|
|
800
802
|
]
|
|
801
803
|
};
|
|
802
804
|
}
|
|
805
|
+
let filesCreated = false;
|
|
806
|
+
let ticketFilePath = null;
|
|
807
|
+
let sessionFilePath = null;
|
|
808
|
+
if (result2.effectivePpmDir) {
|
|
809
|
+
try {
|
|
810
|
+
const workingDir = path.join(result2.effectivePpmDir, "working");
|
|
811
|
+
const ticketFileName = `${result2.ticketNumber}-${result2.slug}.md`;
|
|
812
|
+
const sessionFileName = `${result2.ticketNumber}-${result2.slug}.session.md`;
|
|
813
|
+
ticketFilePath = path.join(workingDir, ticketFileName);
|
|
814
|
+
sessionFilePath = path.join(workingDir, sessionFileName);
|
|
815
|
+
fs.mkdirSync(workingDir, { recursive: true });
|
|
816
|
+
fs.writeFileSync(ticketFilePath, result2.content, "utf-8");
|
|
817
|
+
const sessionTemplate = generateSessionTemplate(
|
|
818
|
+
result2.ticketNumber,
|
|
819
|
+
result2.slug,
|
|
820
|
+
result2.workspaceRoot,
|
|
821
|
+
result2.effectivePpmDir
|
|
822
|
+
);
|
|
823
|
+
fs.writeFileSync(sessionFilePath, sessionTemplate, "utf-8");
|
|
824
|
+
filesCreated = true;
|
|
825
|
+
} catch (fsError) {
|
|
826
|
+
console.error("[MCP] tickets:work file I/O error:", fsError);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
let responseText = `# Ticket: ${result2.slug} [WORKING]
|
|
830
|
+
|
|
831
|
+
`;
|
|
832
|
+
responseText += result2.content;
|
|
833
|
+
responseText += `
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
`;
|
|
837
|
+
if (filesCreated) {
|
|
838
|
+
responseText += `_Session files created:_
|
|
839
|
+
`;
|
|
840
|
+
responseText += `- Ticket: \`${ticketFilePath}\`
|
|
841
|
+
`;
|
|
842
|
+
responseText += `- Session: \`${sessionFilePath}\`
|
|
843
|
+
|
|
844
|
+
`;
|
|
845
|
+
responseText += `_Use session file to log progress and resume points._
|
|
846
|
+
`;
|
|
847
|
+
} else if (!result2.effectivePpmDir) {
|
|
848
|
+
responseText += `_Local session files not created (no PPM directory configured)._
|
|
849
|
+
`;
|
|
850
|
+
} else {
|
|
851
|
+
responseText += `_Local session files could not be created (file system error)._
|
|
852
|
+
`;
|
|
853
|
+
}
|
|
854
|
+
responseText += `
|
|
855
|
+
${result2.remainingTickets} ticket(s) remaining in queue.
|
|
856
|
+
|
|
857
|
+
`;
|
|
858
|
+
responseText += `**Next steps:**
|
|
859
|
+
`;
|
|
860
|
+
responseText += `- Use \`${ticketTool.workspaceSlug}:tickets:message\` to log progress
|
|
861
|
+
`;
|
|
862
|
+
responseText += `- Use \`${ticketTool.workspaceSlug}:tickets:close\` when done`;
|
|
803
863
|
return {
|
|
804
864
|
content: [
|
|
805
865
|
{
|
|
806
866
|
type: "text",
|
|
807
|
-
text:
|
|
808
|
-
|
|
809
|
-
${result2.content}
|
|
810
|
-
|
|
811
|
-
---
|
|
812
|
-
_Ticket moved to working status. ${result2.remainingTickets} ticket(s) remaining in queue._
|
|
813
|
-
|
|
814
|
-
**Next steps:**
|
|
815
|
-
- Use \`${ticketTool.workspaceSlug}:tickets:message\` to log progress
|
|
816
|
-
- Use \`${ticketTool.workspaceSlug}:tickets:close\` when done`
|
|
867
|
+
text: responseText
|
|
817
868
|
}
|
|
818
869
|
]
|
|
819
870
|
};
|
|
820
871
|
} catch (error) {
|
|
821
872
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
822
|
-
console.error(
|
|
873
|
+
console.error("[MCP] tickets:work error:", error);
|
|
823
874
|
return {
|
|
824
875
|
content: [
|
|
825
876
|
{
|
|
826
877
|
type: "text",
|
|
827
|
-
text: `Error
|
|
878
|
+
text: `Error starting ticket work: ${errorMessage}`
|
|
828
879
|
}
|
|
829
880
|
],
|
|
830
881
|
isError: true
|
|
@@ -1155,6 +1206,27 @@ async function fetchMcpPrompts(client, apiKey, workspaces) {
|
|
|
1155
1206
|
);
|
|
1156
1207
|
}
|
|
1157
1208
|
}
|
|
1209
|
+
function generateSessionTemplate(ticketNumber, slug, workspaceRoot, effectivePpmDir) {
|
|
1210
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1211
|
+
return `# Session: ${ticketNumber}-${slug}
|
|
1212
|
+
Started: ${timestamp}
|
|
1213
|
+
|
|
1214
|
+
## Context
|
|
1215
|
+
- Ticket: ${ticketNumber}-${slug}
|
|
1216
|
+
- Working directory: ${workspaceRoot || "Not configured"}
|
|
1217
|
+
- PPM directory: ${effectivePpmDir || "Not configured"}
|
|
1218
|
+
|
|
1219
|
+
## Progress
|
|
1220
|
+
|
|
1221
|
+
<!-- Append progress entries with timestamps -->
|
|
1222
|
+
|
|
1223
|
+
## Resume Point
|
|
1224
|
+
<!-- Note where to pick up if interrupted -->
|
|
1225
|
+
|
|
1226
|
+
## Notes
|
|
1227
|
+
<!-- Observations, blockers, questions -->
|
|
1228
|
+
`;
|
|
1229
|
+
}
|
|
1158
1230
|
|
|
1159
1231
|
// src/index.ts
|
|
1160
1232
|
async function main() {
|
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 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\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\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 tickets:work command (Ticket 153: replaces tickets:next with local file support)\n */\ninterface WorkTicketResult {\n content: string | null;\n slug: string;\n ticketNumber: number;\n status: string; // \"working\"\n remainingTickets: number;\n // Ticket 153: New workspace path fields for local file creation\n workspaceRoot: string | null;\n localPpmDir: string | null;\n effectivePpmDir: string | null; // localPpmDir OR \"{workspaceRoot}/.ppm\"\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, 153)\n // Each workspace gets :tickets:list, :tickets:work, :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' | 'work' | '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 // Ticket 153: Renamed tickets:next → tickets:work\n dynamicTicketTools.push({\n name: `${workspaceSlug}:tickets:work`,\n description: `Start work on a ticket with local session files in the \"${workspaceSlug}\" workspace. Optionally specify a ticket number or slug.`,\n workspaceSlug,\n type: 'work',\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, 153 - handle as slash commands)\n // Handle exact matches and :work with optional argument (e.g., \"workspace:tickets:work 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 ticketWorkMatch = promptName.match(/^(.+):tickets:work\\s+(.+)$/);\n\n if (ticketTool || ticketWorkMatch) {\n let promptContent: string;\n let description: string;\n\n if (ticketWorkMatch) {\n // Handle tickets:work with specific ticket argument\n const workspaceSlug = ticketWorkMatch[1];\n const ticketArg = ticketWorkMatch[2].trim();\n description = `Start work on ticket \"${ticketArg}\" from \"${workspaceSlug}\"`;\n promptContent = `Start work on ticket \"${ticketArg}\" from the \"${workspaceSlug}\" workspace queue.\\n\\nCall the \\`${workspaceSlug}:tickets:work\\` tool with ticketSlug: \"${ticketArg}\" to start working on 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 === 'work') {\n // Ticket 153: Renamed from 'next' to 'work'\n description = ticketTool!.description;\n promptContent = `Start work on the next ticket from the \"${ticketTool!.workspaceSlug}\" workspace queue.\\n\\nCall the \\`${ticketTool!.name}\\` tool to get the next ticket and move it to working status. Local session files will be created if PPM directory is configured.\\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 {\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, 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 === '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 === 'work') {\n // Ticket 153: Renamed from 'next' to 'work'\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, starts work on 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 === 'work') {\n // Ticket 153: Handle tickets:work (replaces tickets:next with local file support)\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:workMcpTicket\",\n {\n apiKey: config.apiKey,\n workspaceSlug: ticketTool.workspaceSlug,\n ticketSlug: ticketSlug, // Optional: specific ticket to work on\n }\n ) as WorkTicketResult | null;\n\n if (!result || !result.content) {\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 153: Attempt local file creation if effectivePpmDir exists\n let filesCreated = false;\n let ticketFilePath: string | null = null;\n let sessionFilePath: string | null = null;\n\n if (result.effectivePpmDir) {\n try {\n const workingDir = path.join(result.effectivePpmDir, 'working');\n const ticketFileName = `${result.ticketNumber}-${result.slug}.md`;\n const sessionFileName = `${result.ticketNumber}-${result.slug}.session.md`;\n\n ticketFilePath = path.join(workingDir, ticketFileName);\n sessionFilePath = path.join(workingDir, sessionFileName);\n\n // Create directory (recursive)\n fs.mkdirSync(workingDir, { recursive: true });\n\n // Write ticket file (flattened content)\n fs.writeFileSync(ticketFilePath, result.content, 'utf-8');\n\n // Write session file (template)\n const sessionTemplate = generateSessionTemplate(\n result.ticketNumber,\n result.slug,\n result.workspaceRoot,\n result.effectivePpmDir\n );\n fs.writeFileSync(sessionFilePath, sessionTemplate, 'utf-8');\n\n filesCreated = true;\n } catch (fsError) {\n console.error(\"[MCP] tickets:work file I/O error:\", fsError);\n // Continue without files - graceful degradation\n }\n }\n\n // Build response\n let responseText = `# Ticket: ${result.slug} [WORKING]\\n\\n`;\n responseText += result.content;\n responseText += `\\n\\n---\\n`;\n\n if (filesCreated) {\n responseText += `_Session files created:_\\n`;\n responseText += `- Ticket: \\`${ticketFilePath}\\`\\n`;\n responseText += `- Session: \\`${sessionFilePath}\\`\\n\\n`;\n responseText += `_Use session file to log progress and resume points._\\n`;\n } else if (!result.effectivePpmDir) {\n responseText += `_Local session files not created (no PPM directory configured)._\\n`;\n } else {\n responseText += `_Local session files could not be created (file system error)._\\n`;\n }\n\n responseText += `\\n${result.remainingTickets} ticket(s) remaining in queue.\\n\\n`;\n responseText += `**Next steps:**\\n`;\n responseText += `- Use \\`${ticketTool.workspaceSlug}:tickets:message\\` to log progress\\n`;\n responseText += `- Use \\`${ticketTool.workspaceSlug}:tickets:close\\` when done`;\n\n return {\n content: [\n {\n type: \"text\",\n text: responseText,\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 starting ticket work: ${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\n/**\n * Generate session template for local ticket session file (Ticket 153)\n */\nfunction generateSessionTemplate(\n ticketNumber: number,\n slug: string,\n workspaceRoot: string | null,\n effectivePpmDir: string | null\n): string {\n const timestamp = new Date().toISOString();\n\n return `# Session: ${ticketNumber}-${slug}\nStarted: ${timestamp}\n\n## Context\n- Ticket: ${ticketNumber}-${slug}\n- Working directory: ${workspaceRoot || 'Not configured'}\n- PPM directory: ${effectivePpmDir || 'Not configured'}\n\n## Progress\n\n<!-- Append progress entries with timestamps -->\n\n## Resume Point\n<!-- Note where to pick up if interrupted -->\n\n## Notes\n<!-- Observations, blockers, questions -->\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