fid-mcp 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.

Potentially problematic release.


This version of fid-mcp might be problematic. Click here for more details.

fid_mcp/server.py CHANGED
@@ -204,14 +204,38 @@ class DynamicToolServer:
204
204
  }
205
205
  self.tools: Dict[str, Dict[str, Any]] = {}
206
206
 
207
+ # Fid knowledge base configuration
208
+ self.fid_config = None
209
+ self.fid_pat = os.environ.get("FID_PAT")
210
+
207
211
  # Setup handlers
208
212
  self.setup_handlers()
209
213
 
210
214
  def setup_handlers(self):
211
215
  @self.server.list_tools()
212
216
  async def handle_list_tools() -> list[types.Tool]:
213
- """Return all dynamically loaded tools"""
217
+ """Return all dynamically loaded tools plus Fid search"""
214
218
  tools = []
219
+
220
+ # Always add Fid search tool (will show error if not configured when called)
221
+ tools.append(
222
+ types.Tool(
223
+ name="search",
224
+ description="Search the user's Fid knowledge base, which typically contains datasheets, integration manuals, API references, and other technical documentation, particularly for hardware components. ALWAYS try searching Fid first if the user asks about a hardware component, datasheet, manual, or API spec.",
225
+ inputSchema={
226
+ "type": "object",
227
+ "properties": {
228
+ "query": {
229
+ "type": "string",
230
+ "description": "The search query string",
231
+ }
232
+ },
233
+ "required": ["query"],
234
+ },
235
+ )
236
+ )
237
+
238
+ # Add dynamically loaded tools
215
239
  for tool_name, tool_def in self.tools.items():
216
240
  # Build input schema from parameters
217
241
  properties = {}
