Contributing to linkedin-mcp-pro¶
Thanks for your interest! This project is open source under MIT.
Quick start¶
git clone https://github.com/your-org/linkedin-mcp-pro
cd linkedin-mcp-pro
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest
# Run a single test file
pytest tests/test_safety.py -v
# Lint
ruff check linkedin_mcp/ tests/
ruff format linkedin_mcp/ tests/
# Type check
mypy linkedin_mcp/
Code style¶
- Python 3.11+ syntax (use
X | NonenotOptional[X], etc.) - Type hints on all public functions
- Async by default for I/O
- Ruff for formatting and linting
- Docstrings on public functions (Google style)
- No global state outside the
server.pylifespan
Adding a new tool¶
To add a new MCP tool:
- Pick a category: read (no ban risk) or write (safety-enforced)
- Implement in the appropriate module (
api/*.pyorbrowser/*.py) - Register in
server.py: - Add to
TOOLSlist (withinputSchema) - Add a dispatch branch in
_dispatch_read()or_dispatch_write() - Add tests in
tests/test_api.pyortests/test_browser.py - Update README tool list
Example for a new write tool:
# browser/post.py
async def schedule_post(client, text: str, scheduled_at: str) -> dict:
"""Schedule a post for future publication."""
# ...
return {"ok": True, "scheduled_at": scheduled_at}
# server.py
elif name == "schedule_post":
plan = ActionPlan(action="post", target="self", payload={...}, dry_run=dry_run)
guard.enforce(plan)
if dry_run:
raise DryRun(plan)
result = await br.schedule_post(text=args["text"], scheduled_at=args["scheduled_at"])
# Add to TOOLS list
{
"name": "schedule_post",
"description": "Schedule a post for future publication.",
"inputSchema": {...},
}
Adding a new safety check¶
Safety is a single layer (safety.py). To add a new check:
- Add a method to
SafetyGuard, e.g.def check_xyz(self, plan): ... - Call it from
enforce()in the right order - Raise the appropriate
SafetyErrorsubclass - Add a test in
tests/test_safety.py - Update
docs/SAFETY.md
Testing¶
We use pytest with pytest-asyncio (configured asyncio_mode = "auto").
# All tests
pytest
# Verbose
pytest -v
# With coverage
pytest --cov=linkedin_mcp --cov-report=term-missing
# Just safety
pytest tests/test_safety.py
# Just API
pytest tests/test_api.py
Mocking conventions¶
- httpx: use
httpx.MockTransport(no extra dep) - Patchright: mock the page object via
unittest.mock.AsyncMock - SQLite: use
tmp_pathfixture for isolation - Config: use
monkeypatch.setenv()to override env vars
Commit conventions¶
Use Conventional Commits:
feat: add schedule_post tool
fix: correct quota zone for 50%
docs: update SAFETY.md with new captcha pattern
test: add coverage for warm-up ramp
chore: bump pydantic to 2.7
Pull request process¶
- Fork the repo
- Create a feature branch:
git checkout -b feat/your-feature - Make your changes
- Add tests (PRs without tests are unlikely to merge)
- Run
pytest && ruff check && ruff format && mypy - Commit with conventional format
- Open a PR with a clear description
- Address review feedback
- Squash-merge when approved
Especially wanted contributions¶
- More Voyager endpoints (the API is undocumented — discover & document)
- Test coverage — current focus: tools, safety edge cases
- Documentation translations (we'd love a Spanish, Chinese, or Hindi version)
- Docker / k8s deployment examples
- Captcha pattern detection improvements
- Browser selectors that survive LinkedIn UI changes (we mark these as TODO)
Code of conduct¶
- Be kind and respectful
- Don't post spam / unsolicited outreach tools
- Don't add features that bypass LinkedIn's TOS in a way that harms other users
- This project is for legitimate professional use (job search, networking, brand building) — not for spam
License¶
By contributing, you agree your contributions are licensed under MIT.