sad-mcp 0.1.17 → 0.1.19

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.
Files changed (2) hide show
  1. package/dist/tools.js +26 -40
  2. package/package.json +1 -1
package/dist/tools.js CHANGED
@@ -12,12 +12,33 @@ function isExamFile(file) {
12
12
  async function getExamList() {
13
13
  const allFiles = await listAllFiles();
14
14
  const examFiles = allFiles.filter(f => isExamFile(f) && isExtractable(f));
15
+ // Debug logging to stderr (visible in MCP server logs)
16
+ console.error(`[getExamList] allFiles=${allFiles.length}, examFiles=${examFiles.length}`);
17
+ for (const f of examFiles.slice(0, 10)) {
18
+ console.error(`[getExamList] path="${f.path}" name="${f.name}" mime="${f.mimeType}"`);
19
+ }
20
+ if (examFiles.length === 0) {
21
+ // Log files that ARE categorized as exams but fail isExtractable
22
+ const examOnly = allFiles.filter(f => isExamFile(f));
23
+ console.error(`[getExamList] files categorized as exams (before extractable filter): ${examOnly.length}`);
24
+ for (const f of examOnly.slice(0, 10)) {
25
+ console.error(`[getExamList] exam-cat: path="${f.path}" name="${f.name}" mime="${f.mimeType}"`);
26
+ }
27
+ // Log a few files that contain "מבחנ" in path
28
+ const withMbchn = allFiles.filter(f => f.path.includes("מבחנ"));
29
+ console.error(`[getExamList] files with מבחנ in path: ${withMbchn.length}`);
30
+ for (const f of withMbchn.slice(0, 10)) {
31
+ console.error(`[getExamList] מבחנ: path="${f.path}" name="${f.name}"`);
32
+ }
33
+ }
15
34
  const examsMap = new Map();
16
35
  for (const file of examFiles) {
17
36
  // Match paths like "מבחנים-לסטודנטים/2024-א-א/מבחן.pdf"
18
37
  const match = file.path.match(/(\d{4})-([\u0590-\u05FFa-z]+)-([\u0590-\u05FFa-z]+)\//i);
19
- if (!match)
38
+ if (!match) {
39
+ console.error(`[getExamList] regex NO MATCH for path: "${file.path}"`);
20
40
  continue;
41
+ }
21
42
  const [, year, semester, moed] = match;
22
43
  const id = `${year}-${semester}-${moed}`;
23
44
  if (!examsMap.has(id)) {
@@ -188,7 +209,7 @@ export function registerToolHandlers(server) {
188
209
  },
189
210
  {
190
211
  name: "practice_exam",
191
- description: "Get a past exam for practice. Returns ONLY the exam questions NEVER the solution. Use this when a student wants to practice an exam. After the student answers, use get_material with the solution path to check their work. IMPORTANT: Do NOT retrieve the solution until the student explicitly asks to check their answers.",
212
+ description: "Get a past exam for practice. Returns a Google Drive link to the exam file so the student can download/view it. NEVER return the solution link only provide it after the student explicitly asks to check their answers.",
192
213
  inputSchema: {
193
214
  type: "object",
194
215
  properties: {
@@ -196,10 +217,6 @@ export function registerToolHandlers(server) {
196
217
  type: "string",
197
218
  description: "The exam identifier (e.g., '2024-א-א'). Get available IDs from list_exams.",
198
219
  },
199
- page: {
200
- type: "number",
201
- description: "Page number (1-indexed). Each page is ~5000 characters. Defaults to 1.",
202
- },
203
220
  user_question: {
204
221
  type: "string",
205
222
  description: "The student's original question exactly as they typed it. Always pass this for analytics.",
@@ -421,42 +438,11 @@ export function registerToolHandlers(server) {
421
438
  trackToolCall(name, toolArgs, { success: false, responseChars: notFound.length }, Date.now() - startTime);
422
439
  return { content: [{ type: "text", text: notFound }] };
423
440
  }
424
- // Extract exam text (on demand)
425
- let examText;
426
- const cached = textCache.get(exam.examFile.id);
427
- if (cached) {
428
- examText = cached.text;
429
- }
430
- else {
431
- const diskCache = loadTextCache();
432
- const diskEntry = diskCache[exam.examFile.id];
433
- if (diskEntry && diskEntry.modifiedTime === exam.examFile.modifiedTime) {
434
- examText = diskEntry.text;
435
- textCache.set(exam.examFile.id, { file: exam.examFile, text: examText });
436
- }
437
- else {
438
- const buffer = await downloadFile(exam.examFile);
439
- examText = await extractText(exam.examFile, buffer);
440
- textCache.set(exam.examFile.id, { file: exam.examFile, text: examText });
441
- saveTextEntry(exam.examFile.id, { modifiedTime: exam.examFile.modifiedTime, text: examText });
442
- }
443
- }
444
- // Pagination
445
- const PAGE_SIZE = 5000;
446
- const page = Math.max(1, args.page || 1);
447
- const totalChars = examText.length;
448
- const totalPages = Math.ceil(totalChars / PAGE_SIZE);
449
- const start = (page - 1) * PAGE_SIZE;
450
- const end = Math.min(start + PAGE_SIZE, totalChars);
451
- const pageText = examText.substring(start, end);
452
- const header = `📝 מבחן ${examId} — Page ${page}/${totalPages} (${totalChars} chars total)`;
441
+ const examLink = `https://drive.google.com/file/d/${exam.examFile.id}/view`;
453
442
  const solutionHint = exam.solutionFile
454
- ? `\n\n[Solution available — use get_material with path "${exam.solutionFile.path}" ONLY after the student has answered]`
443
+ ? `\n\n[Solution available — ONLY share this link after the student explicitly asks to check their answers: https://drive.google.com/file/d/${exam.solutionFile.id}/view]`
455
444
  : "\n\n[No solution available for this exam]";
456
- const pageFooter = page < totalPages
457
- ? `\n\n[More questions available — call practice_exam with page: ${page + 1} to continue]`
458
- : "";
459
- const fullResponse = `${header}\n\n${pageText}${pageFooter}${solutionHint}`;
445
+ const fullResponse = `📝 מבחן ${examId} (שנה: ${exam.year}, סמסטר: ${exam.semester}, מועד: ${exam.moed})\n\nExam file: ${examLink}${solutionHint}`;
460
446
  trackToolCall(name, toolArgs, { success: true, responseChars: fullResponse.length }, Date.now() - startTime);
461
447
  return { content: [{ type: "text", text: fullResponse }] };
462
448
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sad-mcp",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "MCP server for Software Analysis and Design course materials at BGU",
5
5
  "type": "module",
6
6
  "bin": {