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 +114 -9
- {fid_mcp-0.1.1.dist-info → fid_mcp-0.1.2.dist-info}/METADATA +5 -4
- fid_mcp-0.1.2.dist-info/RECORD +9 -0
- fid_mcp-0.1.1.dist-info/RECORD +0 -9
- {fid_mcp-0.1.1.dist-info → fid_mcp-0.1.2.dist-info}/WHEEL +0 -0
- {fid_mcp-0.1.1.dist-info → fid_mcp-0.1.2.dist-info}/entry_points.txt +0 -0
- {fid_mcp-0.1.1.dist-info → fid_mcp-0.1.2.dist-info}/licenses/LICENSE +0 -0
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
|
-
|
|
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(
|
|
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.
|
|
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.
|
|
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
|
|
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,,
|
fid_mcp-0.1.1.dist-info/RECORD
DELETED
|
@@ -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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|