@@ -249,7 +273,33 @@ class DynamicToolServer:
249
273
  async def handle_call_tool(
250
274
  name: str, arguments: Dict[str, Any] | None
251
275
  ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
252
- """Execute a dynamically loaded tool"""
276
+ """Execute a dynamically loaded tool or Fid search"""
277
+
278
+ # Handle Fid search tool
279
+ if name == "search":
280
+ if not self.fid_pat:
281
+ error_msg = "Personal Access Token (PAT) missing. Please install the Fid MCP server according to these instructions: https://docs.fidlabs.ai/en/latest/connecting-agents.html"
282
+ return [types.TextContent(type="text", text=f"Error: {error_msg}")]
283
+
284
+ if not self.fid_config:
285
+ error_msg = "No Fid toolkit found in current directory. Download an existing toolkit from your Fid project, or create a new one with these instructions: https://docs.fidlabs.ai/en/latest/toolkits.html"
286
+ return [types.TextContent(type="text", text=f"Error: {error_msg}")]
287
+
288
+ if not arguments or "query" not in arguments:
289
+ raise ValueError("Query parameter is required")
290
+
291
+ try:
292
+ results = await self._search_fid_knowledge(arguments["query"])
293
+ return [
294
+ types.TextContent(
295
+ type="text", text=json.dumps(results, indent=2)
296
+ )
297
+ ]
298
+ except Exception as e:
299
+ error_msg = f"Search failed: {str(e)}"
300
+ return [types.TextContent(type="text", text=f"Error: {error_msg}")]
301
+
302
+ # Handle dynamic tools
253
303
  if name not in self.tools:
254
304
  raise ValueError(f"Unknown tool: {name}")
255
305
 
@@ -324,6 +374,55 @@ class DynamicToolServer:
324
374
  output = self._build_output(tool_def.get("output"), exec_context)
325
375
  return [types.TextContent(type="text", text=json.dumps(output, indent=2))]
326
376
 
377
+ async def _search_fid_knowledge(self, query: str) -> Dict[str, Any]:
378
+ """Search the Fid knowledge base"""
379
+ import aiohttp
380
+ import time
381
+
382
+ start_time = time.time()
383
+ default_k = 6
384
+
385
+ # Use the correct projects/{projectId}/search endpoint
386
+ url = f"{self.fid_config['apiBaseUrl']}/projects/{self.fid_config['projectId']}/search"
387
+ headers = {
388
+ "X-API-Key": self.fid_pat,
389
+ "X-Client-Source": "mcp_client",
390
+ }
391
+
392
+ payload = {
393
+ "query": query,
394
+ "k": default_k,
395
+ "userId": "", # Required field, can be empty
396
+ "search_method": "multi_stage",
397
+ "multi_stage_methods": ["full_text", "vector"],
398
+ }
399
+
400
+ async with aiohttp.ClientSession() as session:
401
+ async with session.post(url, json=payload, headers=headers) as response:
402
+ if response.status != 200:
403
+ error_text = await response.text()
404
+ raise ValueError(
405
+ f"API request failed with status {response.status}: {error_text}"
406
+ )
407
+
408
+ data = await response.json()
409
+
410
+ # Log search time
411
+ duration = time.time() - start_time
412
+
413
+ if not data.get("results"):
414
+ return {
415
+ "results": [],
416
+ "message": "No search results found",
417
+ "duration": duration,
418
+ }
419
+
420
+ return {
421
+ "results": data.get("results", []),
422
+ "totalCount": data.get("totalCount"),
423
+ "duration": duration,
424
+ }
425
+
327
426
  def load_toolset(self, filepath: Path):
328
427
  """Load and register tools from a .fidtools or fidtools.json file"""
329
428
  with open(filepath, "r") as f:
@@ -335,6 +434,13 @@ class DynamicToolServer:
335
434
  except ValueError as e:
336
435
  raise ValueError(f"Failed to validate toolset '{filepath}': {e}")
337
436
 
437
+ # Extract Fid configuration if present
438
+ if "projectId" in toolset and "apiBaseUrl" in toolset:
439
+ self.fid_config = {
440
+ "projectId": toolset["projectId"],
441
+ "apiBaseUrl": toolset["apiBaseUrl"],
442
+ }
443
+
338
444
  # Register each tool
339
445
  for tool_def in toolset["tools"]:
340
446
  self.tools[tool_def["name"]] = tool_def
@@ -426,19 +532,18 @@ class DynamicToolServer:
426
532
  f.write(f"Using working_dir: {working_dir}\n")
427
533
 
428
534
  # Look for .fidtools or fidtools.json file in actual working directory
429
- config_files = [
430
- working_dir / ".fidtools",
431
- working_dir / "fidtools.json"
432
- ]
433
-
535
+ config_files = [working_dir / ".fidtools", working_dir / "fidtools.json"]
536
+
434
537
  config_file = None
435
538
  for file_path in config_files:
436
539
  if file_path.exists() and file_path.is_file():
437
540
  config_file = file_path
438
541
  break
439
-
542
+
440
543
  with open(debug_log, "a") as f:
441
- f.write(f"Looking for config files: {', '.join(str(f) for f in config_files)}\n")
544
+ f.write(
545
+ f"Looking for config files: {', '.join(str(f) for f in config_files)}\n"
546
+ )
442
547
  if config_file:
443
548
  f.write(f"Found config file: {config_file}\n")
444
549
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fid-mcp
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: MCP Server for serving configurable Fid toolkits
5
5
  Project-URL: Homepage, https://fidlabs.ai
6
6
  Author-email: Fid Labs <contact@fidlabs.ai>
@@ -10,6 +10,7 @@ Keywords: mcp,model-context-protocol,server,tools
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.8
13
+ Requires-Dist: aiohttp
13
14
  Requires-Dist: mcp
14
15
  Requires-Dist: pexpect
15
16
  Requires-Dist: pydantic
@@ -17,12 +18,12 @@ Description-Content-Type: text/markdown
17
18
 
18
19
  # Fid MCP Server
19
20
 
20
- MCP server that dynamically serves tools according to `.fidtools` configs present in the working directory. `.fidtools` are generated by the Fid web application and intended to allow developers to quickly onboard coding agents to their unique development environments.
21
+ MCP server that dynamically serves tools according to `fidtools.json` or `.fidtools` configs present in the working directory. Toolkits are generated by the Fid web application and intended to allow developers to quickly onboard coding agents to their unique development environments.
21
22
 
22
23
  To install:
23
24
  ```bash
24
- claude mcp add fid --scope user --env FID_PAT=YOUR_FID_PAT -- uvx fid-mcp
25
+ claude mcp add Fid --scope user --env FID_PAT=YOUR_FID_PAT -- uvx fid-mcp
25
26
  ```
26
27
  Note: retrieve your PAT from the user menu in your Fid project, or just use the pre-constructed install command provided by the "Connect to your Agent" button.
27
28
 
28
- See [fidlabs.ai](https://fidlabs.ai) for more information or reach out to us at [contact@fidlabs.ai](mailto:contact@fidlabs.ai).
29
+ See [docs.fidlabs.ai](https://docs.fidlabs.ai) for more information or reach out to us at [contact@fidlabs.ai](mailto:contact@fidlabs.ai).
@@ -0,0 +1,9 @@
1
+ fid_mcp/__init__.py,sha256=cv_5UWE6kUBeTfAY6JZq9o47hEfzaLhcoKW0rw8GKq8,17
2
+ fid_mcp/config.py,sha256=YEH9BD4UWU9Hp3ifc3PGg4nk3FvFadfRt52-_fhCaqk,7365
3
+ fid_mcp/server.py,sha256=LctNUIjsBzvza6-NGNOxcByHjyFG83ojfxUdoELX8ak,22501
4
+ fid_mcp/shell.py,sha256=mLbGIVuk4LGCT37tS8deDOyTSY2zPG57WE9KBGsKSHg,26459
5
+ fid_mcp-0.1.2.dist-info/METADATA,sha256=VCqD3CDKW5tUkwe-HCtQGLFKFn_trrjxL0m4hBiArrM,1259
6
+ fid_mcp-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ fid_mcp-0.1.2.dist-info/entry_points.txt,sha256=Xdh2RDDC7r5rIXe1kM3smsA1rgNxd1tafL_JuuTJf2o,48
8
+ fid_mcp-0.1.2.dist-info/licenses/LICENSE,sha256=5SkiXC7s2RbMDCdmq4N6MCWNKw151sFmkGbWS9BLSJE,177
9
+ fid_mcp-0.1.2.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- fid_mcp/__init__.py,sha256=cv_5UWE6kUBeTfAY6JZq9o47hEfzaLhcoKW0rw8GKq8,17
2
- fid_mcp/config.py,sha256=YEH9BD4UWU9Hp3ifc3PGg4nk3FvFadfRt52-_fhCaqk,7365
3
- fid_mcp/server.py,sha256=ZlQqNW_b6vfGzjcxxgKPKYy_YNw7FQNZfbjKV0ywA04,18016
4
- fid_mcp/shell.py,sha256=mLbGIVuk4LGCT37tS8deDOyTSY2zPG57WE9KBGsKSHg,26459
5
- fid_mcp-0.1.1.dist-info/METADATA,sha256=l348ByqdrsTS43EchBzAFoyqQAj_GtRCUZ0_pd2wKfg,1210
6
- fid_mcp-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- fid_mcp-0.1.1.dist-info/entry_points.txt,sha256=Xdh2RDDC7r5rIXe1kM3smsA1rgNxd1tafL_JuuTJf2o,48
8
- fid_mcp-0.1.1.dist-info/licenses/LICENSE,sha256=5SkiXC7s2RbMDCdmq4N6MCWNKw151sFmkGbWS9BLSJE,177
9
- fid_mcp-0.1.1.dist-info/RECORD,,