11"""
2- Cursor client configuration for MCP
2+ Cursor integration utilities for MCP
33"""
44
55import os
66import logging
7- from typing import Dict , Any
7+ import platform
8+ from typing import Dict , Any , Optional , List
89
910from mcpm .clients .base import BaseClientManager
1011from mcpm .utils .server_config import ServerConfig
1112
12- # Cursor stores MCP configuration in:
13- # - Project config: .cursor/mcp.json in the project directory
14- # - Global config: ~/.cursor/mcp.json in the home directory
15-
16- # Global config path for Cursor
17- HOME_DIR = os .path .expanduser ("~" )
18- CURSOR_CONFIG_PATH = os .path .join (HOME_DIR , ".cursor" , "mcp.json" )
19-
2013logger = logging .getLogger (__name__ )
2114
22- # Get the project config path for Cursor
23- def get_project_config_path (project_dir : str ) -> str :
24- """
25- Get the project-specific MCP configuration path for Cursor
26-
27- Args:
28- project_dir (str): Project directory path
29-
30- Returns:
31- str: Path to the project-specific MCP configuration file
32- """
33- return os .path .join (project_dir , ".cursor" , "mcp.json" )
34-
15+ # Cursor config paths based on platform
16+ if platform .system () == "Darwin" : # macOS
17+ CURSOR_CONFIG_PATH = os .path .expanduser ("~/Library/Application Support/Cursor/User/mcp_config.json" )
18+ elif platform .system () == "Windows" :
19+ CURSOR_CONFIG_PATH = os .path .join (os .environ .get ("APPDATA" , "" ), "Cursor" , "User" , "mcp_config.json" )
20+ else :
21+ # Linux
22+ CURSOR_CONFIG_PATH = os .path .expanduser ("~/.config/Cursor/User/mcp_config.json" )
3523
3624class CursorManager (BaseClientManager ):
37- """Manages Cursor client configuration for MCP """
25+ """Manages Cursor MCP server configurations """
3826
3927 def __init__ (self , config_path : str = CURSOR_CONFIG_PATH ):
4028 super ().__init__ (config_path )
@@ -86,12 +74,60 @@ def _convert_to_client_format(self, server_config: ServerConfig) -> Dict[str, An
8674 """Convert ServerConfig to Cursor format
8775
8876 Args:
89- server_config: StandardServer configuration
77+ server_config: ServerConfig object
9078
9179 Returns:
9280 Dict containing Cursor-specific configuration
9381 """
94- return server_config .to_cursor_format ()
82+ # Base result containing essential execution information
83+ result = {
84+ "command" : server_config .command ,
85+ "args" : server_config .args ,
86+ }
87+
88+ # Add filtered environment variables if present
89+ non_empty_env = server_config .get_filtered_env_vars ()
90+ if non_empty_env :
91+ result ["env" ] = non_empty_env
92+
93+ # Add additional metadata fields for display in Cursor
94+ # Fields that are None will be automatically excluded by JSON serialization
95+ for field in ["name" , "display_name" , "description" , "version" , "status" , "path" , "install_date" ]:
96+ value = getattr (server_config , field , None )
97+ if value is not None :
98+ result [field ] = value
99+
100+ return result
101+
102+ @classmethod
103+ def from_cursor_format (cls , server_name : str , client_config : Dict [str , Any ]) -> ServerConfig :
104+ """Convert Cursor format to ServerConfig
105+
106+ Args:
107+ server_name: Name of the server
108+ client_config: Cursor-specific configuration
109+
110+ Returns:
111+ ServerConfig object
112+ """
113+ # Create a dictionary that ServerConfig.from_dict can work with
114+ server_data = {
115+ "name" : server_name ,
116+ "command" : client_config .get ("command" , "" ),
117+ "args" : client_config .get ("args" , []),
118+ }
119+
120+ # Add environment variables if present
121+ if "env" in client_config :
122+ server_data ["env_vars" ] = client_config ["env" ]
123+
124+ # Add additional metadata fields if present
125+ for field in ["display_name" , "description" , "version" , "status" , "path" , "install_date" ,
126+ "package" , "installation_method" , "installation_type" ]:
127+ if field in client_config :
128+ server_data [field ] = client_config [field ]
129+
130+ return ServerConfig .from_dict (server_data )
95131
96132 def _convert_from_client_format (self , server_name : str , client_config : Dict [str , Any ]) -> ServerConfig :
97133 """Convert Cursor format to ServerConfig
@@ -103,7 +139,7 @@ def _convert_from_client_format(self, server_name: str, client_config: Dict[str,
103139 Returns:
104140 ServerConfig object
105141 """
106- return ServerConfig .from_cursor_format (server_name , client_config )
142+ return self .from_cursor_format (server_name , client_config )
107143
108144 def remove_server (self , server_name : str ) -> bool :
109145 """Remove an MCP server from Cursor config
@@ -116,15 +152,56 @@ def remove_server(self, server_name: str) -> bool:
116152 """
117153 config = self ._load_config ()
118154
119- if "mcpServers" not in config or server_name not in config ["mcpServers" ]:
120- logger .warning (f"Server not found in Cursor config: { server_name } " )
155+ # Check if mcpServers exists
156+ if "mcpServers" not in config :
157+ logger .warning (f"Cannot remove server { server_name } : mcpServers section doesn't exist" )
158+ return False
159+
160+ # Check if the server exists
161+ if server_name not in config ["mcpServers" ]:
162+ logger .warning (f"Server { server_name } not found in Cursor config" )
121163 return False
122164
123165 # Remove the server
124166 del config ["mcpServers" ][server_name ]
125167
126168 return self ._save_config (config )
127169
128- def is_cursor_installed (self ) -> bool :
129- """Check if Cursor is installed"""
130- return self .is_client_installed ()
170+ def get_server (self , server_name : str ) -> Optional [ServerConfig ]:
171+ """Get a server configuration from Cursor
172+
173+ Args:
174+ server_name: Name of the server
175+
176+ Returns:
177+ ServerConfig object if found, None otherwise
178+ """
179+ config = self ._load_config ()
180+
181+ # Check if mcpServers exists
182+ if "mcpServers" not in config :
183+ logger .warning (f"Cannot get server { server_name } : mcpServers section doesn't exist" )
184+ return None
185+
186+ # Check if the server exists
187+ if server_name not in config ["mcpServers" ]:
188+ logger .debug (f"Server { server_name } not found in Cursor config" )
189+ return None
190+
191+ # Get the server config and convert to StandardServer
192+ client_config = config ["mcpServers" ][server_name ]
193+ return self ._convert_from_client_format (server_name , client_config )
194+
195+ def list_servers (self ) -> List [str ]:
196+ """List all MCP servers in Cursor config
197+
198+ Returns:
199+ List of server names
200+ """
201+ config = self ._load_config ()
202+
203+ # Check if mcpServers exists
204+ if "mcpServers" not in config :
205+ return []
206+
207+ return list (config ["mcpServers" ].keys ())
0 commit comments