fmea-api-mcp-server 1.0.6 → 1.0.7

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 (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +57 -26
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -101,7 +101,7 @@ When the package is published to NPM:
101
101
  - **Tools**:
102
102
  - **Tools**:
103
103
  - `search_apis`:
104
- - Smart search with relevance scoring (Summary > Description > Path).
105
- - Supports filters: `query`, `method` (GET/POST), `version` (v1/v2).
106
- - Results limited to top 10 by default to prevent context pollution.
104
+ - Smart search with relevance scoring and pagination.
105
+ - Supports filters: `query` (use `*` for all), `method`, `version`, `page` (default 1).
106
+ - Results limited to 10 per page. Returns meta info (total, totalPages) and guidance.
107
107
  - `get_api_details`: Get full details (schema, parameters) for a specific endpoint.
package/dist/index.js CHANGED
@@ -114,6 +114,10 @@ class ApiDocsServer {
114
114
  type: "string",
115
115
  description: "Filter by API version (e.g. 'v1', 'v2'). Optional.",
116
116
  },
117
+ page: {
118
+ type: "integer",
119
+ description: "Page number for pagination (default: 1).",
120
+ },
117
121
  },
118
122
  required: ["query"],
119
123
  },
@@ -144,7 +148,8 @@ class ApiDocsServer {
144
148
  const query = String(request.params.arguments?.query).toLowerCase();
145
149
  const method = request.params.arguments?.method ? String(request.params.arguments?.method).toUpperCase() : undefined;
146
150
  const version = request.params.arguments?.version ? String(request.params.arguments?.version).toLowerCase() : undefined;
147
- const results = await this.searchInFiles(query, method, version);
151
+ const page = request.params.arguments?.page ? Number(request.params.arguments?.page) : 1;
152
+ const results = await this.searchInFiles(query, method, version, page);
148
153
  return {
149
154
  content: [
150
155
  {
@@ -205,19 +210,19 @@ class ApiDocsServer {
205
210
  }
206
211
  return results;
207
212
  }
208
- // Smart search helper with scoring, filtering, and limits
209
- async searchInFiles(query, filterMethod, filterVersion) {
213
+ // Smart search helper with scoring, filtering, limits, and pagination
214
+ async searchInFiles(query, filterMethod, filterVersion, page = 1) {
210
215
  const files = await this.getAllFiles(ENDPOINTS_DIR);
211
216
  let allMatches = [];
217
+ const isWildcard = query === "*" || query === "";
212
218
  for (const filePath of files) {
213
219
  try {
214
220
  const content = await fs.readFile(filePath, "utf-8");
215
221
  const json = JSON.parse(content);
216
222
  const fileName = path.relative(ENDPOINTS_DIR, filePath);
217
- // Version Filtering (File level or content level check)
218
- // Check if file path contains version (e.g. "v1/...") or json has version field
223
+ // Version Filtering
219
224
  if (filterVersion) {
220
- const fileVersion = fileName.split(path.sep)[0]; // e.g. "v1" from "v1/projects/..."
225
+ const fileVersion = fileName.split(path.sep)[0];
221
226
  if (fileVersion !== filterVersion && json.version !== filterVersion) {
222
227
  continue;
223
228
  }
@@ -230,17 +235,22 @@ class ApiDocsServer {
230
235
  }
231
236
  // Scoring Logic
232
237
  let score = 0;
233
- const summary = (endpoint.summary || "").toLowerCase();
234
- const description = (endpoint.description || "").toLowerCase();
235
- const apiPath = (endpoint.path || "").toLowerCase();
236
- const operationId = (endpoint.operationId || "").toLowerCase();
237
- // 1. Exact/High relevance matches
238
- if (summary.includes(query) || operationId.includes(query))
239
- score += 10;
240
- if (description.includes(query))
241
- score += 5;
242
- if (apiPath.includes(query))
243
- score += 3;
238
+ if (isWildcard) {
239
+ score = 1; // All match in wildcard mode
240
+ }
241
+ else {
242
+ const summary = (endpoint.summary || "").toLowerCase();
243
+ const description = (endpoint.description || "").toLowerCase();
244
+ const apiPath = (endpoint.path || "").toLowerCase();
245
+ const operationId = (endpoint.operationId || "").toLowerCase();
246
+ // Exact/High relevance matches
247
+ if (summary.includes(query) || operationId.includes(query))
248
+ score += 10;
249
+ if (description.includes(query))
250
+ score += 5;
251
+ if (apiPath.includes(query))
252
+ score += 3;
253
+ }
244
254
  if (score > 0) {
245
255
  allMatches.push({
246
256
  score,
@@ -258,19 +268,40 @@ class ApiDocsServer {
258
268
  // Ignore parse errors
259
269
  }
260
270
  }
261
- // Sort by score descending
262
- allMatches.sort((a, b) => b.score - a.score);
263
- // Limit results
264
- const LIMIT = 10;
265
271
  const totalFound = allMatches.length;
266
- const limitedResults = allMatches.slice(0, LIMIT).map(({ score, ...rest }) => rest); // Remove score from output
267
- if (totalFound > LIMIT) {
272
+ if (totalFound === 0) {
268
273
  return {
269
- results: limitedResults,
270
- warning: `Found ${totalFound} results. Showing top ${LIMIT}. Please refine your search query or use filters.`
274
+ results: [],
275
+ message: `No results found for '${query}'. Try using '*' to list all endpoints, or check your version/method filters.`
271
276
  };
272
277
  }
273
- return limitedResults;
278
+ // Sort by score descending (only meaningful if not wildcard)
279
+ if (!isWildcard) {
280
+ allMatches.sort((a, b) => b.score - a.score);
281
+ }
282
+ // Pagination
283
+ const LIMIT = 10;
284
+ const totalPages = Math.ceil(totalFound / LIMIT);
285
+ const currentPage = Math.max(1, page); // Ensure page is at least 1
286
+ const start = (currentPage - 1) * LIMIT;
287
+ const end = start + LIMIT;
288
+ const slicedResults = allMatches.slice(start, end).map(({ score, ...rest }) => rest);
289
+ let warning = undefined;
290
+ if (totalPages > 1) {
291
+ warning = `Found ${totalFound} results. Showing page ${currentPage} of ${totalPages}.`;
292
+ if (currentPage < totalPages) {
293
+ warning += ` Use 'page: ${currentPage + 1}' to see next results.`;
294
+ }
295
+ }
296
+ return {
297
+ results: slicedResults,
298
+ meta: {
299
+ total: totalFound,
300
+ page: currentPage,
301
+ totalPages: totalPages
302
+ },
303
+ warning
304
+ };
274
305
  }
275
306
  // Helper to get full details of an API
276
307
  async getApiDetails(apiPath, method) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fmea-api-mcp-server",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "MCP server for serving API documentation from endpoints directory",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",