LinkedIn Job Search MCP Server

LinkedIn Job Search MCP Server

Enables AI assistants to search LinkedIn jobs with built-in rate limiting to prevent IP bans. Supports job search, filtering, company profiles, and job categories through MCP tools.

Category
访问服务器

README

LinkedIn Job Search MCP Server

A Model Context Protocol (MCP) server that enables AI assistants (Claude, ChatGPT, etc.) to search LinkedIn jobs with built-in rate limiting to prevent IP bans.

Features

LinkedIn-Only Job Search — Real-time job data from LinkedIn via JobSpy
Request Throttling — Configurable delays (default: 2 seconds) between API calls
Rate Limit Handling — Graceful error messages when LinkedIn limits requests
5 MCP Tools — Search, filter, get details, company profiles, discover categories
Type-Safe — Pydantic models for all data structures
Production Ready — Comprehensive logging and error handling

Project Structure

mcp-server/
├── src/
│   ├── index.py              # MCP server with tool definitions & handlers
│   └── linkedin_client.py    # JobSpy wrapper with rate limiting
├── examples/
│   └── (future usage examples)
├── requirements.txt          # Python dependencies
├── pyproject.toml            # Project metadata
├── README.md                 # This file
├── .gitignore
└── .vscode/
    └── linkedin-mcp.json     # VS Code MCP configuration

Installation

Prerequisites

  • Python 3.10+
  • pip package manager
  • Virtual environment (recommended)

Setup

  1. Clone or navigate to the project:

    cd /Users/tarunkumaruppu/AI/mcp-server
    
  2. Create and activate a virtual environment:

    python3 -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  3. Install dependencies:

    pip install -r requirements.txt
    
  4. Verify installation:

    python -c "from src.linkedin_client import LinkedInJobClient; print('✅ Installation successful!')"
    

Configuration

Rate Limiting

Control how frequently the server calls LinkedIn to prevent IP bans.

Default behavior: 2 seconds between requests

To customize:

# Via environment variable (override default)
export LINKEDIN_REQUEST_DELAY=3.0  # 3 seconds between requests
python src/index.py

# Or set in code (src/index.py, line ~35):
linkedin_client = LinkedInJobClient(request_delay=3.0)

Recommended values:

  • 2.0 — Balanced (default)
  • 3.0-5.0 — Conservative (safer)
  • 1.0 — Aggressive (risk of bans)

VS Code Integration

  1. Open VS Code settings (Cmd+, on macOS)
  2. Search for "MCP Servers"
  3. The server is pre-configured in .vscode/linkedin-mcp.json
  4. Restart VS Code to enable

Or manually add to .vscode/settings.json:

{
  "mcpServers": {
    "linkedin-job-search": {
      "type": "stdio",
      "command": "python",
      "args": ["src/index.py"],
      "cwd": "/path/to/mcp-server"
    }
  }
}

Available Tools

1. search_jobs

Search for jobs on LinkedIn with optional filters.

Parameters:

  • keywords (required) — Job search keywords (e.g., "Python Developer")
  • location (optional) — Job location (default: "United States")
  • job_type (optional) — Filter by type (e.g., "full-time", "part-time")
  • experience_level (optional) — Filter by level (e.g., "entry-level", "senior")
  • hours_old (optional) — Jobs posted within last N hours (e.g., 24, 168)
  • limit (optional) — Max results (default: 25, max recommended: 50)

Example:

search_jobs(
  keywords="Data Scientist",
  location="San Francisco, CA",
  job_type="full-time",
  limit=20
)

Response:

Found 20 jobs for 'Data Scientist' in San Francisco, CA

1. Senior Data Scientist at Google (San Francisco, CA) [$150,000 - $200,000]
   Job ID: a1b2c3d4e5f6
   URL: https://www.linkedin.com/jobs/view/...
   Type: Full-time
   Posted: 2 days ago

2. get_job_details

Get detailed information about a specific job.

Parameters:

  • job_id (required) — Job ID from search results
  • job_url (required) — Job URL from search results

Example:

get_job_details(
  job_id="a1b2c3d4e5f6",
  job_url="https://www.linkedin.com/jobs/view/..."
)

Response:

Job Details (ID: a1b2c3d4e5f6)
job_id: a1b2c3d4e5f6
job_url: https://www.linkedin.com/jobs/view/...
message: Full job details are available by visiting the LinkedIn URL provided.
note: For complete job descriptions, visit the job_url directly on LinkedIn.

