"""
LinkedIn person profile scraping tools.
Uses innerText extraction for resilient profile data capture
with configurable section selection.
"""
import logging
from typing import Any
from fastmcp import Context, FastMCP
from mcp.types import ToolAnnotations
from linkedin_mcp_server.drivers.browser import (
ensure_authenticated,
get_or_create_browser,
)
from linkedin_mcp_server.error_handler import handle_tool_error
from linkedin_mcp_server.scraping import LinkedInExtractor, parse_person_sections
logger = logging.getLogger(__name__)
def register_person_tools(mcp: FastMCP) -> None:
"""Register all person-related tools with the MCP server."""
@mcp.tool(
annotations=ToolAnnotations(
title="Get Person Profile",
readOnlyHint=True,
destructiveHint=False,
openWorldHint=True,
)
)
async def get_person_profile(
linkedin_username: str,
ctx: Context,
sections: str | None = None,
) -> dict[str, Any]:
"""
Get a specific person's LinkedIn profile.
Args:
linkedin_username: LinkedIn username (e.g., "stickerdaniel", "williamhgates")
ctx: FastMCP context for progress reporting
sections: Comma-separated list of extra sections to scrape.
The main profile page is always included.
Available sections: experience, education, interests, honors, languages, contact_info
Examples: "experience,education", "contact_info", "honors,languages"
Default (None) scrapes only the main profile page.
Returns:
Dict with url, sections (name -> raw text), pages_visited, and sections_requested.
Sections may be absent if extraction yielded no content for that page.
The LLM should parse the raw text in each section.
"""
try:
await ensure_authenticated()
fields, unknown = parse_person_sections(sections)
logger.info(
"Scraping profile: %s (sections=%s)",
linkedin_username,
sections,
)
browser = await get_or_create_browser()
extractor = LinkedInExtractor(browser.page)
await ctx.report_progress(
progress=0, total=100, message="Starting person profile scrape"
)
result = await extractor.scrape_person(linkedin_username, fields)
if unknown:
result["unknown_sections"] = unknown
await ctx.report_progress(progress=100, total=100, message="Complete")
return result
except Exception as e:
return handle_tool_error(e, "get_person_profile")