### Start Background Browser Setup Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Asynchronously starts the browser setup process in the background. This is non-blocking and downloads Chromium and creates a browser context if it's the first run. ```python async def start_background_browser_setup_if_needed() -> None: """Start Patchright download and browser creation in background.""" ``` -------------------------------- ### Development Setup Commands Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CONTRIBUTING.md Commands to clone the repository, install dependencies, set up pre-commit hooks, install a browser, and run tests. ```bash git clone https://github.com/stickerdaniel/linkedin-mcp-server cd linkedin-mcp-server uv sync # Install dependencies uv sync --group dev # Install dev dependencies uv run pre-commit install # Set up pre-commit hooks uv run patchright install chromium # Install browser uv run pytest --cov # Run tests with coverage ``` -------------------------------- ### Install Chromium Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Use this command to install Chromium if the browser fails to start. Ensure you have sufficient disk space. ```bash uv run patchright install chromium ``` -------------------------------- ### start_background_browser_setup_if_needed Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Starts the browser setup process asynchronously in the background. This is a non-blocking operation that handles downloading Chromium and creating the browser context on the first run, without waiting for completion. ```APIDOC ## start_background_browser_setup_if_needed ### Description Starts the browser setup process asynchronously in the background. This operation is non-blocking and handles downloading Chromium and creating the browser context on the first run. It does not wait for the setup to complete. ### Signature ```python async def start_background_browser_setup_if_needed() -> None: """Start Patchright download and browser creation in background.""" ``` ### Parameters None ### Request Example ```python import asyncio asyncio.run(start_background_browser_setup_if_needed()) ``` ### Response #### Success Response (200) None ``` -------------------------------- ### Browser Lifespan Management Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md The `browser_lifespan` context manager handles browser setup during server startup and cleanup during shutdown. It initializes the bootstrap process, starts background browser setup if needed, and ensures the browser is closed and resources are released upon server termination. ```python initialize_bootstrap(get_runtime_policy()) await start_background_browser_setup_if_needed() # ... server logic ... await close_browser() ``` -------------------------------- ### Clone Repository and Install Dependencies Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Clone the repository, install the uv package manager, and synchronize development dependencies. ```bash # 1. Clone repository git clone https://github.com/stickerdaniel/linkedin-mcp-server cd linkedin-mcp-server # 2. Install UV package manager (if not already installed) curl -LsSf https://astral.sh/uv/install.sh | sh # 3. Install dependencies uv sync uv sync --group dev # 4. Install pre-commit hooks uv run pre-commit install ``` -------------------------------- ### Copy Example .env File Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Command to copy the example environment variable file (.env.example) to a new .env file, which can then be customized. ```bash cp .env.example .env ``` -------------------------------- ### Install Dev Dependencies Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/00-index.md Installs development dependencies using uv sync with the 'dev' group. Ensure uv is installed and configured. ```bash # Install dev dependencies uv sync --group dev ``` -------------------------------- ### Register Custom Tools with FastMCP Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Define and register a new tool with the FastMCP server. This example registers a 'Get Recommendations' tool with a specified timeout and tags, utilizing a custom extractor. ```python from fastmcp import FastMCP def register_custom_tools(mcp: FastMCP): @mcp.tool( timeout=180, title="Get Recommendations", tags={"person", "scraping"}, ) async def get_recommendations( username: str, ctx, extractor=None, ): """Get recommendations for a person.""" extractor = extractor or await get_ready_extractor(ctx) return await extractor.scrape_recommendations(username) ``` -------------------------------- ### Get or Create Browser Instance Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Obtains the singleton BrowserManager instance, creating it on the first call. Subsequent calls return the cached instance. Browser setup occurs in the background. ```python from linkedin_mcp_server.drivers.browser import get_or_create_browser browser = await get_or_create_browser() await browser.page.goto("https://www.linkedin.com/feed/") ``` -------------------------------- ### Start the LinkedIn MCP Server Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Start the local server using uv. The server prepares the browser cache and opens LinkedIn login on the first auth-requiring tool call. ```bash # 5. Start the server uv run -m linkedin_mcp_server ``` -------------------------------- ### Environment Variable Examples Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Examples of setting various environment variables to configure the server's behavior, such as logging level, port, timeouts, and browser path. These can be set directly in the shell. ```bash # Set logging to debug export LOG_LEVEL=DEBUG # Set HTTP server to port 8080 export PORT=8080 # Increase browser timeout export TIMEOUT=10000 # Use custom Chrome export CHROME_PATH=/usr/bin/chromium-browser # Disable headless (show window) export HEADLESS=0 # Set viewport export VIEWPORT=1920x1080 # Run server uv run -m linkedin_mcp_server ``` -------------------------------- ### Start LinkedIn MCP Server Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Run the server using uv or a package script. This is the main entry point for the server. ```bash uv run -m linkedin_mcp_server ``` ```bash mcp-server-linkedin ``` -------------------------------- ### Usage Example for get_ready_extractor Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Demonstrates how to obtain a ready LinkedInExtractor and use it to scrape person data. Ensure the 'linkedin_mcp_server.dependencies' module is imported. ```python from linkedin_mcp_server.dependencies import get_ready_extractor extractor = await get_ready_extractor(ctx, tool_name="get_person_profile") result = await extractor.scrape_person("williamhgates", {"main_profile"}) ``` -------------------------------- ### Configure Logging for MCP Server Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Set up the logging level and format for the LinkedIn MCP Server. This example configures DEBUG level logging with a non-JSON format and demonstrates how to get and use a logger. ```python import logging # Configure logging from linkedin_mcp_server.logging_config import configure_logging configure_logging( log_level="DEBUG", json_format=False ) # Get logger logger = logging.getLogger("linkedin_mcp_server.scraping") logger.debug("Detailed debugging info") ``` -------------------------------- ### Start LinkedIn MCP Server Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CLAUDE.md Starts the MCP server with streamable-http transport and DEBUG log level. Ensure a valid login profile exists at ~/.linkedin-mcp/profile/. ```bash # Start server uv run -m linkedin_mcp_server --transport streamable-http --log-level DEBUG ``` -------------------------------- ### Docker Volume Mounts for Persistence Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Example of mounting a local directory to the container's profile directory for session persistence across restarts. This ensures user data is not lost when the container is stopped and started. ```bash docker run \ -v ~/.linkedin-mcp:/home/pwuser/.linkedin-mcp \ stickerdaniel/linkedin-mcp-server:latest ``` -------------------------------- ### Logging Examples Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Demonstrates how to log messages at different levels using a named logger. This is useful for tracking application behavior and debugging. ```python logger = logging.getLogger(__name__) logger.debug("Debug message") logger.info("Info message") logger.warning("Warning message") logger.error("Error message") ``` -------------------------------- ### Run Server with Saved Session Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Starts the server using a previously saved session profile. This command assumes a successful login has already occurred. ```bash uv run -m linkedin_mcp_server ``` -------------------------------- ### Main Server Startup Function Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md This asynchronous function orchestrates the server startup process. It handles configuration, logging, CLI special modes, browser setup, and server execution using either stdio or HTTP transport. ```python async def main() -> None: config = get_config() configure_logging( log_level=config.server.log_level, json_format=not config.is_interactive, ) version = get_version() logger.info(f"LinkedIn MCP Server v{version}") # Handle CLI special modes if config.server.login: await get_profile_and_exit() if config.server.logout: clear_profile_and_exit() if config.server.status: await check_status_and_exit() # Set up browser ensure_browser_installed() configure_browser_environment() set_headless(config.browser.headless) # Create and run server mcp = create_mcp_server(tool_timeout=config.server.tool_timeout_seconds) if config.server.transport == "stdio": mcp.run(transport="stdio") else: await mcp.run_async( transport="streamable-http", host=config.server.host, port=config.server.port, path=config.server.path, ) ``` -------------------------------- ### Start New Login Session Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Initiate an interactive login session by running the server with the --login flag. Subsequent runs will reuse the created session. ```bash # Create session interactively uv run -m linkedin_mcp_server --login # Run server with that profile uv run -m linkedin_mcp_server ``` -------------------------------- ### Get LinkedIn MCP Server Package Version Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Import and print the package version using the __version__ attribute. This is useful for verifying the installed version. ```python from linkedin_mcp_server import __version__ print(f"Version: {__version__}") ``` -------------------------------- ### Extractor Logic Example Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CONTRIBUTING.md Python code snippet demonstrating how the extractor iterates through section configurations to determine which sections to process. ```python for section_name, (suffix, is_overlay) in PERSON_SECTIONS.items(): if section_name not in requested: continue # navigate and extract... ``` -------------------------------- ### Starting MCP Inspector Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Launch the MCP Inspector tool in a separate terminal to test the running MCP server. Access the inspector in your browser. ```bash # Terminal 2: Start inspector bunx @modelcontextprotocol/inspector # Browser: Inspector at http://localhost:5000 # Select "Streamable HTTP" # URL: http://localhost:8080/mcp # Connect and test tools ``` -------------------------------- ### Usage Example for MCPContextProgressCallback Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Demonstrates how to instantiate and use `MCPContextProgressCallback` with an extractor to report progress during a scraping operation. Ensure the callback is passed to the scraping method. ```python from linkedin_mcp_server.callbacks import MCPContextProgressCallback cb = MCPContextProgressCallback(ctx) result = await extractor.scrape_person( "williamhgates", {"main_profile", "experience"}, callbacks=cb, ) ``` -------------------------------- ### Run Local Server (No Headless, Debug) Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/00-index.md Starts the LinkedIn MCP server locally without a headless browser and with debug logging enabled. Useful for detailed troubleshooting. ```bash uv run -m linkedin_mcp_server --no-headless --log-level DEBUG ``` -------------------------------- ### get_or_create_browser Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Obtains the singleton browser instance. If no browser instance exists, it creates a new one. Subsequent calls return the cached instance. Browser setup is performed in the background. ```APIDOC ## get_or_create_browser ### Description Get the singleton browser instance or create new one. Subsequent calls return the cached instance. Browser setup happens in background. ### Signature ```python async def get_or_create_browser() -> BrowserManager: """Return singleton BrowserManager, creating if needed.""" ``` ### Usage ```python from linkedin_mcp_server.drivers.browser import get_or_create_browser browser = await get_or_create_browser() await browser.page.goto("https://www.linkedin.com/feed/") ``` ``` -------------------------------- ### Synthetic Prompt Example Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CLAUDE.md Example of a synthetic prompt to reproduce a PR diff for Claude Code. This distills the conversation into a single instruction. ```markdown ## Synthetic prompt > Add `skills` and `projects` sections to `get_person_profile`, following the certifications PR pattern. Update fields, tests, docs, and manifest. Generated with ``` -------------------------------- ### Starting LinkedIn MCP Server for MCP Inspector Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Start the LinkedIn MCP Server in HTTP mode on port 8080 for testing with MCP Inspector. This command is executed in the first terminal. ```bash # Terminal 1: Start server in HTTP mode uv run -m linkedin_mcp_server --transport streamable-http --port 8080 ``` -------------------------------- ### Simulate Internal Tool Exception Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md An example of an internal tool raising a ValueError, which will be masked by FastMCP. ```python raise ValueError("Internal database issue") ``` -------------------------------- ### Get Application Configuration Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Retrieves the singleton AppConfig instance. Use this to access application settings like browser and tool timeouts. ```python from linkedin_mcp_server.config import get_config config = get_config() browser_timeout = config.browser.default_timeout tool_timeout = config.server.tool_timeout_seconds ``` -------------------------------- ### browser_lifespan Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Lifespan context manager for browser setup and teardown, handling initialization and cleanup of browser resources. ```APIDOC ## browser_lifespan ### Description Lifespan context manager for browser setup and teardown. Manages browser lifecycle, including initialization on startup and cleanup on shutdown. ### Method Lifespan context manager ### Parameters None ### Lifecycle Events - **Startup**: Initialize bootstrap, start background browser setup. - **Shutdown**: Close browser, clean up resources. ### Bootstrap Initialization ```python initialize_bootstrap(get_runtime_policy()) await start_background_browser_setup_if_needed() ``` This process determines the runtime environment, starts Chromium download in the background, loads session state if available, and does not block on browser creation. ### Cleanup ```python await close_browser() ``` This closes the browser and releases all associated resources. ``` -------------------------------- ### Run Interactive Profile Creation Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Initiates an interactive flow for creating a user profile, which includes logging into LinkedIn. This function is part of the setup process. ```python async def run_profile_creation( user_data_dir: Path, headless: bool = False, ) -> bool: """ Run interactive LinkedIn login. Returns: True if successful, False if cancelled/failed """ ``` -------------------------------- ### Example HTTP Request using curl Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Demonstrates how to make a POST request to the MCP HTTP endpoint using curl to call the 'get_person_profile' tool. Includes setting the session ID and request payload. ```bash curl -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -H "Mcp-Session-Id: " \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_person_profile", "arguments": { "linkedin_username": "williamhgates", "sections": "experience" } } }' ``` -------------------------------- ### Conditional Server Action Based on Status Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md An example script that checks the server status and either proceeds if logged in or initiates a login process if not. ```bash if uv run -m linkedin_mcp_server --status; then echo "Ready to use" else echo "Need to login first" uv run -m linkedin_mcp_server --login fi ``` -------------------------------- ### Docker Environment Variables Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Example of how to set environment variables for the LinkedIn MCP server when running in Docker, such as LOG_LEVEL and TOOL_TIMEOUT. ```bash docker run -e LOG_LEVEL=DEBUG -e TOOL_TIMEOUT=300 ... ``` -------------------------------- ### Run Local Server (Login Mode) Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/00-index.md Starts the LinkedIn MCP server locally in login mode. This is typically used for development and testing authentication flows. ```bash # Run locally uv run -m linkedin_mcp_server --login ``` -------------------------------- ### Get Runtime Profile Directory Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Calculates and returns the runtime-specific profile directory path based on the provided profile directory. ```python def runtime_profile_dir(profile_dir: Path) -> Path: """Return derived runtime profile path.""" ``` -------------------------------- ### Source Code References Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/README.md Examples of source code file paths provided for reference. These paths indicate the location of specific functions, classes, or modules within the project. ```text linkedin_mcp_server/tools/person.py:38-102 linkedin_mcp_server/config/schema.py:24-59 linkedin_mcp_server/core/exceptions.py:10-13 ``` -------------------------------- ### Claude Desktop Configuration with uvx Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Use this configuration for Claude Desktop to automatically run the latest version of the LinkedIn MCP Server with auto-updates. Ensure uvx is installed. ```json { "mcpServers": { "linkedin": { "command": "uvx", "args": ["mcp-server-linkedin@latest"], "env": { "UV_HTTP_TIMEOUT": "300" } } } } ``` -------------------------------- ### Get or Create Browser Instance Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Manages the lifecycle of a Patchright browser instance. This function ensures a singleton BrowserManager instance is used. ```python from linkedin_mcp_server.drivers.browser import get_or_create_browser browser = await get_or_create_browser() page = browser.page title = await page.title() ``` -------------------------------- ### Run LinkedIn MCP Server in HTTP Mode Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Starts the LinkedIn MCP Server using the streamable-http transport. Configure host, port, and path as needed. ```bash uv run -m linkedin_mcp_server --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp ``` -------------------------------- ### Create LinkedIn MCP Server Profile Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/docs/docker-hub.md Run this command on your host machine to create a local browser profile for LinkedIn login. This is a one-time setup step. ```bash uvx mcp-server-linkedin@latest --login ``` -------------------------------- ### Call a Tool with cURL Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CLAUDE.md Calls a specific tool (e.g., 'get_person_profile') using the initialized session ID. This example requests the 'posts' section for a given LinkedIn username. ```bash # Call a tool curl -s -X POST http://127.0.0.1:8000/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Mcp-Session-Id: $SESSION_ID" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_person_profile","arguments":{"linkedin_username":"williamhgates","sections":"posts"}}}' ``` -------------------------------- ### Get Ready LinkedIn Extractor Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Provides an authenticated LinkedInExtractor instance, ensuring the browser is created and authenticated. It validates the session and handles setup-in-progress errors. Returns a singleton extractor. ```python async def get_ready_extractor( ctx: Context, tool_name: str = "unknown", ) -> LinkedInExtractor: """ Get authenticated extractor. Raises: AuthenticationError if not logged in """ ``` -------------------------------- ### Get Recent Inbox Conversations Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/01-tools-reference.md Fetches a list of recent conversations from the LinkedIn messaging inbox. Use this to get an overview of recent activity. The limit parameter controls the number of conversations returned. ```python result = await get_inbox(limit=30) inbox_text = result["sections"].get("inbox", "") ``` -------------------------------- ### Register Person Profile Tools Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Registers tools for managing person profiles, including getting profiles, searching people, and connecting with individuals. These tools are designed for GET operations (readOnlyHint: True) and POST operations (destructiveHint: True for connect). ```python def register_person_tools( mcp: FastMCP, *, tool_timeout: float = 180.0 ) -> None: ``` -------------------------------- ### initialize_bootstrap Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Initializes the runtime bootstrap process based on the provided RuntimePolicy. This function configures the environment by detecting the runtime, loading session state, setting up the browser, and preparing the profile directory. ```APIDOC ## initialize_bootstrap ### Description Initializes runtime bootstrap based on the runtime policy. This involves detecting the runtime environment, loading session state, configuring the browser, and preparing the profile directory. ### Signature ```python def initialize_bootstrap(policy: RuntimePolicy) -> None: """Initialize bootstrap based on runtime policy.""" ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **policy** (RuntimePolicy) - Required - The runtime policy to determine the bootstrap configuration. ### Request Example ```python from linkedin_mcp_server.bootstrap import initialize_bootstrap, RuntimePolicy initialize_bootstrap(RuntimePolicy.LOCAL) ``` ### Response #### Success Response (200) None ``` -------------------------------- ### Handle ScrapingError in Python Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md Example of catching a ScrapingError during an API call and retrying with a smaller scope. ```python try: result = await get_person_profile("williamhgates", sections="posts") except ScrapingError as e: print(f"Scraping failed: {e}") # Retry with smaller scope result = await get_person_profile("williamhgates") ``` -------------------------------- ### Initialize Runtime Bootstrap Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Initializes the runtime bootstrap process based on the provided RuntimePolicy. This function is used to set up the server's environment. ```python def initialize_bootstrap(policy: RuntimePolicy) -> None: """Initialize bootstrap based on runtime policy.""" ``` -------------------------------- ### runtime_profile_dir Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Get runtime-specific profile directory. This function returns the derived runtime profile path. ```APIDOC ## runtime_profile_dir ### Description Get runtime-specific profile directory. ### Signature ```python def runtime_profile_dir(profile_dir: Path) -> Path: """Return derived runtime profile path.""" ``` ``` -------------------------------- ### Initiate Interactive Login Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Execute this command to open a browser for an interactive login session. The server will exit after a successful login. This method handles CAPTCHAs and 2FA prompts. ```bash uv run -m linkedin_mcp_server --login ``` -------------------------------- ### Dependency Injection in Tool Signatures Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Illustrates how tools receive dependencies, such as the MCP context and optional extractors, directly through function arguments. This facilitates testing and modularity. ```python async def get_person_profile( linkedin_username: str, ctx: Context, # MCP context (injected) sections: str | None = None, extractor: Any | None = None, # Optional override (testing) ) -> dict[str, Any]: extractor = extractor or await get_ready_extractor(ctx) ``` -------------------------------- ### Release Process Steps Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CLAUDE.md Commands to execute for releasing a new version. Use 'uv version --bump' to update the version in pyproject.toml and uv.lock. ```bash git checkout main && git pull uv version --bump minor # or: major, patch — updates pyproject.toml AND uv.lock gt create -m "chore: Bump version to X.Y.Z" gt submit # merge PR to trigger release workflow ``` -------------------------------- ### configure_logging Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Sets up the logging system for the application. It allows configuration of the log level and output format (JSON or text). ```APIDOC ## configure_logging ### Description Sets up the logging system for the application. It allows configuration of the log level and output format (JSON or text). ### Signature ```python def configure_logging( log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"], json_format: bool = False, ) -> None ``` ### Parameters #### Parameters - **log_level** (str) - Required - Logging level threshold - **json_format** (bool) - Optional - Use JSON format (for non-interactive, non-debug) ``` -------------------------------- ### Handle ElementNotFoundError Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md Example of catching ElementNotFoundError during an operation like connecting with a person. This can occur if buttons are missing or the page structure has changed. ```python try: result = await connect_with_person("williamhgates") except ElementNotFoundError as e: print(f"Element not found: {e}") # Could be: already connected, profile restricted, button hidden ``` -------------------------------- ### BrowserManager Singleton Implementation Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Internal implementation details for the BrowserManager singleton pattern, managing the global browser instance. ```python _browser: BrowserManager | None = None async def get_or_create_browser() -> BrowserManager: global _browser if _browser is None: _browser = await _create_browser() return _browser async def close_browser() -> None: global _browser if _browser: await _browser.browser.close() _browser = None ``` -------------------------------- ### Create MCP Server with Custom Timeout Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Instantiate the MCP server with a specific tool timeout value. This allows for longer-running tools. ```python from linkedin_mcp_server.server import create_mcp_server # Create server with custom tool timeout mcp = create_mcp_server(tool_timeout=300) # 5 minutes ``` -------------------------------- ### Reinstall Dependencies with UV Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Synchronizes and reinstalls project dependencies using uv. Use this command if you encounter dependency-related issues. ```bash uv sync --reinstall ``` -------------------------------- ### Run uvx with Debug Logging Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Execute the LinkedIn MCP server with debug logging enabled to observe detailed operational information. ```bash uvx mcp-server-linkedin@latest --log-level DEBUG ``` -------------------------------- ### Get Sidebar Profiles Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/01-tools-reference.md Extract profile URLs from sidebar recommendation sections on a LinkedIn profile page. This is useful for discovering related profiles. ```python async def get_sidebar_profiles( linkedin_username: str, ctx: Context, extractor: Any | None = None, ) -> dict[str, Any]: ... result = await get_sidebar_profiles("williamhgates") # Extract all sidebar profile recommendations sidebar = result.get("sidebar_profiles", {}) for section_name, profile_paths in sidebar.items(): print(f"{section_name}: {len(profile_paths)} profiles") for path in profile_paths: username = path.split("/in/")[1].rstrip("/") print(f" - {username}") ``` -------------------------------- ### Get Browser Profile Directory Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Retrieves the configured path for the browser profile directory. This path is used for storing and loading browser sessions. ```python from linkedin_mcp_server.drivers.browser import get_profile_dir profile_dir = get_profile_dir() print(f"Browser profile directory: {profile_dir}") ``` -------------------------------- ### run_profile_creation Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Initiates an interactive profile creation flow, typically for LinkedIn login. It can be run in headless mode. ```APIDOC ## run_profile_creation ### Description Initiates an interactive profile creation flow, typically for LinkedIn login. It can be run in headless mode. ### Signature ```python async def run_profile_creation( user_data_dir: Path, headless: bool = False, ) -> bool: """ Run interactive LinkedIn login. Returns: True if successful, False if cancelled/failed """ ``` ### Parameters #### Parameters - **user_data_dir** (Path) - Required - Directory for user data - **headless** (bool) - Optional - Whether to run in headless mode ``` -------------------------------- ### Handle ProfileNotFoundError Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md Example of catching ProfileNotFoundError when fetching a person's profile that does not exist. If a profile is not found, consider using a search function instead. ```python try: result = await get_person_profile("williamhgates123xyz") # Doesn't exist except ProfileNotFoundError as e: print("Profile not found") # Try searching instead search = await search_people("william gates") ``` -------------------------------- ### GitHub CLI for PR Review Comments Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/CLAUDE.md Use these GitHub CLI commands to fetch initial reviews, inline comments, and follow-up reviews for a pull request. ```bash gh api repos/{owner}/{repo}/pulls/{pr}/reviews # initial reviews gh api repos/{owner}/{repo}/pulls/{pr}/comments # inline comments gh api repos/{owner}/{repo}/issues/{pr}/comments # follow-up reviews ``` -------------------------------- ### Validate Configuration Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Call the validate() method to check if the loaded configuration is correct. This is typically done on server startup. ```python config.validate() ``` -------------------------------- ### Logout and Login Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md If your session expires, use these commands to log out and log in again. This is useful for re-authenticating your account. ```bash uv run -m linkedin_mcp_server --logout && --login ``` -------------------------------- ### Get Company Employees Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/01-tools-reference.md Lists employees at a specified company, with an option to filter by a keyword. This is useful for finding employees with specific roles or skills within an organization. ```python # List all employees result = await get_company_employees("docker") ``` ```python # Filter by keyword result = await get_company_employees("docker", keyword_filter="engineer") ``` -------------------------------- ### Pull Latest Docker Image Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/RELEASE_NOTES_TEMPLATE.md Use this command to pull the latest version of the linkedin-mcp-server Docker image. The 'latest' tag ensures you get the most recent release. ```bash docker pull stickerdaniel/linkedin-mcp-server:latest ``` -------------------------------- ### Run uvx in HTTP Mode Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/README.md Configure and run the LinkedIn MCP server using the streamable HTTP transport mode with specified host, port, and path. ```bash uvx mcp-server-linkedin@latest --transport streamable-http --host 127.0.0.1 --port 8080 --path /mcp ``` -------------------------------- ### Configure HTTP Server Host Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Set the HTTP server bind address to listen on all network interfaces. Warning: Exposes the MCP endpoint to the network without authentication. ```bash uv run -m linkedin_mcp_server --transport streamable-http --host 0.0.0.0 ``` -------------------------------- ### Initialize LinkedInExtractor Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Initializes the LinkedInExtractor with a BrowserManager instance. This is the first step before performing any scraping operations. ```python def __init__(self, browser: BrowserManager): self.browser = browser self.page = browser.page ``` -------------------------------- ### Extend Scraper with Custom Methods Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Create a custom extractor by inheriting from LinkedInExtractor and adding new scraping methods. This example shows how to scrape recommendations for a given username. ```python from linkedin_mcp_server.scraping.extractor import LinkedInExtractor class CustomExtractor(LinkedInExtractor): async def scrape_recommendations(self, username: str): """Custom method to scrape recommendations.""" await self.page.goto( f"https://www.linkedin.com/in/{username}/details/recommendations/", wait_until="domcontentloaded", ) text = await self.page.text_content() return {"recommendations": text} ``` -------------------------------- ### Set Headless Mode for Browser Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Configures whether the browser should run in headless mode for subsequent creations. This setting must be applied before calling `get_or_create_browser`. ```python from linkedin_mcp_server.drivers.browser import set_headless, get_or_create_browser set_headless(True) # Run in headless mode browser = await get_or_create_browser() # ... use browser ... ``` -------------------------------- ### Create MCP Server Instance Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Use the `create_mcp_server` factory function to initialize and configure the FastMCP server. This function registers all LinkedIn tools, sets up sequential execution middleware, manages browser lifecycles, and enables error masking. The `tool_timeout` parameter controls the per-tool execution timeout in seconds. ```python from linkedin_mcp_server.server import create_mcp_server mcp = create_mcp_server(tool_timeout=300) # Server is ready for MCP client connections ``` -------------------------------- ### Get Authenticated User's Profile Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/01-tools-reference.md Retrieves the LinkedIn profile of the currently authenticated user. The 'url' field in the result reveals the user's actual username. ```python async def get_my_profile( ctx: Context, sections: str | None = None, max_scrolls: int | None = None, extractor: Any | None = None, ) -> dict[str, Any]: ... # Get own profile result = await get_my_profile() # Reveals actual username in URL (e.g., "linkedin.com/in/johndoe/") actual_username = result["url"].split("/in/")[1].rstrip("/") # Fetch own profile with all sections result = await get_my_profile( sections="experience,education,skills,projects,posts" ) ``` -------------------------------- ### Run LinkedIn MCP Server with Custom Chrome Path Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/06-server-and-cli.md Launch the server using a specific path to the Chrome or Chromium browser executable. ```bash uv run -m linkedin_mcp_server \ --chrome-path /usr/bin/chromium-browser \ --timeout 10000 ``` -------------------------------- ### get_runtime_id Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Get unique identifier for current runtime environment. Returns a unique ID per container for Docker, or 'local' for local environments, used for session isolation. ```APIDOC ## get_runtime_id ### Description Get unique identifier for current runtime environment. ### Signature ```python def get_runtime_id() -> str: """Return runtime ID (uuid or "local").""" ``` ### Behavior - Docker: Unique ID per container - Local: "local" - Used for session isolation ``` -------------------------------- ### End-to-End Test Get Person Profile Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md Integration test for scraping a person's profile against a live LinkedIn instance. Requires a valid session and will open/close a browser. ```python import pytest @pytest.mark.asyncio async def test_get_person_profile_e2e(): """Test against live LinkedIn (requires valid session).""" from linkedin_mcp_server.drivers.browser import ( get_or_create_browser, close_browser, ) from linkedin_mcp_server.scraping.extractor import LinkedInExtractor from linkedin_mcp_server.core import is_logged_in browser = await get_or_create_browser() # Verify logged in assert await is_logged_in(browser.page) # Scrape extractor = LinkedInExtractor(browser) result = await extractor.scrape_person( "williamhgates", {"main_profile", "experience"} ) # Verify assert "williamhgates" in result["url"] assert "main_profile" in result["sections"] await close_browser() ``` -------------------------------- ### Custom Browser and Profile Directory Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Specify a custom path for the Chrome executable and a user data directory for a custom browser profile. ```bash uv run -m linkedin_mcp_server \ --user-data-dir /opt/linkedin-profiles/user1 \ --chrome-path /usr/bin/chromium-browser ``` -------------------------------- ### Environment Variables in .env File Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Example of a .env file used to store environment variables for the LinkedIn MCP Server. This file is read by the configuration loader via python-dotenv. ```dotenv # .env LOG_LEVEL=DEBUG TIMEOUT=10000 TOOL_TIMEOUT=300 CHROME_PATH=/usr/bin/chromium-browser PORT=8080 VIEWPORT=1920x1080 ``` -------------------------------- ### Production/Docker HTTP Server Configuration Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/03-configuration.md Configure the server for production or Docker use with HTTP transport, specifying host, port, log level, and an extended tool timeout. ```bash uv run -m linkedin_mcp_server \ --transport streamable-http \ --host 127.0.0.1 \ --port 8000 \ --log-level WARNING \ --tool-timeout 300 ``` -------------------------------- ### Get Runtime ID Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Retrieves the unique identifier for the current runtime environment. Returns 'local' for local execution and a unique ID for Docker containers, used for session isolation. ```python def get_runtime_id() -> str: """Return runtime ID (uuid or "local").""" ``` -------------------------------- ### Enable Visual Debugging and Slow Motion Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md Run the server in non-headless mode with slow motion enabled to visually observe browser navigation and element interactions during scraping. This is useful for debugging failures visually. ```bash uv run -m linkedin_mcp_server --no-headless --slow-mo 1000 --log-level DEBUG ``` -------------------------------- ### Handle NetworkError Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/04-errors.md Example of catching NetworkError when fetching a person's profile due to network issues. If a network error occurs, it's often advisable to wait and retry the operation. ```python try: result = await get_person_profile("williamhgates") except NetworkError as e: print(f"Network error: {e}") # Wait and retry await asyncio.sleep(5) result = await get_person_profile("williamhgates") ``` -------------------------------- ### get_config Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/05-core-modules.md Retrieves the global application configuration instance. This function provides access to all current settings loaded from environment variables, CLI arguments, and default values. ```APIDOC ## get_config ### Description Get global AppConfig instance with all current settings. ### Signature ```python def get_config() -> AppConfig: """Get global AppConfig instance.""" ``` ### Returns Singleton `AppConfig` instance with all current settings. ### Usage ```python from linkedin_mcp_server.config import get_config config = get_config() browser_timeout = config.browser.default_timeout tool_timeout = config.server.tool_timeout_seconds ``` ``` -------------------------------- ### Log Tool Execution Stats Source: https://github.com/stickerdaniel/linkedin-mcp-server/blob/main/_autodocs/07-integration-guide.md This Python snippet shows how to log tool execution statistics using the built-in logger. It's useful for monitoring the start and completion of tool operations. ```python import logging # Get tool execution stats logger = logging.getLogger("linkedin_mcp_server.sequential_tool_middleware") logger.debug("Tool execution: start") logger.debug("Tool execution: complete, duration=") ```