gfp-mcp 0.2.4__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.
- {mcp_standalone → gfp_mcp}/__init__.py +10 -8
- {mcp_standalone → gfp_mcp}/client.py +0 -14
- gfp_mcp/config.py +161 -0
- gfp_mcp/render.py +139 -0
- gfp_mcp/samples.py +206 -0
- gfp_mcp/server.py +235 -0
- gfp_mcp/tools/__init__.py +134 -0
- gfp_mcp/tools/base.py +235 -0
- gfp_mcp/tools/bbox.py +115 -0
- gfp_mcp/tools/build.py +159 -0
- gfp_mcp/tools/cells.py +103 -0
- gfp_mcp/tools/connectivity.py +70 -0
- gfp_mcp/tools/drc.py +379 -0
- gfp_mcp/tools/freeze.py +82 -0
- gfp_mcp/tools/lvs.py +86 -0
- gfp_mcp/tools/pdk.py +47 -0
- gfp_mcp/tools/port.py +82 -0
- gfp_mcp/tools/project.py +160 -0
- gfp_mcp/tools/samples.py +215 -0
- gfp_mcp/tools/simulation.py +153 -0
- gfp_mcp/utils.py +55 -0
- {gfp_mcp-0.2.4.dist-info → gfp_mcp-0.3.2.dist-info}/METADATA +13 -1
- gfp_mcp-0.3.2.dist-info/RECORD +29 -0
- gfp_mcp-0.3.2.dist-info/entry_points.txt +2 -0
- gfp_mcp-0.3.2.dist-info/top_level.txt +1 -0
- gfp_mcp-0.2.4.dist-info/RECORD +0 -14
- gfp_mcp-0.2.4.dist-info/entry_points.txt +0 -2
- gfp_mcp-0.2.4.dist-info/top_level.txt +0 -1
- mcp_standalone/config.py +0 -50
- mcp_standalone/mappings.py +0 -565
- mcp_standalone/server.py +0 -282
- mcp_standalone/tools.py +0 -466
- {mcp_standalone → gfp_mcp}/registry.py +0 -0
- {mcp_standalone → gfp_mcp}/resources.py +0 -0
- {gfp_mcp-0.2.4.dist-info → gfp_mcp-0.3.2.dist-info}/WHEEL +0 -0
- {gfp_mcp-0.2.4.dist-info → gfp_mcp-0.3.2.dist-info}/licenses/LICENSE +0 -0
gfp_mcp/tools/bbox.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Bounding box generation tool handler.
|
|
2
|
+
|
|
3
|
+
This module provides the handler for generating bounding box
|
|
4
|
+
GDS files from input GDS files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.types import Tool
|
|
12
|
+
|
|
13
|
+
from .base import EndpointMapping, ToolHandler, add_project_param
|
|
14
|
+
|
|
15
|
+
__all__ = ["GenerateBboxHandler"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GenerateBboxHandler(ToolHandler):
|
|
19
|
+
"""Handler for generating bounding box GDS files.
|
|
20
|
+
|
|
21
|
+
Creates a simplified version of the layout with only a bounding box
|
|
22
|
+
on specified layers.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def name(self) -> str:
|
|
27
|
+
return "generate_bbox"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def definition(self) -> Tool:
|
|
31
|
+
return Tool(
|
|
32
|
+
name="generate_bbox",
|
|
33
|
+
description=(
|
|
34
|
+
"Generate a bounding box GDS file from an input GDS. This creates "
|
|
35
|
+
"a simplified version of the layout with only a bounding box on "
|
|
36
|
+
"specified layers. Useful for creating abstract views, floorplanning, "
|
|
37
|
+
"or hierarchical design. Can optionally preserve specific layers and "
|
|
38
|
+
"ports."
|
|
39
|
+
),
|
|
40
|
+
inputSchema=add_project_param(
|
|
41
|
+
{
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"path": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": (
|
|
47
|
+
"Path to the input GDS file. Can be absolute or relative "
|
|
48
|
+
"to the project directory."
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
"outpath": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": (
|
|
54
|
+
"Output path for the bounding box GDS. If not specified, "
|
|
55
|
+
"uses the input filename with '-bbox' suffix."
|
|
56
|
+
),
|
|
57
|
+
"default": "",
|
|
58
|
+
},
|
|
59
|
+
"layers_to_keep": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": {"type": "string"},
|
|
62
|
+
"description": (
|
|
63
|
+
"List of layer names to preserve in the output. "
|
|
64
|
+
"Other layers will be replaced by the bounding box."
|
|
65
|
+
),
|
|
66
|
+
"default": [],
|
|
67
|
+
},
|
|
68
|
+
"bbox_layer": {
|
|
69
|
+
"type": "array",
|
|
70
|
+
"items": {"type": "integer"},
|
|
71
|
+
"description": (
|
|
72
|
+
"Layer (as [layer, datatype]) to use for the bounding box. "
|
|
73
|
+
"Default is [99, 0]."
|
|
74
|
+
),
|
|
75
|
+
"default": [99, 0],
|
|
76
|
+
},
|
|
77
|
+
"ignore_ports": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": (
|
|
80
|
+
"If true, do not include ports in the output. "
|
|
81
|
+
"Default is false."
|
|
82
|
+
),
|
|
83
|
+
"default": False,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"required": ["path"],
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def mapping(self) -> EndpointMapping:
|
|
93
|
+
return EndpointMapping(method="POST", path="/api/bbox")
|
|
94
|
+
|
|
95
|
+
def transform_request(self, args: dict[str, Any]) -> dict[str, Any]:
|
|
96
|
+
"""Transform generate_bbox MCP args to FastAPI params.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
args: MCP tool arguments
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Dict with 'json_data' key for request body
|
|
103
|
+
"""
|
|
104
|
+
json_data: dict[str, Any] = {"path": args["path"]}
|
|
105
|
+
|
|
106
|
+
if "outpath" in args and args["outpath"]:
|
|
107
|
+
json_data["outpath"] = args["outpath"]
|
|
108
|
+
if "layers_to_keep" in args and args["layers_to_keep"]:
|
|
109
|
+
json_data["layers_to_keep"] = args["layers_to_keep"]
|
|
110
|
+
if "bbox_layer" in args and args["bbox_layer"]:
|
|
111
|
+
json_data["bbox_layer"] = args["bbox_layer"]
|
|
112
|
+
if "ignore_ports" in args:
|
|
113
|
+
json_data["ignore_ports"] = args["ignore_ports"]
|
|
114
|
+
|
|
115
|
+
return {"json_data": json_data}
|
gfp_mcp/tools/build.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Build cells tool handler.
|
|
2
|
+
|
|
3
|
+
This module provides the handler for building GDS cells, including
|
|
4
|
+
optional PNG image rendering for visualization.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
from mcp.types import ImageContent, TextContent, Tool
|
|
14
|
+
|
|
15
|
+
from ..render import HAS_KLAYOUT, render_built_cells
|
|
16
|
+
from .base import EndpointMapping, ToolHandler, add_project_param
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from ..client import FastAPIClient
|
|
20
|
+
|
|
21
|
+
__all__ = ["BuildCellsHandler"]
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BuildCellsHandler(ToolHandler):
|
|
27
|
+
"""Handler for building GDS cells.
|
|
28
|
+
|
|
29
|
+
This handler builds one or more GDS cells and optionally renders
|
|
30
|
+
specified cells to PNG images for visualization.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def name(self) -> str:
|
|
35
|
+
return "build_cells"
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def definition(self) -> Tool:
|
|
39
|
+
return Tool(
|
|
40
|
+
name="build_cells",
|
|
41
|
+
description=(
|
|
42
|
+
"Build one or more GDS cells by name. This creates the physical layout "
|
|
43
|
+
"files (.gds) for photonic components. Pass a list of cell names to build. "
|
|
44
|
+
"For a single cell, pass a list with one element. All cells are built "
|
|
45
|
+
"in the background and saved to the project build directory. "
|
|
46
|
+
"Use the optional 'visualize' parameter to specify which cells should be "
|
|
47
|
+
"rendered to PNG images and returned in the response."
|
|
48
|
+
),
|
|
49
|
+
inputSchema=add_project_param(
|
|
50
|
+
{
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"names": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"items": {"type": "string"},
|
|
56
|
+
"description": "List of cell/component names to build (can be a single-item list)",
|
|
57
|
+
},
|
|
58
|
+
"visualize": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"items": {"type": "string"},
|
|
61
|
+
"description": (
|
|
62
|
+
"Optional list of cell names to render as PNG images. "
|
|
63
|
+
"Only cells in this list will be visualized. If not provided, "
|
|
64
|
+
"no images are returned. Use this to selectively view only "
|
|
65
|
+
"the cells you need to inspect."
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
"with_metadata": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": (
|
|
71
|
+
"Include metadata in the GDS files (default: true)"
|
|
72
|
+
),
|
|
73
|
+
"default": True,
|
|
74
|
+
},
|
|
75
|
+
"register": {
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"description": (
|
|
78
|
+
"Re-register the cells in the KLayout cache (default: true)"
|
|
79
|
+
),
|
|
80
|
+
"default": True,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
"required": ["names"],
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def mapping(self) -> EndpointMapping:
|
|
90
|
+
return EndpointMapping(method="POST", path="/api/build-cells")
|
|
91
|
+
|
|
92
|
+
def transform_request(self, args: dict[str, Any]) -> dict[str, Any]:
|
|
93
|
+
"""Transform build_cells MCP args to FastAPI params.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
args: MCP tool arguments
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Dict with 'params' key for query parameters and 'json_data' for body
|
|
100
|
+
"""
|
|
101
|
+
return {
|
|
102
|
+
"params": {
|
|
103
|
+
"with_metadata": args.get("with_metadata", True),
|
|
104
|
+
"register": args.get("register", True),
|
|
105
|
+
},
|
|
106
|
+
"json_data": args["names"],
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async def handle(
|
|
110
|
+
self,
|
|
111
|
+
arguments: dict[str, Any],
|
|
112
|
+
client: FastAPIClient,
|
|
113
|
+
) -> list[TextContent | ImageContent]:
|
|
114
|
+
"""Build cells and optionally render images.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
arguments: MCP tool arguments
|
|
118
|
+
client: FastAPI client for making requests
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
List of TextContent with build results and optional ImageContent
|
|
122
|
+
"""
|
|
123
|
+
try:
|
|
124
|
+
project = arguments.get("project")
|
|
125
|
+
transformed = self.transform_request(arguments)
|
|
126
|
+
|
|
127
|
+
response = await client.request(
|
|
128
|
+
method=self.mapping.method,
|
|
129
|
+
path=self.mapping.path,
|
|
130
|
+
params=transformed.get("params"),
|
|
131
|
+
json_data=transformed.get("json_data"),
|
|
132
|
+
project=project,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
logger.debug("Build cells result: %s", response)
|
|
136
|
+
|
|
137
|
+
results: list[TextContent | ImageContent] = [
|
|
138
|
+
TextContent(
|
|
139
|
+
type="text",
|
|
140
|
+
text=json.dumps(response, indent=2),
|
|
141
|
+
)
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
# Render images if klayout is available and visualize is specified
|
|
145
|
+
visualize = arguments.get("visualize", [])
|
|
146
|
+
if visualize and HAS_KLAYOUT:
|
|
147
|
+
results.extend(await render_built_cells(visualize, project))
|
|
148
|
+
|
|
149
|
+
return results
|
|
150
|
+
|
|
151
|
+
except Exception as e:
|
|
152
|
+
error_msg = f"Tool execution failed: {e!s}"
|
|
153
|
+
logger.exception(error_msg)
|
|
154
|
+
return [
|
|
155
|
+
TextContent(
|
|
156
|
+
type="text",
|
|
157
|
+
text=json.dumps({"error": error_msg}),
|
|
158
|
+
)
|
|
159
|
+
]
|
gfp_mcp/tools/cells.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Cell listing and info tool handlers.
|
|
2
|
+
|
|
3
|
+
These tools provide information about available cells/components
|
|
4
|
+
in the current PDK.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.types import Tool
|
|
12
|
+
|
|
13
|
+
from .base import EndpointMapping, ToolHandler, add_project_param
|
|
14
|
+
|
|
15
|
+
__all__ = ["ListCellsHandler", "GetCellInfoHandler"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ListCellsHandler(ToolHandler):
|
|
19
|
+
"""Handler for listing all available cells/components."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def name(self) -> str:
|
|
23
|
+
return "list_cells"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def definition(self) -> Tool:
|
|
27
|
+
return Tool(
|
|
28
|
+
name="list_cells",
|
|
29
|
+
description=(
|
|
30
|
+
"List all available cells/components that can be built. Returns "
|
|
31
|
+
"the names of all registered component factories in the current PDK. "
|
|
32
|
+
"Use this to discover what components are available before building."
|
|
33
|
+
),
|
|
34
|
+
inputSchema=add_project_param(
|
|
35
|
+
{
|
|
36
|
+
"type": "object",
|
|
37
|
+
"properties": {},
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def mapping(self) -> EndpointMapping:
|
|
44
|
+
return EndpointMapping(method="GET", path="/api/cells")
|
|
45
|
+
|
|
46
|
+
def transform_response(self, response: Any) -> dict[str, Any]:
|
|
47
|
+
"""Transform list_cells response to MCP format.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
response: FastAPI response (list of cell names)
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Formatted response with cell names
|
|
54
|
+
"""
|
|
55
|
+
if isinstance(response, list):
|
|
56
|
+
return {"cells": response, "count": len(response)}
|
|
57
|
+
return response
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class GetCellInfoHandler(ToolHandler):
|
|
61
|
+
"""Handler for getting detailed info about a specific cell."""
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def name(self) -> str:
|
|
65
|
+
return "get_cell_info"
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def definition(self) -> Tool:
|
|
69
|
+
return Tool(
|
|
70
|
+
name="get_cell_info",
|
|
71
|
+
description=(
|
|
72
|
+
"Get detailed information about a specific cell/component. Returns "
|
|
73
|
+
"metadata including the source file, parameters, and other details "
|
|
74
|
+
"about the component factory."
|
|
75
|
+
),
|
|
76
|
+
inputSchema=add_project_param(
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"properties": {
|
|
80
|
+
"name": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"description": "Name of the cell/component to get info about",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
"required": ["name"],
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def mapping(self) -> EndpointMapping:
|
|
92
|
+
return EndpointMapping(method="GET", path="/api/cell-info")
|
|
93
|
+
|
|
94
|
+
def transform_request(self, args: dict[str, Any]) -> dict[str, Any]:
|
|
95
|
+
"""Transform get_cell_info MCP args to FastAPI params.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
args: MCP tool arguments
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Dict with 'params' key for query parameters
|
|
102
|
+
"""
|
|
103
|
+
return {"params": {"name": args["name"]}}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Connectivity check tool handler.
|
|
2
|
+
|
|
3
|
+
This module provides the handler for running local connectivity
|
|
4
|
+
checks on GDS files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.types import Tool
|
|
12
|
+
|
|
13
|
+
from .base import EndpointMapping, ToolHandler, add_project_param
|
|
14
|
+
|
|
15
|
+
__all__ = ["CheckConnectivityHandler"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CheckConnectivityHandler(ToolHandler):
|
|
19
|
+
"""Handler for running connectivity checks on GDS files.
|
|
20
|
+
|
|
21
|
+
This is a fast, local check that verifies all layers are properly
|
|
22
|
+
connected and identifies any connectivity violations.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def name(self) -> str:
|
|
27
|
+
return "check_connectivity"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def definition(self) -> Tool:
|
|
31
|
+
return Tool(
|
|
32
|
+
name="check_connectivity",
|
|
33
|
+
description=(
|
|
34
|
+
"Run a local connectivity check on a GDS file. This verifies that "
|
|
35
|
+
"all layers are properly connected and identifies any connectivity "
|
|
36
|
+
"violations. This is a fast, local check (does not require uploading "
|
|
37
|
+
"to a remote server). Use this to quickly check for disconnected "
|
|
38
|
+
"components. Returns XML results showing connectivity issues."
|
|
39
|
+
),
|
|
40
|
+
inputSchema=add_project_param(
|
|
41
|
+
{
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"path": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": (
|
|
47
|
+
"Path to the GDS file to check. Can be absolute or "
|
|
48
|
+
"relative to the project directory."
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
"required": ["path"],
|
|
53
|
+
}
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def mapping(self) -> EndpointMapping:
|
|
59
|
+
return EndpointMapping(method="POST", path="/api/check-connectivity")
|
|
60
|
+
|
|
61
|
+
def transform_request(self, args: dict[str, Any]) -> dict[str, Any]:
|
|
62
|
+
"""Transform check_connectivity MCP args to FastAPI params.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
args: MCP tool arguments
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Dict with 'json_data' key for request body
|
|
69
|
+
"""
|
|
70
|
+
return {"json_data": {"path": args["path"]}}
|