3. filter_jobs

Filter job results by salary, type, or keywords (local operation, no API call).

Parameters:

  • salary_min (optional) — Minimum annual salary
  • salary_max (optional) — Maximum annual salary
  • job_type (optional) — Filter by job type
  • keywords_filter (optional) — Filter by keywords in title/company

Example:

filter_jobs(
  salary_min=120000,
  salary_max=200000,
  job_type="full-time",
  keywords_filter="remote"
)

4. fetch_company_profile

Get company information from LinkedIn.

Parameters:

  • company_name (required) — Company name (e.g., "Google")

Example:

fetch_company_profile(company_name="Google")

Response:

Company Profile: Google

LinkedIn URL: https://www.linkedin.com/search/results/companies/?keywords=Google
Open Jobs: 142

5. list_job_categories

Discover supported job types and experience levels (no API call).

Example:

list_job_categories()

Response:

Supported Job Categories

Job Types:
  - Full-time
  - Part-time
  - Contract
  - Temporary
  - Internship

Experience Levels:
  - Entry-level
  - Mid-level
  - Senior
  - Executive

Note: Not all filters may be available for all searches on LinkedIn.

Rate Limiting & Error Handling

How Rate Limiting Works

  1. Request Throttle — Server waits LINKEDIN_REQUEST_DELAY seconds between API calls
  2. Timestamp Tracking — Each request timestamp is logged for debugging
  3. Sleep Before Request — If requests come too fast, the server sleeps to enforce delay

Common Errors & Solutions

❌ "LinkedIn rate limit reached"

Error: LinkedIn rate limit reached. Please wait 5-10 minutes before retrying.

Solution: Increase LINKEDIN_REQUEST_DELAY to 3-5 seconds, or wait and retry.

❌ "LinkedIn blocked the request (HTTP 403)"

Error: LinkedIn blocked the request (HTTP 403). Your IP may be temporarily banned.
       Wait 24-48 hours before retrying.

Solution: Your IP is temporarily blocked by LinkedIn. Wait 24-48 hours, then retry with higher delay.

❌ "Failed to search jobs"

Error: Failed to search jobs: [detailed error message]

Solution: Check your internet connection, keywords, and location. Review logs for details.


Logging

All requests and errors are logged to stdout with timestamps.

Log format:

2026-06-10 14:30:45,123 - src.linkedin_client - INFO - Searching LinkedIn for: Python Developer in San Francisco
2026-06-10 14:30:47,456 - src.linkedin_client - INFO - Found 25 jobs
2026-06-10 14:30:48,789 - src.index - INFO - Tool called: search_jobs with arguments: {...}

To adjust log level:

# In src/index.py, line ~20
logging.basicConfig(level=logging.DEBUG)  # For verbose output

Usage Examples

Example 1: Simple Job Search

Claude: "Find me Python developer jobs in San Francisco"

→ Tool Call: search_jobs(
    keywords="Python Developer",
    location="San Francisco, CA",
    limit=25
  )

→ Result: [25 job listings with titles, companies, salaries]

Example 2: Search with Filters

Claude: "Find senior-level data scientist jobs in NYC, full-time, posted in the last 7 days"

→ Tool Call: search_jobs(
    keywords="Data Scientist",
    location="New York, NY",
    job_type="full-time",
    experience_level="senior",
    hours_old=168,
    limit=20
  )

→ Result: [20 filtered job listings]

Example 3: Company Research

Claude: "How many open positions does Google have on LinkedIn?"

→ Tool Call: fetch_company_profile(company_name="Google")

→ Result: 
  LinkedIn URL: https://www.linkedin.com/search/results/companies/?keywords=Google
  Open Jobs: 142

Example 4: Multi-Step Job Hunt

Turn 1: Claude searches for jobs
  → search_jobs(keywords="ML Engineer", location="Remote", limit=30)
  
Turn 2: Claude asks for company info on top candidates
  → fetch_company_profile(company_name="Anthropic")
  
Turn 3: Claude filters results by salary
  → filter_jobs(salary_min=150000, salary_max=250000)

Performance & Limitations

Performance

