gfp-mcp 0.1.0__py3-none-any.whl → 0.2.1__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,210 @@
1
+ Metadata-Version: 2.4
2
+ Name: gfp-mcp
3
+ Version: 0.2.1
4
+ Summary: Model Context Protocol (MCP) server for GDSFactory+ photonic IC design
5
+ Author: GDSFactory+ Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/doplaydo/gfp-mcp
8
+ Project-URL: Repository, https://github.com/doplaydo/gfp-mcp
9
+ Project-URL: Documentation, https://github.com/doplaydo/gfp-mcp#readme
10
+ Project-URL: Changelog, https://github.com/doplaydo/gfp-mcp/blob/main/CHANGELOG.md
11
+ Project-URL: Issue Tracker, https://github.com/doplaydo/gfp-mcp/issues
12
+ Keywords: mcp,gdsfactory,photonics,ic-design,eda,model-context-protocol,photonic-ic,gds
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3 :: Only
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: mcp>=1.7.1
28
+ Requires-Dist: httpx>=0.25.0
29
+ Requires-Dist: typing-extensions>=4.0.0; python_version < "3.11"
30
+ Requires-Dist: psutil>=5.9.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # GDSFactory+ MCP Server
39
+
40
+ [![PyPI version](https://img.shields.io/pypi/v/gfp-mcp.svg)](https://pypi.org/project/gfp-mcp/)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/gfp-mcp.svg)](https://pypi.org/project/gfp-mcp/)
42
+ [![Tests](https://github.com/doplaydo/gfp-mcp/workflows/Tests/badge.svg)](https://github.com/doplaydo/gfp-mcp/actions)
43
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
+
45
+ Model Context Protocol (MCP) server for GDSFactory+ that enables AI assistants like Claude to design and build photonic integrated circuits.
46
+
47
+ ## What is this?
48
+
49
+ This MCP server connects AI assistants to [GDSFactory+](https://gdsfactory.com), allowing you to design photonic ICs through natural language. Build components, run verification checks, and manage multiple projects directly from Claude Code or Claude Desktop.
50
+
51
+ ## Quick Start
52
+
53
+ ### 1. Install Prerequisites
54
+
55
+ - Python 3.10 or higher
56
+ - VSCode with the [GDSFactory+ extension](https://marketplace.visualstudio.com/items?itemName=gdsfactory.gdsfactoryplus) installed
57
+
58
+ ### 2. Install the MCP Server
59
+
60
+ ```bash
61
+ pip install gfp-mcp
62
+ ```
63
+
64
+ Or with uv:
65
+
66
+ ```bash
67
+ uvx --from gfp-mcp gfp-mcp-serve
68
+ ```
69
+
70
+ ### 3. Connect to Your AI Assistant
71
+
72
+ <details>
73
+ <summary><strong>Claude Code</strong></summary>
74
+
75
+ Add to `.claude/settings.json`:
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "gdsfactoryplus": {
81
+ "command": "gfp-mcp-serve",
82
+ "args": [],
83
+ "env": {
84
+ "GFP_API_URL": "http://localhost:8787"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ Or use the CLI:
92
+
93
+ ```bash
94
+ claude mcp add gdsfactoryplus -- gfp-mcp-serve
95
+ ```
96
+
97
+ </details>
98
+
99
+ <details>
100
+ <summary><strong>Claude Desktop</strong></summary>
101
+
102
+ Add to your config file:
103
+
104
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
105
+
106
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
107
+
108
+ **Linux**: `~/.config/Claude/claude_desktop_config.json`
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "gdsfactoryplus": {
114
+ "command": "gfp-mcp-serve",
115
+ "args": []
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ Restart Claude Desktop after adding the configuration.
122
+
123
+ </details>
124
+
125
+ <details>
126
+ <summary><strong>Cursor</strong></summary>
127
+
128
+ Coming soon. Follow the MCP integration instructions for Cursor when available.
129
+
130
+ </details>
131
+
132
+ ### 4. Start Designing
133
+
134
+ The MCP server automatically discovers running GDSFactory+ servers via the registry (`~/.gdsfactory/server-registry.json`). On startup, it will log all discovered projects.
135
+
136
+ Try these commands with your AI assistant:
137
+
138
+ - "List all available photonic components"
139
+ - "Build an MZI interferometer"
140
+ - "Show me details about the directional coupler"
141
+ - "Build multiple components: mzi, coupler, and bend_euler"
142
+ - "List all my GDSFactory+ projects"
143
+
144
+ ## Available Tools
145
+
146
+ - **build_cell** - Build a single GDS cell by name
147
+ - **build_cells** - Build multiple GDS cells in batch
148
+ - **list_cells** - List all available photonic components
149
+ - **get_cell_info** - Get detailed component metadata
150
+ - **download_gds** - Download built GDS files
151
+ - **list_projects** - List all running GDSFactory+ server instances
152
+ - **get_project_info** - Get detailed information about a specific project
153
+ - **check_drc** - Run Design Rule Check verification
154
+ - **check_connectivity** - Run connectivity verification
155
+ - **check_lvs** - Run Layout vs. Schematic verification
156
+
157
+ ## Multi-Project Support
158
+
159
+ The MCP server automatically discovers all running GDSFactory+ projects via the server registry (`~/.gdsfactory/server-registry.json`). The registry is the source of truth for available servers. Use the `list_projects` tool to see all running projects, then specify the project name when building components:
160
+
161
+ ```
162
+ User: "List all my GDSFactory+ projects"
163
+ Claude: [Uses list_projects tool to show all running servers]
164
+
165
+ User: "Build the mzi component in my_photonics_project"
166
+ Claude: [Routes request to the correct project]
167
+ ```
168
+
169
+ ## Troubleshooting
170
+
171
+ <details>
172
+ <summary><strong>Server not appearing in Claude</strong></summary>
173
+
174
+ 1. Verify installation: `gfp-mcp-serve --help`
175
+ 2. Check Claude Code logs: `claude --debug`
176
+ 3. Restart Claude Desktop/Code
177
+ 4. Ensure the GDSFactory+ VSCode extension is active and a project is open
178
+
179
+ </details>
180
+
181
+ <details>
182
+ <summary><strong>Connection refused errors</strong></summary>
183
+
184
+ The MCP server uses the registry (`~/.gdsfactory/server-registry.json`) to discover running servers.
185
+
186
+ 1. Use the `list_projects` tool in Claude to check available servers
187
+ 2. If no servers are found, ensure the GDSFactory+ VSCode extension is running with an active project:
188
+ - Open VSCode with the GDSFactory+ extension installed
189
+ - Open a GDSFactory+ project folder
190
+ - The extension automatically starts the server and registers it
191
+ 3. Check the MCP startup logs for discovered servers
192
+ 4. Verify the registry is accessible at `~/.gdsfactory/server-registry.json`
193
+ 5. For backward compatibility, you can set a specific server URL:
194
+
195
+ ```bash
196
+ export GFP_API_URL="http://localhost:YOUR_PORT"
197
+ ```
198
+
199
+ </details>
200
+
201
+ <details>
202
+ <summary><strong>Tool execution timeout</strong></summary>
203
+
204
+ Increase the timeout for long-running operations:
205
+
206
+ ```bash
207
+ export GFP_MCP_TIMEOUT=600 # 10 minutes
208
+ ```
209
+
210
+ </details>
@@ -0,0 +1,14 @@
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,4 @@
1
+ PROPRIETARY AND CONFIDENTIAL
2
+ THIS SOFTWARE IS THE SOLE PROPERTY AND COPYRIGHT (c) 2025 OF DOPLAYDO INC.
3
+ USE OR REPRODUCTION IN PART OR AS A WHOLE WITHOUT THE WRITTEN AGREEMENT OF DOPLAYDO IS PROHIBITED.
4
+ NOTICE VERSION: 0.0.2
@@ -23,6 +23,7 @@ from __future__ import annotations
23
23
 
24
24
  from .client import FastAPIClient
25
25
  from .config import MCPConfig
26
+ from .resources import get_all_resources, get_resource_content
26
27
  from .server import create_server, main, run_server
27
28
  from .tools import get_all_tools, get_tool_by_name
28
29
 
@@ -34,6 +35,8 @@ __all__ = [
34
35
  "run_server",
35
36
  "get_all_tools",
36
37
  "get_tool_by_name",
38
+ "get_all_resources",
39
+ "get_resource_content",
37
40
  ]
38
41
 
39
- __version__ = "0.1.0"
42
+ __version__ = "0.2.1"
mcp_standalone/client.py CHANGED
@@ -218,6 +218,10 @@ class FastAPIClient:
218
218
  async def health_check(self, project: str | None = None) -> bool:
219
219
  """Check if the FastAPI server is reachable.
220
220
 
221
+ .. deprecated::
222
+ This method is deprecated and no longer called during MCP startup.
223
+ Use list_projects() for server discovery instead.
224
+
221
225
  Args:
222
226
  project: Optional project name to check specific server
223
227
 
mcp_standalone/config.py CHANGED
@@ -16,6 +16,8 @@ class MCPConfig:
16
16
  """
17
17
 
18
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.
19
21
  API_URL: Final[str] = os.getenv("GFP_API_URL", "http://localhost:8787")
20
22
 
21
23
  # Timeout for tool calls in seconds (default: 300 = 5 minutes)
@@ -189,6 +189,81 @@ def _check_lvs_request(args: dict[str, Any]) -> dict[str, Any]:
189
189
  }
190
190
 
191
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
+
192
267
  # Tool name -> Endpoint mapping
193
268
  TOOL_MAPPINGS: dict[str, EndpointMapping] = {
194
269
  # Phase 1: Core Building Tools
@@ -234,6 +309,31 @@ TOOL_MAPPINGS: dict[str, EndpointMapping] = {
234
309
  path="/api/check-lvs",
235
310
  request_transformer=_check_lvs_request,
236
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
+ ),
237
337
  }
238
338
 
239
339
 
@@ -0,0 +1,141 @@
1
+ """MCP resource definitions for GDSFactory+.
2
+
3
+ This module defines the MCP resources that are exposed to AI assistants.
4
+ Resources provide read-only access to documentation and instruction content.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from mcp.types import Resource
10
+
11
+ __all__ = [
12
+ "RESOURCES",
13
+ "get_all_resources",
14
+ "get_resource_content",
15
+ ]
16
+
17
+
18
+ # Define available resources
19
+ RESOURCES: list[Resource] = [
20
+ Resource(
21
+ uri="instructions://build_custom_cell",
22
+ name="Build Custom Cell Instructions",
23
+ description=(
24
+ "Comprehensive instructions for building custom photonic cells "
25
+ "in GDSFactory+. Covers component creation, file organization, "
26
+ "PDK integration, and best practices."
27
+ ),
28
+ mimeType="text/markdown",
29
+ ),
30
+ ]
31
+
32
+
33
+ # Resource content
34
+ RESOURCE_CONTENT = {
35
+ "instructions://build_custom_cell": """---
36
+ Workflow: Creating Custom Components in GDSFactory+ Projects
37
+
38
+ Overview
39
+
40
+ When users request custom photonic components, keep user-defined components separate from PDK-defined
41
+ objects to maintain clean project organization.
42
+
43
+ Step-by-Step Process
44
+
45
+ 1. File Organization
46
+
47
+ - DO NOT add custom components to cells.py - this file is reserved for PDK-defined objects
48
+ - CREATE or use custom_components.py in the package directory (e.g., myph18da/custom_components.py)
49
+ - This keeps custom user components separate from the PDK
50
+
51
+ 2. Component Creation
52
+
53
+ \"\"\"Custom user-defined components.\"\"\"
54
+
55
+ import gdsfactory as gf
56
+ from ph18da.cells import <relevant_pdk_functions> # Use PDK functions when available
57
+
58
+ __all__ = ["custom_component_name"]
59
+
60
+ @gf.cell
61
+ def custom_component_name(
62
+ param1: float = default_value,
63
+ param2: float = default_value,
64
+ ) -> gf.Component:
65
+ \"\"\"Component description.
66
+
67
+ Args:
68
+ param1: Description
69
+ param2: Description
70
+
71
+ Returns:
72
+ Component description
73
+ \"\"\"
74
+ # Implementation using PDK functions
75
+ c = pdk_function(parameters...)
76
+ return c
77
+
78
+ 3. Key Implementation Guidelines
79
+
80
+ - Use @gf.cell decorator for all components
81
+ - Prefer using existing PDK functions (e.g., mzi_swg) over internal functions (e.g., _mzi)
82
+ - Import from ph18da.cells for PDK-specific components
83
+ - Use standard PDK component names (e.g., "c_mmi_2x2_swg", "wg_straight_swg", "wg_arc_swg")
84
+ - Keep component parameters clear and well-documented
85
+
86
+ 4. Register the Component
87
+
88
+ Update the package __init__.py to import and expose the custom component:
89
+ from myph18da.custom_components import custom_component_name
90
+
91
+ 5. Build the Component
92
+
93
+ Use the MCP build tool:
94
+ mcp__gdsfactoryplus__build_cell(
95
+ name="custom_component_name",
96
+ project="project-name"
97
+ )
98
+
99
+ 6. Verification
100
+
101
+ - Check build status with get_cell_info
102
+ - Verify GDS file exists in build/gds/ directory
103
+ - Ensure status is "SUCCESS"
104
+
105
+ Troubleshooting
106
+
107
+ If build fails with import errors:
108
+ - Use PDK public functions instead of internal _functions
109
+ - Check that imports are from the correct PDK modules
110
+
111
+ If component not found:
112
+ - Ensure it's imported in __init__.py
113
+ - Rebuild the component after changes
114
+
115
+ If parameter errors occur:
116
+ - Check PDK component compatibility
117
+ - Verify parameter names match PDK expectations
118
+ ---
119
+ """,
120
+ }
121
+
122
+
123
+ def get_all_resources() -> list[Resource]:
124
+ """Get all available MCP resources.
125
+
126
+ Returns:
127
+ List of all resource definitions
128
+ """
129
+ return RESOURCES
130
+
131
+
132
+ def get_resource_content(uri: str) -> str | None:
133
+ """Get resource content by URI.
134
+
135
+ Args:
136
+ uri: Resource URI
137
+
138
+ Returns:
139
+ Resource content string or None if not found
140
+ """
141
+ return RESOURCE_CONTENT.get(uri)
mcp_standalone/server.py CHANGED
@@ -13,11 +13,17 @@ from typing import Any
13
13
 
14
14
  from mcp.server import Server
15
15
  from mcp.server.stdio import stdio_server
16
- from mcp.types import TextContent, Tool
16
+ from mcp.types import (
17
+ Resource,
18
+ TextContent,
19
+ Tool,
20
+ )
17
21
 
18
22
  from .client import FastAPIClient
19
23
  from .config import MCPConfig
20
24
  from .mappings import get_mapping, transform_request, transform_response
25
+ from .registry import get_registry_path
26
+ from .resources import get_all_resources, get_resource_content
21
27
  from .tools import get_all_tools
22
28
 
23
29
  __all__ = ["create_server", "run_server", "main"]
@@ -51,6 +57,41 @@ def create_server(api_url: str | None = None) -> Server:
51
57
  logger.info("Listing %d tools", len(tools))
52
58
  return tools
53
59
 
60
+ @server.list_resources()
61
+ async def list_resources() -> list[Resource]:
62
+ """List all available MCP resources.
63
+
64
+ Returns:
65
+ List of resource definitions
66
+ """
67
+ resources = get_all_resources()
68
+ logger.info("Listing %d resources", len(resources))
69
+ return resources
70
+
71
+ @server.read_resource()
72
+ async def read_resource(uri: str) -> str:
73
+ """Read a specific resource by URI.
74
+
75
+ Args:
76
+ uri: Resource URI
77
+
78
+ Returns:
79
+ Resource content as string
80
+
81
+ Raises:
82
+ ValueError: If resource URI is not found
83
+ """
84
+ logger.info("Resource requested: %s", uri)
85
+
86
+ # Get resource content
87
+ content = get_resource_content(uri)
88
+ if content is None:
89
+ error_msg = f"Unknown resource URI: {uri}"
90
+ logger.error(error_msg)
91
+ raise ValueError(error_msg)
92
+
93
+ return content
94
+
54
95
  @server.call_tool()
55
96
  async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]: # noqa: PLR0911
56
97
  """Call an MCP tool.
@@ -157,6 +198,35 @@ def create_server(api_url: str | None = None) -> Server:
157
198
  return server
158
199
 
159
200
 
201
+ def _log_server_discovery(client: FastAPIClient) -> None:
202
+ """Log discovered GDSFactory+ servers at startup."""
203
+ try:
204
+ projects = client.list_projects()
205
+ if projects:
206
+ logger.info("Discovered %d GDSFactory+ server(s):", len(projects))
207
+ for project in projects[:3]: # Show first 3
208
+ logger.info(
209
+ " - %s (port %d, PDK: %s)",
210
+ project["project_name"],
211
+ project["port"],
212
+ project.get("pdk", "unknown"),
213
+ )
214
+ if len(projects) > 3:
215
+ logger.info(" ... and %d more", len(projects) - 3)
216
+ else:
217
+ logger.warning(
218
+ "No GDSFactory+ servers found. Start a server with: "
219
+ "gfp serve --port 8787"
220
+ )
221
+ logger.info("Registry location: %s", get_registry_path())
222
+ except Exception as e:
223
+ logger.warning("Could not read server registry: %s", e)
224
+ logger.info(
225
+ "If GDSFactory+ is running, ensure registry is accessible at: %s",
226
+ get_registry_path(),
227
+ )
228
+
229
+
160
230
  async def run_server(api_url: str | None = None) -> None:
161
231
  """Run the MCP server with STDIO transport.
162
232
 
@@ -182,12 +252,8 @@ async def run_server(api_url: str | None = None) -> None:
182
252
  # Start HTTP client
183
253
  await client.start()
184
254
 
185
- # Health check
186
- healthy = await client.health_check()
187
- if not healthy:
188
- logger.warning(
189
- "FastAPI server health check failed. Server may not be running."
190
- )
255
+ # Discover available servers
256
+ _log_server_discovery(client)
191
257
 
192
258
  # Run server with STDIO transport
193
259
  async with stdio_server() as (read_stream, write_stream):
mcp_standalone/tools.py CHANGED
@@ -58,7 +58,7 @@ PROJECT_PARAM_SCHEMA = {
58
58
  "type": "string",
59
59
  "description": (
60
60
  "Optional project name or path to route this request to a specific "
61
- "server. If not provided, uses the default server (port 8787). "
61
+ "server. If not provided, routes to the default server. "
62
62
  "Use list_projects to see available projects."
63
63
  ),
64
64
  },
@@ -331,8 +331,170 @@ VERIFICATION_TOOLS: list[Tool] = [
331
331
  # Phase 3: SPICE Workflow Tools (to be implemented)
332
332
  SPICE_TOOLS: list[Tool] = []
333
333
 
334
- # Phase 4: Simulation & Advanced Tools (to be implemented)
335
- ADVANCED_TOOLS: list[Tool] = []
334
+ # Phase 4: Simulation & Advanced Tools
335
+ ADVANCED_TOOLS: list[Tool] = [
336
+ Tool(
337
+ name="simulate_component",
338
+ description=(
339
+ "Run a SAX circuit simulation on a photonic component by name. "
340
+ "This simulates the optical behavior of the component using its "
341
+ "SAX model. Returns S-parameters showing how light propagates "
342
+ "through the component's ports. Use this to analyze component "
343
+ "performance before fabrication."
344
+ ),
345
+ inputSchema=_add_project_param(
346
+ {
347
+ "type": "object",
348
+ "properties": {
349
+ "name": {
350
+ "type": "string",
351
+ "description": (
352
+ "Name of the component/cell to simulate. The component "
353
+ "must have a SAX model defined."
354
+ ),
355
+ },
356
+ },
357
+ "required": ["name"],
358
+ }
359
+ ),
360
+ ),
361
+ Tool(
362
+ name="get_port_center",
363
+ description=(
364
+ "Get the center coordinates (x, y) of a specific port in a component "
365
+ "instance. This is useful for positioning components, routing waveguides, "
366
+ "or analyzing layout geometry. Returns the physical coordinates in "
367
+ "microns."
368
+ ),
369
+ inputSchema=_add_project_param(
370
+ {
371
+ "type": "object",
372
+ "properties": {
373
+ "netlist": {
374
+ "type": "string",
375
+ "description": (
376
+ "Name of the component/netlist containing the instance"
377
+ ),
378
+ },
379
+ "instance": {
380
+ "type": "string",
381
+ "description": "Name of the instance within the netlist",
382
+ },
383
+ "port": {
384
+ "type": "string",
385
+ "description": "Name of the port to get coordinates for",
386
+ },
387
+ },
388
+ "required": ["netlist", "instance", "port"],
389
+ }
390
+ ),
391
+ ),
392
+ Tool(
393
+ name="generate_bbox",
394
+ description=(
395
+ "Generate a bounding box GDS file from an input GDS. This creates "
396
+ "a simplified version of the layout with only a bounding box on "
397
+ "specified layers. Useful for creating abstract views, floorplanning, "
398
+ "or hierarchical design. Can optionally preserve specific layers and "
399
+ "ports."
400
+ ),
401
+ inputSchema=_add_project_param(
402
+ {
403
+ "type": "object",
404
+ "properties": {
405
+ "path": {
406
+ "type": "string",
407
+ "description": (
408
+ "Path to the input GDS file. Can be absolute or relative "
409
+ "to the project directory."
410
+ ),
411
+ },
412
+ "outpath": {
413
+ "type": "string",
414
+ "description": (
415
+ "Output path for the bounding box GDS. If not specified, "
416
+ "uses the input filename with '-bbox' suffix."
417
+ ),
418
+ "default": "",
419
+ },
420
+ "layers_to_keep": {
421
+ "type": "array",
422
+ "items": {"type": "string"},
423
+ "description": (
424
+ "List of layer names to preserve in the output. "
425
+ "Other layers will be replaced by the bounding box."
426
+ ),
427
+ "default": [],
428
+ },
429
+ "bbox_layer": {
430
+ "type": "array",
431
+ "items": {"type": "integer"},
432
+ "description": (
433
+ "Layer (as [layer, datatype]) to use for the bounding box. "
434
+ "Default is [99, 0]."
435
+ ),
436
+ "default": [99, 0],
437
+ },
438
+ "ignore_ports": {
439
+ "type": "boolean",
440
+ "description": (
441
+ "If true, do not include ports in the output. "
442
+ "Default is false."
443
+ ),
444
+ "default": False,
445
+ },
446
+ },
447
+ "required": ["path"],
448
+ }
449
+ ),
450
+ ),
451
+ Tool(
452
+ name="freeze_cell",
453
+ description=(
454
+ "Freeze a parametric Python cell as a static schematic netlist. "
455
+ "This converts a gdsfactory component with specific parameters into "
456
+ "a fixed netlist representation in YAML format. Useful for creating "
457
+ "versioned snapshots of parametric designs or preparing components "
458
+ "for simulation workflows."
459
+ ),
460
+ inputSchema=_add_project_param(
461
+ {
462
+ "type": "object",
463
+ "properties": {
464
+ "cell_name": {
465
+ "type": "string",
466
+ "description": "Name of the cell/component to freeze",
467
+ },
468
+ "kwargs": {
469
+ "type": "object",
470
+ "description": (
471
+ "Optional keyword arguments to pass to the component "
472
+ "factory. Use this to specify parameter values when "
473
+ "freezing the cell. Default is empty (use default params)."
474
+ ),
475
+ "default": {},
476
+ },
477
+ },
478
+ "required": ["cell_name"],
479
+ }
480
+ ),
481
+ ),
482
+ Tool(
483
+ name="get_pdk_info",
484
+ description=(
485
+ "Get information about the current PDK (Process Design Kit) in use. "
486
+ "Returns metadata including PDK name, project name, project path, "
487
+ "server port, and version. Use this to verify which PDK is active "
488
+ "and get project configuration details."
489
+ ),
490
+ inputSchema=_add_project_param(
491
+ {
492
+ "type": "object",
493
+ "properties": {},
494
+ }
495
+ ),
496
+ ),
497
+ ]
336
498
 
337
499
  # All tools (Phase 1 + Project tools)
338
500
  TOOLS: list[Tool] = [
@@ -1,360 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: gfp-mcp
3
- Version: 0.1.0
4
- Summary: Model Context Protocol (MCP) server for GDSFactory+ photonic IC design
5
- Author: GDSFactory+ Team
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/doplaydo/gfp-mcp
8
- Project-URL: Repository, https://github.com/doplaydo/gfp-mcp
9
- Project-URL: Documentation, https://github.com/doplaydo/gfp-mcp#readme
10
- Project-URL: Changelog, https://github.com/doplaydo/gfp-mcp/blob/main/CHANGELOG.md
11
- Project-URL: Issue Tracker, https://github.com/doplaydo/gfp-mcp/issues
12
- Keywords: mcp,gdsfactory,photonics,ic-design,eda,model-context-protocol,photonic-ic,gds
13
- Classifier: Development Status :: 4 - Beta
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: Science/Research
16
- Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
17
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
- Classifier: License :: OSI Approved :: MIT License
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.10
21
- Classifier: Programming Language :: Python :: 3.11
22
- Classifier: Programming Language :: Python :: 3.12
23
- Classifier: Programming Language :: Python :: 3 :: Only
24
- Requires-Python: >=3.10
25
- Description-Content-Type: text/markdown
26
- Requires-Dist: mcp>=1.7.1
27
- Requires-Dist: httpx>=0.25.0
28
- Requires-Dist: typing-extensions>=4.0.0; python_version < "3.11"
29
- Requires-Dist: psutil>=5.9.0
30
- Provides-Extra: dev
31
- Requires-Dist: pytest>=7.0.0; extra == "dev"
32
- Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
- Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
34
- Requires-Dist: ruff>=0.1.0; extra == "dev"
35
-
36
- # GDSFactory+ MCP Server
37
-
38
- [![PyPI version](https://img.shields.io/pypi/v/gfp-mcp.svg)](https://pypi.org/project/gfp-mcp/)
39
- [![Python versions](https://img.shields.io/pypi/pyversions/gfp-mcp.svg)](https://pypi.org/project/gfp-mcp/)
40
- [![Tests](https://github.com/doplaydo/gfp-mcp/workflows/Tests/badge.svg)](https://github.com/doplaydo/gfp-mcp/actions)
41
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
42
-
43
- Model Context Protocol (MCP) server for GDSFactory+ that exposes photonic IC design operations as tools for AI assistants like Claude Code and Claude Desktop.
44
-
45
- ## Overview
46
-
47
- This project implements a standalone MCP server that bridges AI assistants with GDSFactory+ photonic IC design capabilities. The server acts as a lightweight proxy that exposes GDSFactory+ operations through standardized MCP tools while maintaining zero modifications to the existing FastAPI backend.
48
-
49
- ## Features
50
-
51
- ### Phase 1: Core Building Tools (Complete)
52
-
53
- - **build_cell** - Build a single GDS cell by name
54
- - **build_cells** - Build multiple GDS cells in batch
55
- - **list_cells** - List all available photonic components
56
- - **get_cell_info** - Get detailed component metadata
57
- - **download_gds** - Download built GDS files
58
- - **list_projects** - List all running GDSFactory+ server instances
59
- - **get_project_info** - Get detailed information about a specific project
60
-
61
- ### Multi-Project Support
62
-
63
- The MCP server integrates with the GDSFactory+ server registry to support working with multiple projects simultaneously. The registry is stored at `~/.gdsfactory/server-registry.json` and is automatically managed by GDSFactory+ servers.
64
-
65
- #### How It Works
66
-
67
- 1. When you start a GDSFactory+ server with `gfp serve`, it registers itself in the shared registry
68
- 2. The MCP server reads from this registry to discover available projects
69
- 3. Tools accept an optional `project` parameter to route requests to specific servers
70
- 4. The MCP server automatically resolves project names to the correct port
71
-
72
- #### Example Usage
73
-
74
- ```
75
- User: "List all running GDSFactory+ projects"
76
- Claude: [Uses list_projects tool to show all registered servers]
77
-
78
- User: "Build the mzi component in the my_photonics_project"
79
- Claude: [Uses build_cell tool with project="my_photonics_project"]
80
- ```
81
-
82
- **Note**: The MCP has read-only access to the registry. Only GDSFactory+ servers can register/unregister themselves.
83
-
84
- ### Architecture
85
-
86
- ```
87
- AI Assistant (Claude) <-> MCP Server (STDIO) <-> HTTP Client <-> FastAPI Server
88
- ```
89
-
90
- **Key Benefits:**
91
- - Universal MCP client compatibility via STDIO transport
92
- - Zero modifications to existing FastAPI server
93
- - Clean separation of concerns
94
- - No database conflicts (only FastAPI touches SQLite)
95
- - Scalable architecture ready for 20+ tools
96
-
97
- ## Installation
98
-
99
- ### From PyPI (Recommended)
100
-
101
- Install the package from PyPI:
102
-
103
- ```bash
104
- pip install gfp-mcp
105
- ```
106
-
107
- Or with uv:
108
-
109
- ```bash
110
- uv pip install gfp-mcp
111
- ```
112
-
113
- ### From Source (Development)
114
-
115
- For development or if you want the latest unreleased changes:
116
-
117
- ```bash
118
- git clone https://github.com/doplaydo/gfp-mcp.git
119
- cd gfp-mcp
120
- pip install -e ".[dev]"
121
- ```
122
-
123
- ### Prerequisites
124
-
125
- - Python 3.10 or higher
126
- - GDSFactory+ with FastAPI server running
127
-
128
- ### Verify Installation
129
-
130
- ```bash
131
- gfp-mcp-serve --help
132
- ```
133
-
134
- ## Quick Start
135
-
136
- ### 1. Start the FastAPI Server
137
-
138
- In one terminal:
139
-
140
- ```bash
141
- gfp serve --port 8787
142
- ```
143
-
144
- ### 2. Configure Your AI Assistant
145
-
146
- #### Claude Code
147
-
148
- Add to `.claude/settings.json`:
149
-
150
- ```json
151
- {
152
- "mcpServers": {
153
- "gdsfactoryplus": {
154
- "command": "gfp-mcp-serve",
155
- "args": [],
156
- "env": {
157
- "GFP_API_URL": "http://localhost:8787"
158
- }
159
- }
160
- }
161
- }
162
- ```
163
-
164
- Or use the command line:
165
-
166
- ```bash
167
- claude mcp add gdsfactoryplus -- gfp-mcp-serve
168
- ```
169
-
170
- #### Claude Desktop
171
-
172
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
173
-
174
- ```json
175
- {
176
- "mcpServers": {
177
- "gdsfactoryplus": {
178
- "command": "gfp-mcp-serve",
179
- "args": []
180
- }
181
- }
182
- }
183
- ```
184
-
185
- For Windows: `%APPDATA%\Claude\claude_desktop_config.json`
186
-
187
- For Linux: `~/.config/Claude/claude_desktop_config.json`
188
-
189
- ### 3. Use the Tools
190
-
191
- Ask your AI assistant to:
192
-
193
- - "List all available photonic components"
194
- - "Build the mzi component"
195
- - "Show me details about the coupler component"
196
- - "Build multiple components: mzi, coupler, and bend_euler"
197
-
198
- ## Environment Variables
199
-
200
- Configure the MCP server using environment variables:
201
-
202
- ```bash
203
- # FastAPI server URL (default: http://localhost:8787)
204
- export GFP_API_URL="http://localhost:8787"
205
-
206
- # Request timeout in seconds (default: 300)
207
- export GFP_MCP_TIMEOUT=300
208
-
209
- # Enable debug logging (default: false)
210
- export GFP_MCP_DEBUG=true
211
- ```
212
-
213
- ## Project Structure
214
-
215
- ```
216
- gfp-mcp/
217
- ├── mcp_standalone/ # MCP server implementation
218
- │ ├── __init__.py # Package exports
219
- │ ├── config.py # Configuration management
220
- │ ├── client.py # HTTP client for FastAPI
221
- │ ├── registry.py # Server registry (multi-project support)
222
- │ ├── tools.py # MCP tool definitions
223
- │ ├── mappings.py # Tool → Endpoint mappings
224
- │ ├── server.py # MCP server core
225
- │ └── README.md # Detailed documentation
226
- ├── tests/ # Test suite
227
- │ ├── test_mcp_tools.py
228
- │ ├── test_mcp_mappings.py
229
- │ ├── test_mcp_integration.py
230
- │ └── test_registry.py
231
- ├── mcp_serve.py # CLI entry point
232
- ├── MCP_QUICKSTART.md # Quick start guide
233
- ├── MCP_IMPLEMENTATION_STATUS.md # Implementation details
234
- └── README.md # This file
235
- ```
236
-
237
- ## Testing
238
-
239
- Run the test suite:
240
-
241
- ```bash
242
- # Run all MCP tests
243
- pytest tests/test_mcp_*.py -v
244
-
245
- # Run with coverage
246
- pytest tests/test_mcp_*.py --cov=mcp_standalone --cov-report=term-missing
247
-
248
- # Run specific test file
249
- pytest tests/test_mcp_tools.py -v
250
- ```
251
-
252
- All tests are passing (46/46 tests):
253
- - Tool definitions: 15 tests
254
- - Endpoint mappings: 13 tests
255
- - Integration & client: 9 tests
256
- - Registry integration: 9 tests
257
-
258
- ## Example Workflows
259
-
260
- ### Build and Verify a Component
261
-
262
- ```
263
- User: "List all available photonic components"
264
- Claude: [Uses list_cells tool]
265
-
266
- User: "Build the mzi component"
267
- Claude: [Uses build_cell tool with name="mzi"]
268
-
269
- User: "Show me the details of the mzi component"
270
- Claude: [Uses get_cell_info tool with name="mzi"]
271
- ```
272
-
273
- ### Batch Build Multiple Components
274
-
275
- ```
276
- User: "Build the following components: mzi, coupler, and bend_euler"
277
- Claude: [Uses build_cells tool with names=["mzi", "coupler", "bend_euler"]]
278
- ```
279
-
280
- ## Troubleshooting
281
-
282
- ### Error: "Connection refused to localhost:8787"
283
-
284
- **Cause**: FastAPI server is not running
285
-
286
- **Solution**: Start the FastAPI server:
287
-
288
- ```bash
289
- gfp serve --port 8787
290
- ```
291
-
292
- ### Error: "MCP server not responding"
293
-
294
- **Cause**: STDIO transport issue or MCP client misconfiguration
295
-
296
- **Solution**:
297
- 1. Check Claude Code/Desktop logs with `claude --debug`
298
- 2. Restart the MCP server
299
- 3. Verify the configuration in settings.json
300
-
301
- ### Error: "Tool execution timeout"
302
-
303
- **Cause**: Long-running operation exceeded timeout
304
-
305
- **Solution**: Increase the timeout:
306
-
307
- ```bash
308
- export GFP_MCP_TIMEOUT=600 # 10 minutes
309
- gfp mcp-serve
310
- ```
311
-
312
- ## Roadmap
313
-
314
- ### Future Phases
315
-
316
- - **Phase 2**: Verification tools (DRC, LVS)
317
- - **Phase 3**: SPICE workflow tools
318
- - **Phase 4**: Simulation & advanced tools
319
- - **Phase 5**: Comprehensive testing & documentation
320
-
321
- ## Documentation
322
-
323
- - [Quick Start Guide](MCP_QUICKSTART.md) - Step-by-step setup instructions
324
- - [Implementation Status](MCP_IMPLEMENTATION_STATUS.md) - Detailed implementation notes
325
- - [MCP Standalone README](mcp_standalone/README.md) - Architecture details
326
- - [Contributing Guide](CONTRIBUTING.md) - Development and release guidelines
327
- - [Changelog](CHANGELOG.md) - Version history and release notes
328
-
329
- ## Contributing
330
-
331
- Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:
332
-
333
- - Development setup
334
- - Running tests and code quality checks
335
- - Making changes and submitting PRs
336
- - Release process (for maintainers)
337
-
338
- Quick checklist:
339
-
340
- 1. All tests pass: `pytest tests/test_mcp_*.py -v`
341
- 2. Code quality: `ruff check . && ruff format --check .`
342
- 3. Documentation is updated
343
- 4. Changes are backward compatible
344
-
345
- ## License
346
-
347
- See the main GDSFactory+ project for license information.
348
-
349
- ## Support
350
-
351
- For issues or questions:
352
-
353
- 1. Check the [Quick Start Guide](MCP_QUICKSTART.md) troubleshooting section
354
- 2. Review the [Implementation Status](MCP_IMPLEMENTATION_STATUS.md) document
355
- 3. Enable debug mode with `GFP_MCP_DEBUG=true` and check server logs
356
- 4. Open an issue on GitHub
357
-
358
- ## Acknowledgments
359
-
360
- Built on the Model Context Protocol by Anthropic, enabling seamless AI assistant integration with photonic IC design workflows.
@@ -1,12 +0,0 @@
1
- mcp_standalone/__init__.py,sha256=7PhYozHyiRK_oFui0RkF5GJWxA2OZoWVcU_-ESfHIR4,953
2
- mcp_standalone/client.py,sha256=gUs9m2M27OP-GYmJ9fkojyxv212ETVJFqp0v2uN8Q2c,8205
3
- mcp_standalone/config.py,sha256=zr2LnI_wNEcMWrnB_WLscR-skkXjE33ZPBtK08XjaX0,1386
4
- mcp_standalone/mappings.py,sha256=jXEHwSrSYNDuVeMRM2dsSUsr38CzrHBLoe6exkJhqvc,7695
5
- mcp_standalone/registry.py,sha256=1E61UalVot8HUS3cALjM7ejYB0qR6tI5QbQSZZeQe7Y,6401
6
- mcp_standalone/server.py,sha256=Celd9j0KY1Fl_Qw09b9Px03vGhtaTUac2ozlYdGJ23A,7100
7
- mcp_standalone/tools.py,sha256=__j9N396-cJj9CKi6EAdP5_J-xESrbRZG35KNzdszXM,12349
8
- gfp_mcp-0.1.0.dist-info/METADATA,sha256=dVk1r3JfmlEY3RcqVSDqMLYm2fPAqwYjM4cTUD6sVQE,10442
9
- gfp_mcp-0.1.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
10
- gfp_mcp-0.1.0.dist-info/entry_points.txt,sha256=mgyus9dsB_8mjgnztuHNPqzPi-7HcPg1iYzfM5NMIjk,61
11
- gfp_mcp-0.1.0.dist-info/top_level.txt,sha256=g2hRJHoDDPNtrNdXR70T7FR9Ev6DTRJiGW7ZvlvnXMc,15
12
- gfp_mcp-0.1.0.dist-info/RECORD,,