@jaypie/mcp 0.3.0 → 0.3.2

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 CHANGED
@@ -8,6 +8,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
8
  import { z } from 'zod';
9
9
  import * as fs from 'node:fs/promises';
10
10
  import matter from 'gray-matter';
11
+ import { gt } from 'semver';
11
12
  import * as https from 'node:https';
12
13
  import { Llm } from '@jaypie/llm';
13
14
  import { spawn } from 'node:child_process';
@@ -1208,11 +1209,12 @@ async function purgeSQSQueue(options, logger = nullLogger) {
1208
1209
  return executeAwsCommand("sqs", "purge-queue", ["--queue-url", options.queueUrl], { profile: options.profile, region: options.region }, logger);
1209
1210
  }
1210
1211
 
1211
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.0#8cd307b1"
1212
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.2#f7a87775"
1212
1213
  ;
1213
1214
  const __filename$1 = fileURLToPath(import.meta.url);
1214
1215
  const __dirname$1 = path.dirname(__filename$1);
1215
1216
  const PROMPTS_PATH = path.join(__dirname$1, "..", "prompts");
1217
+ const RELEASE_NOTES_PATH = path.join(__dirname$1, "..", "release-notes");
1216
1218
  // Logger utility
1217
1219
  function createLogger(verbose) {
1218
1220
  return {
@@ -1260,6 +1262,75 @@ function formatPromptListItem(prompt) {
1260
1262
  return `* ${filename}`;
1261
1263
  }
1262
1264
  }
1265
+ async function parseReleaseNoteFile(filePath) {
1266
+ try {
1267
+ const content = await fs.readFile(filePath, "utf-8");
1268
+ const filename = path.basename(filePath, ".md");
1269
+ if (content.startsWith("---")) {
1270
+ const parsed = matter(content);
1271
+ const frontMatter = parsed.data;
1272
+ return {
1273
+ date: frontMatter.date,
1274
+ filename,
1275
+ summary: frontMatter.summary,
1276
+ version: frontMatter.version || filename,
1277
+ };
1278
+ }
1279
+ return { filename, version: filename };
1280
+ }
1281
+ catch {
1282
+ return { filename: path.basename(filePath, ".md") };
1283
+ }
1284
+ }
1285
+ function formatReleaseNoteListItem(note) {
1286
+ const { date, packageName, summary, version } = note;
1287
+ const parts = [`* ${packageName}@${version}`];
1288
+ if (date) {
1289
+ parts.push(`(${date})`);
1290
+ }
1291
+ if (summary) {
1292
+ parts.push(`- ${summary}`);
1293
+ }
1294
+ return parts.join(" ");
1295
+ }
1296
+ async function getPackageReleaseNotes(packageName) {
1297
+ const packageDir = path.join(RELEASE_NOTES_PATH, packageName);
1298
+ try {
1299
+ const files = await fs.readdir(packageDir);
1300
+ const mdFiles = files.filter((file) => file.endsWith(".md"));
1301
+ const notes = await Promise.all(mdFiles.map(async (file) => {
1302
+ const parsed = await parseReleaseNoteFile(path.join(packageDir, file));
1303
+ return { ...parsed, packageName };
1304
+ }));
1305
+ // Sort by version descending (newest first)
1306
+ return notes.sort((a, b) => {
1307
+ if (!a.version || !b.version)
1308
+ return 0;
1309
+ try {
1310
+ return gt(a.version, b.version) ? -1 : 1;
1311
+ }
1312
+ catch {
1313
+ // If semver comparison fails, fall back to string comparison
1314
+ return b.version.localeCompare(a.version);
1315
+ }
1316
+ });
1317
+ }
1318
+ catch {
1319
+ return [];
1320
+ }
1321
+ }
1322
+ function filterReleaseNotesSince(notes, sinceVersion) {
1323
+ return notes.filter((note) => {
1324
+ if (!note.version)
1325
+ return false;
1326
+ try {
1327
+ return gt(note.version, sinceVersion);
1328
+ }
1329
+ catch {
1330
+ return false;
1331
+ }
1332
+ });
1333
+ }
1263
1334
  /**
1264
1335
  * Creates and configures an MCP server instance with Jaypie tools
1265
1336
  * @param options - Configuration options (or legacy version string)
@@ -1367,6 +1438,135 @@ function createMcpServer(options = {}) {
1367
1438
  };
1368
1439
  });
1369
1440
  log.info("Registered tool: version");
1441
+ // Release Notes Tools
1442
+ server.tool("list_release_notes", "List available release notes for Jaypie packages. Filter by package name and/or get only versions newer than a specified version.", {
1443
+ package: z
1444
+ .string()
1445
+ .optional()
1446
+ .describe("Filter by package name (e.g., 'jaypie', 'mcp'). If not provided, lists release notes for all packages."),
1447
+ since_version: z
1448
+ .string()
1449
+ .optional()
1450
+ .describe("Only show versions newer than this (e.g., '1.0.0'). Uses semver comparison."),
1451
+ }, async ({ package: packageFilter, since_version: sinceVersion }) => {
1452
+ log.info("Tool called: list_release_notes");
1453
+ log.info(`Release notes directory: ${RELEASE_NOTES_PATH}`);
1454
+ try {
1455
+ // Get list of package directories
1456
+ const entries = await fs.readdir(RELEASE_NOTES_PATH, {
1457
+ withFileTypes: true,
1458
+ });
1459
+ const packageDirs = entries
1460
+ .filter((entry) => entry.isDirectory())
1461
+ .map((entry) => entry.name);
1462
+ log.info(`Found ${packageDirs.length} package directories`);
1463
+ // Filter by package if specified
1464
+ const packagesToList = packageFilter
1465
+ ? packageDirs.filter((pkg) => pkg === packageFilter)
1466
+ : packageDirs;
1467
+ if (packagesToList.length === 0 && packageFilter) {
1468
+ return {
1469
+ content: [
1470
+ {
1471
+ type: "text",
1472
+ text: `No release notes found for package "${packageFilter}".`,
1473
+ },
1474
+ ],
1475
+ };
1476
+ }
1477
+ // Get release notes for each package
1478
+ const allNotes = await Promise.all(packagesToList.map((pkg) => getPackageReleaseNotes(pkg)));
1479
+ let flatNotes = allNotes.flat();
1480
+ // Filter by since_version if specified
1481
+ if (sinceVersion) {
1482
+ flatNotes = filterReleaseNotesSince(flatNotes, sinceVersion);
1483
+ }
1484
+ if (flatNotes.length === 0) {
1485
+ const filterDesc = sinceVersion
1486
+ ? ` newer than ${sinceVersion}`
1487
+ : "";
1488
+ return {
1489
+ content: [
1490
+ {
1491
+ type: "text",
1492
+ text: `No release notes found${filterDesc}.`,
1493
+ },
1494
+ ],
1495
+ };
1496
+ }
1497
+ const formattedList = flatNotes
1498
+ .map(formatReleaseNoteListItem)
1499
+ .join("\n");
1500
+ log.info(`Successfully listed ${flatNotes.length} release notes`);
1501
+ return {
1502
+ content: [
1503
+ {
1504
+ type: "text",
1505
+ text: formattedList,
1506
+ },
1507
+ ],
1508
+ };
1509
+ }
1510
+ catch (error) {
1511
+ log.error("Error listing release notes:", error);
1512
+ return {
1513
+ content: [
1514
+ {
1515
+ type: "text",
1516
+ text: `Error listing release notes: ${error instanceof Error ? error.message : "Unknown error"}`,
1517
+ },
1518
+ ],
1519
+ };
1520
+ }
1521
+ });
1522
+ log.info("Registered tool: list_release_notes");
1523
+ server.tool("read_release_note", "Read the full content of a specific release note. Call list_release_notes first to see available versions.", {
1524
+ package: z
1525
+ .string()
1526
+ .describe("Package name (e.g., 'jaypie', 'mcp')"),
1527
+ version: z
1528
+ .string()
1529
+ .describe("Version number (e.g., '1.2.3')"),
1530
+ }, async ({ package: packageName, version }) => {
1531
+ log.info(`Tool called: read_release_note (package: ${packageName}, version: ${version})`);
1532
+ try {
1533
+ const filePath = path.join(RELEASE_NOTES_PATH, packageName, `${version}.md`);
1534
+ log.info(`Reading file: ${filePath}`);
1535
+ const content = await fs.readFile(filePath, "utf-8");
1536
+ log.info(`Successfully read release note for ${packageName}@${version} (${content.length} bytes)`);
1537
+ return {
1538
+ content: [
1539
+ {
1540
+ type: "text",
1541
+ text: content,
1542
+ },
1543
+ ],
1544
+ };
1545
+ }
1546
+ catch (error) {
1547
+ if (error.code === "ENOENT") {
1548
+ log.error(`Release note not found: ${packageName}@${version}`);
1549
+ return {
1550
+ content: [
1551
+ {
1552
+ type: "text",
1553
+ text: `Error: Release note for "${packageName}@${version}" not found. Use list_release_notes to see available versions.`,
1554
+ },
1555
+ ],
1556
+ };
1557
+ }
1558
+ log.error("Error reading release note:", error);
1559
+ return {
1560
+ content: [
1561
+ {
1562
+ type: "text",
1563
+ text: `Error reading release note: ${error instanceof Error ? error.message : "Unknown error"}`,
1564
+ },
1565
+ ],
1566
+ };
1567
+ }
1568
+ });
1569
+ log.info("Registered tool: read_release_note");
1370
1570
  // Datadog Logs Tool
1371
1571
  server.tool("datadog_logs", "Search and retrieve individual Datadog log entries. Use this to view actual log messages and details. For aggregated counts/statistics (e.g., 'how many errors by service?'), use datadog_log_analytics instead. Requires DATADOG_API_KEY and DATADOG_APP_KEY environment variables.", {
1372
1572
  query: z