Operation Latency API Calls
search_jobs 2-10 seconds 1
get_job_details 2-5 seconds 1
filter_jobs <1 second 0 (local)
fetch_company_profile 2-10 seconds 1
list_job_categories <1 second 0 (local)

Limitations

⚠️ JobSpy Limitations:

  • Limited job description text extraction (full details require visiting LinkedIn URL)
  • Company profile data is minimal (name, URL, job count only)
  • Salary data may be incomplete on LinkedIn

⚠️ Rate Limiting:

  • Default 2-second throttle means max ~30 jobs per minute
  • LinkedIn may impose additional limits if too many requests from same IP
  • No guaranteed uptime—LinkedIn can block access at any time

⚠️ Data Freshness:

  • Job listings are real-time from LinkedIn
  • Salaries and benefits may not be up-to-date
  • Closed jobs may still appear briefly in results

Development

Project Dependencies

  • mcp — Model Context Protocol SDK
  • jobspy — LinkedIn job scraper
  • pydantic — Data validation & type hints
  • python-dotenv — Environment variable support

Code Structure

src/linkedin_client.py:

  • LinkedInJobClient class — Main client with rate limiting
  • JobListing Pydantic model — Job data structure
  • CompanyProfile Pydantic model — Company data structure

src/index.py:

  • MCP server setup and tool definitions
  • Tool handlers (search, details, filter, company, categories)
  • Error handling and formatting

Extending the Server

To add a new tool:

  1. Define the tool schema in get_tools() (src/index.py)
  2. Implement handler in linkedin_client.py
  3. Add MCP handler in handle_call_tool() (src/index.py)
  4. Document in this README

Example:

# 1. In linkedin_client.py
def my_new_feature(self, param: str) -> dict:
    """Implementation"""
    pass

# 2. In index.py, add to get_tools():
Tool(
    name="my_tool",
    description="...",
    inputSchema={...}
)

# 3. In handle_call_tool():
elif name == "my_tool":
    return await handle_my_tool(arguments)

# 4. Create handler:
async def handle_my_tool(arguments: dict):
    ...

Troubleshooting

Issue: ModuleNotFoundError: No module named 'mcp'

Solution:

pip install -r requirements.txt

Issue: Connection timeout to LinkedIn

Solution:

  • Check internet connection
  • Verify LinkedIn is accessible from your IP (not blocked)
  • Increase LINKEDIN_REQUEST_DELAY to reduce request frequency

Issue: Empty search results

Solution:

  • Try different keywords (LinkedIn may have strict matching)
  • Expand location (try "United States" instead of specific city)
  • Check if jobs exist on LinkedIn directly

Issue: Server won't start

Solution:

# Verify Python version
python --version  # Should be 3.10+

# Check dependencies
python -c "import mcp; import jobspy; print('OK')"

# Run with verbose logging
PYTHONUNBUFFERED=1 python src/index.py

Security Considerations

Current Implementation

✅ Parameterized inputs (no SQL injection risk)
✅ Request throttling (prevents IP bans)
✅ Graceful error handling (no sensitive info leakage)
✅ Local-only operation (no cloud storage)

For Production Use

⚠️ Consider adding:

  • IP rotation for high-volume searches
  • Request caching (SQLite) to reduce API calls
  • User rate limiting (per-user request quotas)
  • Audit logging (track who searches what)
  • API key authentication (if exposing over network)

FAQ

Q: Will LinkedIn ban my IP?
A: Unlikely with the default 2-second throttle. LinkedIn allows scraping via JobSpy. Higher request rates or aggressive filtering may trigger temporary blocks (24-48 hours).

Q: Can I search all job boards at once?
A: No, this server is LinkedIn-only. Use JobSpy directly for multi-source searches.

Q: How many jobs can I search per day?
A: Unlimited theoretically, but LinkedIn may rate-limit or block after 1000+ requests/hour.

Q: Can I save job listings locally?
A: Not in this version. Extend with SQLite caching if needed.

Q: Does this tool post on LinkedIn?
A: No, it's read-only. Cannot apply to jobs, message recruiters, or modify profiles.


References


License

MIT License — See LICENSE file for details.


Support

For issues, questions, or feature requests:

  1. Check the Troubleshooting section above
  2. Review Logs for detailed error messages
  3. Verify your Configuration (request delay, credentials, internet)

Last Updated: June 10, 2026
Version: 1.0.0
Status: Production Ready

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选