gfp-mcp 0.2.1__py3-none-any.whl → 0.3.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.
@@ -0,0 +1,29 @@
1
+ gfp_mcp/__init__.py,sha256=7q7olhYHIRXAfT1rSsgTW0duRoQf_uRpFx4yFjSwXSk,1127
2
+ gfp_mcp/client.py,sha256=2-b_FZSC_8576qNLhVUrGT-oYWqr1RLTuz6BRrT0kak,9488
3
+ gfp_mcp/config.py,sha256=lrfg98VZDnIBlmPQD2V5sqw9aVZf7vsdPkOOsgqcqe0,4471
4
+ gfp_mcp/registry.py,sha256=ozDrMPksWoyKAkNd9MH2g8FRoN0XEQKWnLwZsgDxWLc,6127
5
+ gfp_mcp/render.py,sha256=rfiLzmcO9M4Zlvob-B89gu5K0GGu2cHX9GSJys4fexQ,3773
6
+ gfp_mcp/resources.py,sha256=upY93XVemc5ezx1p_YML57O6HYVahCs2RsYXn4Dw_X0,3517
7
+ gfp_mcp/samples.py,sha256=cJRho3G7RKeX7X9fIjJBpjUEGLAHuwHvPbYI5OZphTg,5610
8
+ gfp_mcp/server.py,sha256=dGhnKFKfoB4dBzk3MJ5aSVpeBFD1xQueLgCMdTYh8u8,7540
9
+ gfp_mcp/utils.py,sha256=awyJqKFlyIMIvM-8N0XT3S2vG_FYXkfpHJSAJCp-WcA,1719
10
+ gfp_mcp/tools/__init__.py,sha256=TwgWlw1fMyJKHYifjtESBQ21JmyGZ0pv9b2lmXU44r0,3557
11
+ gfp_mcp/tools/base.py,sha256=kNci7NdIKdY_qUWGgrARJk3KAS3PqzqzKiSNYNJ96Ks,7381
12
+ gfp_mcp/tools/bbox.py,sha256=P7PF0s4ykXfvaUtTNdPV7_WNOQZu76RXf85cXH70SIw,4296
13
+ gfp_mcp/tools/build.py,sha256=hW55JzNw3QL8RXDz8Yx0VJB-vq3WzZ9exwScSNcIYiA,5575
14
+ gfp_mcp/tools/cells.py,sha256=2kOPCxvMqz7rt7qr5Pytv7nEvdvxb7wmUPWc6s-WDxE,3044
15
+ gfp_mcp/tools/connectivity.py,sha256=wHAppW9b6Nern6YAdZpRcZ5jjPS09uJji5xFSZipu68,2259
16
+ gfp_mcp/tools/drc.py,sha256=DHRZDT9JsTLr8CMO6mEplBjUC8OSOAQSuisVYm5d5QI,12888
17
+ gfp_mcp/tools/freeze.py,sha256=d4U-nmHCVMJNgN0RSSwGjL9nXIusmuy5S0KgVJSqLLI,2702
18
+ gfp_mcp/tools/lvs.py,sha256=UfBqO5AQdKhvOkDHrjI-npTc6ktNSW_5HPR5WUUVTxY,2718
19
+ gfp_mcp/tools/pdk.py,sha256=jNWerrJy2NbdEVJxioTlM-uyvWJo1ZSm9l5FINAnUiE,1318
20
+ gfp_mcp/tools/port.py,sha256=Ldm2l771S3h_lEjZOoC1CMexdbk9nvrbU5tmbwkNFiY,2567
21
+ gfp_mcp/tools/project.py,sha256=ULqsMcnMDE9hJAxWTh9abWytkr0jhqLaqu9_2PgcMyg,4984
22
+ gfp_mcp/tools/samples.py,sha256=H-rwOtcqInTA9lmCMvuh8ZpLcVsa_fiZw1BPsxEDBI8,6819
23
+ gfp_mcp/tools/simulation.py,sha256=VtCq2gLloPeikFCNbn2Fvq9yngCSdXgz6kt32_0RUmI,5999
24
+ gfp_mcp-0.3.2.dist-info/licenses/LICENSE,sha256=ixSuHdKKXzNJw_eTgAxHzaCNIds8k48hytA_eJgA8gQ,225
25
+ gfp_mcp-0.3.2.dist-info/METADATA,sha256=fTeePDc3kjuicIEMJi-7wiIB3Nq2OrRMUpWJ17Nk9mY,8236
26
+ gfp_mcp-0.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
27
+ gfp_mcp-0.3.2.dist-info/entry_points.txt,sha256=Fbd4_16Giw-_y6piVlbk8sHDgvZbE3oqAfeYl21Xx98,54
28
+ gfp_mcp-0.3.2.dist-info/top_level.txt,sha256=F7RvvaMcHgg7J_fNBN77ZMt7r32U7ZbVrn4zM1odUSs,8
29
+ gfp_mcp-0.3.2.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gfp-mcp-serve = gfp_mcp.server:main
@@ -0,0 +1 @@
1
+ gfp_mcp
@@ -1,14 +0,0 @@
1
- gfp_mcp-0.2.1.dist-info/licenses/LICENSE,sha256=ixSuHdKKXzNJw_eTgAxHzaCNIds8k48hytA_eJgA8gQ,225
2
- mcp_standalone/__init__.py,sha256=B6JB7U_vEMARO87RzNDesfSZdGgD1U-RC2GkL2ijOCA,1069
3
- mcp_standalone/client.py,sha256=vS_mw3frp5dQr2s_uFbPH-cF4k98rOJFGZLIz1FOU7A,8371
4
- mcp_standalone/config.py,sha256=1B00PLrKOz96c62lkhIgrraF-HWZ015uoPZ7okCcuKk,1525
5
- mcp_standalone/mappings.py,sha256=2J2DEZzXTdmi6VmrtCeI1cg-2T7tYHkytRGrZJ62zog,10583
6
- mcp_standalone/registry.py,sha256=1E61UalVot8HUS3cALjM7ejYB0qR6tI5QbQSZZeQe7Y,6401
7
- mcp_standalone/resources.py,sha256=iMkYIyTxLWwWE0NLxprLabGFYbPnUaIbgwwtbvZ2av0,3606
8
- mcp_standalone/server.py,sha256=jDCns5Cgb5JZahbx8pjCCDqryT-RiLCOFD5FIpgr3OA,9149
9
- mcp_standalone/tools.py,sha256=totbebwVzqOej1TjmY6lOZ7raSPFIwGWmWfOFVN3IyE,18734
10
- gfp_mcp-0.2.1.dist-info/METADATA,sha256=16kFH1_7TvI11tZnuXXrdTyQ6os5s7I5E7mTvSdRfVA,6858
11
- gfp_mcp-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
- gfp_mcp-0.2.1.dist-info/entry_points.txt,sha256=mgyus9dsB_8mjgnztuHNPqzPi-7HcPg1iYzfM5NMIjk,61
13
- gfp_mcp-0.2.1.dist-info/top_level.txt,sha256=g2hRJHoDDPNtrNdXR70T7FR9Ev6DTRJiGW7ZvlvnXMc,15
14
- gfp_mcp-0.2.1.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- gfp-mcp-serve = mcp_standalone.server:main
@@ -1 +0,0 @@
1
- mcp_standalone
mcp_standalone/config.py DELETED
@@ -1,56 +0,0 @@
1
- """Configuration management for MCP standalone server."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
- from typing import Final
7
-
8
- __all__ = ["MCPConfig"]
9
-
10
-
11
- class MCPConfig:
12
- """Configuration for MCP standalone server.
13
-
14
- Manages environment variables and default settings for the MCP server
15
- that proxies requests to the FastAPI backend.
16
- """
17
-
18
- # FastAPI base URL (default: http://localhost:8787)
19
- # This default is primarily for backward compatibility.
20
- # The MCP server automatically discovers running servers via the registry.
21
- API_URL: Final[str] = os.getenv("GFP_API_URL", "http://localhost:8787")
22
-
23
- # Timeout for tool calls in seconds (default: 300 = 5 minutes)
24
- TIMEOUT: Final[int] = int(os.getenv("GFP_MCP_TIMEOUT", "300"))
25
-
26
- # Enable debug logging
27
- DEBUG: Final[bool] = os.getenv("GFP_MCP_DEBUG", "false").lower() in (
28
- "true",
29
- "1",
30
- "yes",
31
- )
32
-
33
- # Retry configuration
34
- MAX_RETRIES: Final[int] = 3
35
- RETRY_BACKOFF: Final[float] = 0.5 # Initial backoff in seconds
36
-
37
- @classmethod
38
- def get_api_url(cls, override: str | None = None) -> str:
39
- """Get the FastAPI base URL.
40
-
41
- Args:
42
- override: Optional URL to override the environment variable
43
-
44
- Returns:
45
- The API base URL
46
- """
47
- return override or cls.API_URL
48
-
49
- @classmethod
50
- def get_timeout(cls) -> int:
51
- """Get the timeout for tool calls.
52
-
53
- Returns:
54
- Timeout in seconds
55
- """
56
- return cls.TIMEOUT
@@ -1,386 +0,0 @@
1
- """Mappings from MCP tools to FastAPI endpoints.
2
-
3
- This module defines how MCP tool arguments are transformed into HTTP
4
- requests to the FastAPI backend, and how responses are transformed back.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from collections.abc import Callable
10
- from typing import Any
11
-
12
- __all__ = [
13
- "TOOL_MAPPINGS",
14
- "get_mapping",
15
- "transform_request",
16
- "transform_response",
17
- ]
18
-
19
-
20
- class EndpointMapping:
21
- """Configuration for mapping an MCP tool to a FastAPI endpoint."""
22
-
23
- def __init__(
24
- self,
25
- method: str,
26
- path: str,
27
- request_transformer: Callable[[dict[str, Any]], dict[str, Any]] | None = None,
28
- response_transformer: Callable[[Any], Any] | None = None,
29
- ) -> None:
30
- """Initialize endpoint mapping.
31
-
32
- Args:
33
- method: HTTP method (GET, POST, etc.)
34
- path: API endpoint path
35
- request_transformer: Optional function to transform MCP args to
36
- HTTP params
37
- response_transformer: Optional function to transform HTTP response
38
- to MCP format
39
- """
40
- self.method = method
41
- self.path = path
42
- self.request_transformer = request_transformer or (lambda x: x)
43
- self.response_transformer = response_transformer or (lambda x: x)
44
-
45
-
46
- def _build_cell_request(args: dict[str, Any]) -> dict[str, Any]:
47
- """Transform build_cell MCP args to FastAPI params.
48
-
49
- Args:
50
- args: MCP tool arguments
51
-
52
- Returns:
53
- Dict with 'params' key for query parameters
54
- """
55
- return {
56
- "params": {
57
- "name": args["name"],
58
- "with_metadata": args.get("with_metadata", True),
59
- "register": args.get("register", True),
60
- }
61
- }
62
-
63
-
64
- def _build_cells_request(args: dict[str, Any]) -> dict[str, Any]:
65
- """Transform build_cells MCP args to FastAPI params.
66
-
67
- Args:
68
- args: MCP tool arguments
69
-
70
- Returns:
71
- Dict with 'params' key for query parameters and 'json_data' for body
72
- """
73
- return {
74
- "params": {
75
- "with_metadata": args.get("with_metadata", True),
76
- "register": args.get("register", True),
77
- },
78
- "json_data": args["names"],
79
- }
80
-
81
-
82
- def _list_cells_response(response: Any) -> dict[str, Any]:
83
- """Transform list_cells response to MCP format.
84
-
85
- Args:
86
- response: FastAPI response (list of cell names)
87
-
88
- Returns:
89
- Formatted response with cell names
90
- """
91
- if isinstance(response, list):
92
- return {"cells": response, "count": len(response)}
93
- return response
94
-
95
-
96
- def _get_cell_info_request(args: dict[str, Any]) -> dict[str, Any]:
97
- """Transform get_cell_info MCP args to FastAPI params.
98
-
99
- Args:
100
- args: MCP tool arguments
101
-
102
- Returns:
103
- Dict with 'params' key for query parameters
104
- """
105
- return {"params": {"name": args["name"]}}
106
-
107
-
108
- def _download_gds_request(args: dict[str, Any]) -> dict[str, Any]:
109
- """Transform download_gds MCP args to FastAPI path.
110
-
111
- Args:
112
- args: MCP tool arguments
113
-
114
- Returns:
115
- Dict with modified 'path' for the endpoint
116
- """
117
- path = args["path"]
118
- # The path template in FastAPI is /api/download/{path:path}.gds
119
- # We need to construct the full path
120
- return {"path": f"/api/download/{path}.gds"}
121
-
122
-
123
- def _download_gds_response(response: Any) -> dict[str, Any]:
124
- """Transform download_gds response to MCP format.
125
-
126
- Args:
127
- response: FastAPI response (file path or error)
128
-
129
- Returns:
130
- Formatted response with file path
131
- """
132
- # If response is a string (text), it's likely the file content or path
133
- if isinstance(response, str):
134
- return {"status": "success", "message": response}
135
- return response
136
-
137
-
138
- def _check_drc_request(args: dict[str, Any]) -> dict[str, Any]:
139
- """Transform check_drc MCP args to FastAPI params.
140
-
141
- Args:
142
- args: MCP tool arguments
143
-
144
- Returns:
145
- Dict with 'json_data' key for request body
146
- """
147
- json_data: dict[str, Any] = {"path": args["path"]}
148
-
149
- # Add optional parameters if provided
150
- if "pdk" in args and args["pdk"]:
151
- json_data["pdk"] = args["pdk"]
152
- if "process" in args and args["process"]:
153
- json_data["process"] = args["process"]
154
- if "timeout" in args and args["timeout"]:
155
- json_data["timeout"] = args["timeout"]
156
- if "host" in args and args["host"]:
157
- json_data["host"] = args["host"]
158
-
159
- return {"json_data": json_data}
160
-
161
-
162
- def _check_connectivity_request(args: dict[str, Any]) -> dict[str, Any]:
163
- """Transform check_connectivity MCP args to FastAPI params.
164
-
165
- Args:
166
- args: MCP tool arguments
167
-
168
- Returns:
169
- Dict with 'json_data' key for request body
170
- """
171
- return {"json_data": {"path": args["path"]}}
172
-
173
-
174
- def _check_lvs_request(args: dict[str, Any]) -> dict[str, Any]:
175
- """Transform check_lvs MCP args to FastAPI params.
176
-
177
- Args:
178
- args: MCP tool arguments
179
-
180
- Returns:
181
- Dict with 'json_data' key for request body
182
- """
183
- return {
184
- "json_data": {
185
- "cell": args["cell"],
186
- "netpath": args["netpath"],
187
- "cellargs": args.get("cellargs", ""),
188
- }
189
- }
190
-
191
-
192
- def _simulate_component_request(args: dict[str, Any]) -> dict[str, Any]:
193
- """Transform simulate_component MCP args to FastAPI params.
194
-
195
- Args:
196
- args: MCP tool arguments
197
-
198
- Returns:
199
- Dict with 'params' key for query parameters
200
- """
201
- return {"params": {"name": args["name"]}}
202
-
203
-
204
- def _get_port_center_request(args: dict[str, Any]) -> dict[str, Any]:
205
- """Transform get_port_center MCP args to FastAPI params.
206
-
207
- Args:
208
- args: MCP tool arguments
209
-
210
- Returns:
211
- Dict with 'params' key for query parameters
212
- """
213
- return {
214
- "params": {
215
- "netlist": args["netlist"],
216
- "instance": args["instance"],
217
- "port": args["port"],
218
- }
219
- }
220
-
221
-
222
- def _generate_bbox_request(args: dict[str, Any]) -> dict[str, Any]:
223
- """Transform generate_bbox MCP args to FastAPI params.
224
-
225
- Args:
226
- args: MCP tool arguments
227
-
228
- Returns:
229
- Dict with 'json_data' key for request body
230
- """
231
- json_data: dict[str, Any] = {"path": args["path"]}
232
-
233
- # Add optional parameters if provided
234
- if "outpath" in args and args["outpath"]:
235
- json_data["outpath"] = args["outpath"]
236
- if "layers_to_keep" in args and args["layers_to_keep"]:
237
- json_data["layers_to_keep"] = args["layers_to_keep"]
238
- if "bbox_layer" in args and args["bbox_layer"]:
239
- json_data["bbox_layer"] = args["bbox_layer"]
240
- if "ignore_ports" in args:
241
- json_data["ignore_ports"] = args["ignore_ports"]
242
-
243
- return {"json_data": json_data}
244
-
245
-
246
- def _freeze_cell_request(args: dict[str, Any]) -> dict[str, Any]:
247
- """Transform freeze_cell MCP args to FastAPI params.
248
-
249
- Args:
250
- args: MCP tool arguments
251
-
252
- Returns:
253
- Dict with 'path' and 'json_data' for the request
254
- """
255
- cell_name = args["cell_name"]
256
- kwargs = args.get("kwargs", {})
257
-
258
- # The freeze endpoint expects a JSON string in the body.
259
- # httpx with json= will JSON-encode the dict and send it as the body,
260
- # which FastAPI's Body() will read as a string.
261
- return {
262
- "path": f"/freeze/{cell_name}",
263
- "json_data": kwargs, # httpx will JSON-encode this to a string
264
- }
265
-
266
-
267
- # Tool name -> Endpoint mapping
268
- TOOL_MAPPINGS: dict[str, EndpointMapping] = {
269
- # Phase 1: Core Building Tools
270
- "build_cell": EndpointMapping(
271
- method="GET",
272
- path="/api/build-cell",
273
- request_transformer=_build_cell_request,
274
- ),
275
- "build_cells": EndpointMapping(
276
- method="POST",
277
- path="/api/build-cells",
278
- request_transformer=_build_cells_request,
279
- ),
280
- "list_cells": EndpointMapping(
281
- method="GET",
282
- path="/api/cells",
283
- response_transformer=_list_cells_response,
284
- ),
285
- "get_cell_info": EndpointMapping(
286
- method="GET",
287
- path="/api/cell-info",
288
- request_transformer=_get_cell_info_request,
289
- ),
290
- "download_gds": EndpointMapping(
291
- method="GET",
292
- path="/api/download/{path}.gds",
293
- request_transformer=_download_gds_request,
294
- response_transformer=_download_gds_response,
295
- ),
296
- # Phase 2: Verification Tools
297
- "check_drc": EndpointMapping(
298
- method="POST",
299
- path="/api/check-drc",
300
- request_transformer=_check_drc_request,
301
- ),
302
- "check_connectivity": EndpointMapping(
303
- method="POST",
304
- path="/api/check-connectivity",
305
- request_transformer=_check_connectivity_request,
306
- ),
307
- "check_lvs": EndpointMapping(
308
- method="POST",
309
- path="/api/check-lvs",
310
- request_transformer=_check_lvs_request,
311
- ),
312
- # Phase 4: Simulation & Advanced Tools
313
- "simulate_component": EndpointMapping(
314
- method="GET",
315
- path="/api/simulate",
316
- request_transformer=_simulate_component_request,
317
- ),
318
- "get_port_center": EndpointMapping(
319
- method="GET",
320
- path="/api/port-center",
321
- request_transformer=_get_port_center_request,
322
- ),
323
- "generate_bbox": EndpointMapping(
324
- method="POST",
325
- path="/api/bbox",
326
- request_transformer=_generate_bbox_request,
327
- ),
328
- "freeze_cell": EndpointMapping(
329
- method="POST",
330
- path="/freeze/{cell_name}",
331
- request_transformer=_freeze_cell_request,
332
- ),
333
- "get_pdk_info": EndpointMapping(
334
- method="GET",
335
- path="/info",
336
- ),
337
- }
338
-
339
-
340
- def get_mapping(tool_name: str) -> EndpointMapping | None:
341
- """Get the endpoint mapping for a tool.
342
-
343
- Args:
344
- tool_name: Name of the MCP tool
345
-
346
- Returns:
347
- EndpointMapping or None if not found
348
- """
349
- return TOOL_MAPPINGS.get(tool_name)
350
-
351
-
352
- def transform_request(
353
- tool_name: str,
354
- args: dict[str, Any],
355
- ) -> dict[str, Any]:
356
- """Transform MCP tool arguments to HTTP request parameters.
357
-
358
- Args:
359
- tool_name: Name of the MCP tool
360
- args: Tool arguments from MCP
361
-
362
- Returns:
363
- Dict containing HTTP request parameters (params, json_data, path, etc.)
364
- """
365
- mapping = get_mapping(tool_name)
366
- if mapping is None:
367
- return {}
368
-
369
- return mapping.request_transformer(args)
370
-
371
-
372
- def transform_response(tool_name: str, response: Any) -> Any:
373
- """Transform HTTP response to MCP format.
374
-
375
- Args:
376
- tool_name: Name of the MCP tool
377
- response: HTTP response from FastAPI
378
-
379
- Returns:
380
- Transformed response for MCP
381
- """
382
- mapping = get_mapping(tool_name)
383
- if mapping is None:
384
- return response
385
-
386
- return mapping.response_transformer(response)