How the LinkedIn Channel Routes Requests Between linkedin-mcp and Jina Reader Backends
The LinkedIn channel automatically routes requests to the linkedin-scraper-mcp backend when the mcporter CLI is detected and configured, otherwise falling back to Jina Reader, with the active_backend attribute determining the runtime dispatch path.
The Agent-Reach repository implements a robust LinkedIn integration that transparently switches between two distinct backends. Understanding how the LinkedIn channel routes requests between the linkedin-mcp and Jina Reader backends reveals a sophisticated health-check mechanism that prioritizes structured data extraction while maintaining universal accessibility.
Backend Declaration and MCP Health Detection
Declaring Available Backends
In agent_reach/channels/linkedin.py, the LinkedInChannel class explicitly declares its supported backends:
backends = ["linkedin-scraper-mcp", "Jina Reader"]
This ordered list establishes the preference hierarchy, with the MCP server offering richer structured data and Jina Reader providing a reliable fallback.
Probing the MCP Server
The check() method determines availability by probing the local mcporter installation using the probe_command utility from agent_reach/probe.py:
probe = probe_command("mcporter", ["config", "list"], timeout=10, package="mcporter")
If the probe succeeds and the output contains the string "linkedin", the channel sets:
self.active_backend = "linkedin-scraper-mcp"
Otherwise, the channel remains operational but relies on the Jina Reader fallback, ensuring continuous functionality even without the MCP server installed.
Runtime Routing Logic in BaseChannel
The actual request dispatch occurs in the BaseChannel class defined in agent_reach/channels/base.py. When read() or search() methods are invoked, the base class inspects self.active_backend to determine which concrete implementation to execute.
linkedin-scraper-mcp path: When active_backend equals "linkedin-scraper-mcp", the channel delegates to the MCP server via the run_backend helper, executing structured profile extraction through the npm-based MCP server.
Jina Reader fallback: If active_backend is unset or the MCP probe failed, requests route to the Jina Reader API, which fetches raw HTML and extracts textual content without requiring local MCP infrastructure.
Practical Implementation Examples
The following examples demonstrate how the routing operates in practice:
# Automatic backend selection
from agent_reach.core import AgentReach
ar = AgentReach()
profile = ar.read("https://www.linkedin.com/in/jane-doe-12345")
print(profile) # Structured data if MCP active, plain text otherwise
For advanced use cases, you can inspect the backend selection explicitly:
from agent_reach.channels.linkedin import LinkedInChannel
chan = LinkedInChannel()
chan.check() # Detects active_backend based on mcporter probe
if chan.active_backend == "linkedin-scraper-mcp":
data = chan.read("https://www.linkedin.com/jobs/view/123456")
else:
data = chan.read("https://www.linkedin.com/jobs/view/123456")
print(data)
Key Source Files and Responsibilities
-
agent_reach/channels/linkedin.py: Defines theLinkedInChannelclass, declares thebackendslist, and implements thecheck()method that setsactive_backendbased on mcporter probe results. -
agent_reach/channels/base.py: Contains the genericBaseChannelclass that routes requests to the backend specified inself.active_backend. -
agent_reach/probe.py: Provides theprobe_commandutility used to detect external tool availability and configuration. -
agent_reach/core.py: Exposes the publicAgentReachfacade that forwards requests to the appropriate channel.
Summary
- The LinkedIn channel maintains a
backendslist prioritizing "linkedin-scraper-mcp" over "Jina Reader". - The
check()method probes mcporter viaprobe_commandto determine if the MCP server is configured for LinkedIn scraping. - The
active_backendattribute stores the runtime selection, driving the routing decision inBaseChannel. - Requests automatically fall back to Jina Reader when the MCP server is unavailable, ensuring graceful degradation.
- All routing logic is implemented in the open-source Agent-Reach repository under the
agent_reach/channels/directory.
Frequently Asked Questions
What triggers the fallback to Jina Reader?
The fallback activates when the probe_command call to mcporter fails, returns no output, or lacks the "linkedin" configuration string. In these cases, active_backend remains unset or inaccessible, causing BaseChannel to route requests to the Jina Reader API instead of attempting MCP server communication.
How does the channel detect if linkedin-mcp is available?
Detection occurs through the check() method in LinkedInChannel, which executes probe_command("mcporter", ["config", "list"], timeout=10, package="mcporter"). If this command exits successfully and its output contains the substring "linkedin", the channel sets active_backend = "linkedin-scraper-mcp" and subsequent requests use the MCP backend.
Can I force the channel to use a specific backend?
While the public AgentReach API abstracts backend selection, you can instantiate LinkedInChannel directly and manually assign chan.active_backend = "linkedin-scraper-mcp" or "Jina Reader" before calling read() or search(). Note that manual override bypasses the automatic health checking provided by the check() method.
Where is the routing logic implemented?
The routing logic spans two files: agent_reach/channels/linkedin.py sets the active_backend attribute during initialization based on the mcporter probe, while agent_reach/channels/base.py implements the actual dispatch logic that reads this attribute and delegates to the appropriate backend handler.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →