fmea-api-mcp-server 1.0.5 → 1.0.6

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/README.md CHANGED
@@ -99,5 +99,9 @@ When the package is published to NPM:
99
99
  ## Features
100
100
  - **Resources**: Can read JSON files in the `endpoints` folder.
101
101
  - **Tools**:
102
- - `search_apis`: Search APIs by keyword (returns summaries).
102
+ - **Tools**:
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.
103
107
  - `get_api_details`: Get full details (schema, parameters) for a specific endpoint.
package/dist/index.js CHANGED
@@ -104,7 +104,15 @@ class ApiDocsServer {
104
104
  properties: {
105
105
  query: {
106
106
  type: "string",
107
- description: "Search query (e.g. 'user login', 'POST /api/v1')",
107
+ description: "Search query (e.g. 'user login', 'create project').",
108
+ },
109
+ method: {
110
+ type: "string",
111
+ description: "Filter by HTTP method (e.g. 'GET', 'POST'). Optional.",
112
+ },
113
+ version: {
114
+ type: "string",
115
+ description: "Filter by API version (e.g. 'v1', 'v2'). Optional.",
108
116
  },
109
117
  },
110
118
  required: ["query"],
@@ -134,7 +142,9 @@ class ApiDocsServer {
134
142
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
135
143
  if (request.params.name === "search_apis") {
136
144
  const query = String(request.params.arguments?.query).toLowerCase();
137
- const results = await this.searchInFiles(query);
145
+ const method = request.params.arguments?.method ? String(request.params.arguments?.method).toUpperCase() : undefined;
146
+ const version = request.params.arguments?.version ? String(request.params.arguments?.version).toLowerCase() : undefined;
147
+ const results = await this.searchInFiles(query, method, version);
138
148
  return {
139
149
  content: [
140
150
  {
@@ -195,20 +205,45 @@ class ApiDocsServer {
195
205
  }
196
206
  return results;
197
207
  }
198
- // Simple search helper - returns summaries
199
- async searchInFiles(query) {
208
+ // Smart search helper with scoring, filtering, and limits
209
+ async searchInFiles(query, filterMethod, filterVersion) {
200
210
  const files = await this.getAllFiles(ENDPOINTS_DIR);
201
- const matches = [];
211
+ let allMatches = [];
202
212
  for (const filePath of files) {
203
213
  try {
204
214
  const content = await fs.readFile(filePath, "utf-8");
205
215
  const json = JSON.parse(content);
206
216
  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
219
+ if (filterVersion) {
220
+ const fileVersion = fileName.split(path.sep)[0]; // e.g. "v1" from "v1/projects/..."
221
+ if (fileVersion !== filterVersion && json.version !== filterVersion) {
222
+ continue;
223
+ }
224
+ }
207
225
  if (json.endpoints && Array.isArray(json.endpoints)) {
208
226
  for (const endpoint of json.endpoints) {
209
- const str = JSON.stringify(endpoint).toLowerCase();
210
- if (str.includes(query)) {
211
- matches.push({
227
+ // Method Filtering
228
+ if (filterMethod && endpoint.method.toUpperCase() !== filterMethod) {
229
+ continue;
230
+ }
231
+ // Scoring Logic
232
+ 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;
244
+ if (score > 0) {
245
+ allMatches.push({
246
+ score,
212
247
  file: fileName,
213
248
  method: endpoint.method,
214
249
  path: endpoint.path,
@@ -223,7 +258,19 @@ class ApiDocsServer {
223
258
  // Ignore parse errors
224
259
  }
225
260
  }
226
- return matches;
261
+ // Sort by score descending
262
+ allMatches.sort((a, b) => b.score - a.score);
263
+ // Limit results
264
+ const LIMIT = 10;
265
+ const totalFound = allMatches.length;
266
+ const limitedResults = allMatches.slice(0, LIMIT).map(({ score, ...rest }) => rest); // Remove score from output
267
+ if (totalFound > LIMIT) {
268
+ return {
269
+ results: limitedResults,
270
+ warning: `Found ${totalFound} results. Showing top ${LIMIT}. Please refine your search query or use filters.`
271
+ };
272
+ }
273
+ return limitedResults;
227
274
  }
228
275
  // Helper to get full details of an API
229
276
  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.5",
3
+ "version": "1.0.6",
4
4
  "description": "MCP server for serving API documentation from endpoints directory",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",