Skip to main content
Glama

propublica-mcp

cursor.py•5.55 kB
"""Cursor integration for FastMCP install using Cyclopts.""" import base64 import subprocess import sys from pathlib import Path from typing import Annotated import cyclopts from rich import print from fastmcp.mcp_config import StdioMCPServer from fastmcp.utilities.logging import get_logger from .shared import process_common_args logger = get_logger(__name__) def generate_cursor_deeplink( server_name: str, server_config: StdioMCPServer, ) -> str: """Generate a Cursor deeplink for installing the MCP server. Args: server_name: Name of the server server_config: Server configuration Returns: Deeplink URL that can be clicked to install the server """ # Create the configuration structure expected by Cursor # Base64 encode the configuration (URL-safe for query parameter) config_json = server_config.model_dump_json(exclude_none=True) config_b64 = base64.urlsafe_b64encode(config_json.encode()).decode() # Generate the deeplink URL deeplink = f"cursor://anysphere.cursor-deeplink/mcp/install?name={server_name}&config={config_b64}" return deeplink def open_deeplink(deeplink: str) -> bool: """Attempt to open a deeplink URL using the system's default handler. Args: deeplink: The deeplink URL to open Returns: True if the command succeeded, False otherwise """ try: if sys.platform == "darwin": # macOS subprocess.run(["open", deeplink], check=True, capture_output=True) elif sys.platform == "win32": # Windows subprocess.run( ["start", deeplink], shell=True, check=True, capture_output=True ) else: # Linux and others subprocess.run(["xdg-open", deeplink], check=True, capture_output=True) return True except (subprocess.CalledProcessError, FileNotFoundError): return False def install_cursor( file: Path, server_object: str | None, name: str, *, with_editable: Path | None = None, with_packages: list[str] | None = None, env_vars: dict[str, str] | None = None, ) -> bool: """Install FastMCP server in Cursor. Args: file: Path to the server file server_object: Optional server object name (for :object suffix) name: Name for the server in Cursor with_editable: Optional directory to install in editable mode with_packages: Optional list of additional packages to install env_vars: Optional dictionary of environment variables Returns: True if installation was successful, False otherwise """ # Build uv run command args = ["run"] # Collect all packages in a set to deduplicate packages = {"fastmcp"} if with_packages: packages.update(pkg for pkg in with_packages if pkg) # Add all packages with --with for pkg in sorted(packages): args.extend(["--with", pkg]) if with_editable: args.extend(["--with-editable", str(with_editable)]) # Build server spec from parsed components if server_object: server_spec = f"{file.resolve()}:{server_object}" else: server_spec = str(file.resolve()) # Add fastmcp run command args.extend(["fastmcp", "run", server_spec]) # Create server configuration server_config = StdioMCPServer( command="uv", args=args, env=env_vars or {}, ) # Generate deeplink deeplink = generate_cursor_deeplink(name, server_config) print(f"[blue]Opening Cursor to install '{name}'[/blue]") if open_deeplink(deeplink): print("[green]Cursor should now open with the installation dialog[/green]") return True else: print( "[red]Could not open Cursor automatically.[/red]\n" f"[blue]Please copy this link and open it in Cursor: {deeplink}[/blue]" ) return False def cursor_command( server_spec: str, *, server_name: Annotated[ str | None, cyclopts.Parameter( name=["--server-name", "-n"], help="Custom name for the server in Cursor", ), ] = None, with_editable: Annotated[ Path | None, cyclopts.Parameter( name=["--with-editable", "-e"], help="Directory with pyproject.toml to install in editable mode", ), ] = None, with_packages: Annotated[ list[str], cyclopts.Parameter( "--with", help="Additional packages to install", negative=False, ), ] = [], env_vars: Annotated[ list[str], cyclopts.Parameter( "--env", help="Environment variables in KEY=VALUE format", negative=False, ), ] = [], env_file: Annotated[ Path | None, cyclopts.Parameter( "--env-file", help="Load environment variables from .env file", ), ] = None, ) -> None: """Install an MCP server in Cursor. Args: server_spec: Python file to install, optionally with :object suffix """ file, server_object, name, with_packages, env_dict = process_common_args( server_spec, server_name, with_packages, env_vars, env_file ) success = install_cursor( file=file, server_object=server_object, name=name, with_editable=with_editable, with_packages=with_packages, env_vars=env_dict, ) if not success: sys.exit(1)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/asachs01/propublica-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server