sad-mcp 0.1.14 → 0.1.16

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 +13 -7
  2. package/package.json +1 -1
package/dist/tools.js CHANGED
@@ -5,11 +5,15 @@ import { loadTextCache, saveTextEntry } from "./text-cache.js";
5
5
  import { trackToolCall } from "./tracking.js";
6
6
  // In-memory text cache for search (populated from disk cache + fresh extractions)
7
7
  const textCache = new Map();
8
+ function isExamFile(file) {
9
+ return categorizeFile(file) === "exams";
10
+ }
8
11
  async function ensureTextCache() {
9
12
  if (textCache.size > 0)
10
13
  return;
11
14
  const files = await listAllFiles();
12
- const extractableFiles = files.filter(isExtractable);
15
+ // Skip exam files during eager loading — they're extracted on demand via get_material
16
+ const extractableFiles = files.filter(f => isExtractable(f) && !isExamFile(f));
13
17
  const diskCache = loadTextCache();
14
18
  for (const file of extractableFiles) {
15
19
  try {
@@ -84,7 +88,7 @@ export function registerToolHandlers(server) {
84
88
  properties: {
85
89
  name: {
86
90
  type: "string",
87
- description: "The file name (or partial name) to retrieve. Matched against file names from search_materials or list_materials results.",
91
+ description: "The file name or path (or partial match) to retrieve. Use the path from search_materials results for exact matching (e.g., 'מבחנים-לסטודנטים/2024-א-א/מבחן.pdf').",
88
92
  },
89
93
  page: {
90
94
  type: "number",
@@ -160,6 +164,7 @@ export function registerToolHandlers(server) {
160
164
  if (matches.length > 0 || nameMatch) {
161
165
  results.push({
162
166
  fileName: file.name,
167
+ path: file.path,
163
168
  category: categorizeFile(file),
164
169
  matchCount: nameMatch ? matches.length + 100 : matches.length, // Boost file-name matches
165
170
  preview: matches.length > 0
@@ -176,6 +181,7 @@ export function registerToolHandlers(server) {
176
181
  if (file.name.toLowerCase().includes(queryLower) || file.path.toLowerCase().includes(queryLower)) {
177
182
  results.push({
178
183
  fileName: file.name,
184
+ path: file.path,
179
185
  category: categorizeFile(file),
180
186
  matchCount: 100,
181
187
  preview: `(file name matches "${query}" — use get_material to read)`,
@@ -186,7 +192,7 @@ export function registerToolHandlers(server) {
186
192
  results.sort((a, b) => b.matchCount - a.matchCount);
187
193
  const responseText = results.length === 0
188
194
  ? `No results found for "${query}" in course materials.`
189
- : `Found "${query}" in ${results.length} file(s). Use get_material to read the most relevant one(s):\n\n${results.map((r) => `- ${r.fileName} [${r.category}] (${r.matchCount} matches) — "${r.preview}"`).join("\n")}`;
195
+ : `Found "${query}" in ${results.length} file(s). Use get_material with the file path to read the most relevant one(s):\n\n${results.map((r) => `- ${r.path} [${r.category}] (${r.matchCount} matches) — "${r.preview}"`).join("\n")}`;
190
196
  trackToolCall(name, toolArgs, { resultCount: results.length, success: results.length > 0, responseChars: responseText.length }, Date.now() - startTime);
191
197
  return { content: [{ type: "text", text: responseText }] };
192
198
  }
@@ -199,18 +205,18 @@ export function registerToolHandlers(server) {
199
205
  }
200
206
  await ensureTextCache();
201
207
  const queryLower = queryName.toLowerCase();
202
- // First: check text cache
208
+ // First: check text cache (match against both name and path)
203
209
  let bestMatch = null;
204
210
  for (const [, entry] of textCache) {
205
- if (entry.file.name.toLowerCase().includes(queryLower)) {
211
+ if (entry.file.name.toLowerCase().includes(queryLower) || entry.file.path.toLowerCase().includes(queryLower)) {
206
212
  bestMatch = entry;
207
213
  break;
208
214
  }
209
215
  }
210
- // Fallback: search all files by name and attempt fresh extraction
216
+ // Fallback: search all files by name/path and attempt fresh extraction
211
217
  if (!bestMatch) {
212
218
  const allFiles = await listAllFiles();
213
- const matchedFile = allFiles.find(f => f.name.toLowerCase().includes(queryLower));
219
+ const matchedFile = allFiles.find(f => f.name.toLowerCase().includes(queryLower) || f.path.toLowerCase().includes(queryLower));
214
220
  if (matchedFile && isExtractable(matchedFile)) {
215
221
  try {
216
222
  const buffer = await downloadFile(matchedFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sad-mcp",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "MCP server for Software Analysis and Design course materials at BGU",
5
5
  "type": "module",
6
6
  "bin": {