Skip to main content
Glama

web_data_linkedin_job_listings

Extract structured LinkedIn job listings data from URLs using reliable cached access instead of direct scraping.

Instructions

Quickly read structured linkedin job listings data This can be a cache lookup, so it can be more reliable than scraping

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYes

Implementation Reference

  • Core handler logic shared by all 'web_data_*' tools, including 'web_data_linkedin_job_listings'. Triggers a BrightData dataset using the specific dataset_id, polls the snapshot status up to 600 times (10 minutes), and returns the JSON results.
    execute: tool_fn(`web_data_${id}`, async(data, ctx)=>{
        let trigger_response = await axios({
            url: 'https://api.brightdata.com/datasets/v3/trigger',
            params: {dataset_id, include_errors: true},
            method: 'POST',
            data: [data],
            headers: api_headers(),
        });
        if (!trigger_response.data?.snapshot_id)
            throw new Error('No snapshot ID returned from request');
        let snapshot_id = trigger_response.data.snapshot_id;
        console.error(`[web_data_${id}] triggered collection with `
            +`snapshot ID: ${snapshot_id}`);
        let max_attempts = 600;
        let attempts = 0;
        while (attempts < max_attempts)
        {
            try {
                if (ctx && ctx.reportProgress)
                {
                    await ctx.reportProgress({
                        progress: attempts,
                        total: max_attempts,
                        message: `Polling for data (attempt `
                            +`${attempts + 1}/${max_attempts})`,
                    });
                }
                let snapshot_response = await axios({
                    url: `https://api.brightdata.com/datasets/v3`
                        +`/snapshot/${snapshot_id}`,
                    params: {format: 'json'},
                    method: 'GET',
                    headers: api_headers(),
                });
                if (['running', 'building'].includes(snapshot_response.data?.status))
                {
                    console.error(`[web_data_${id}] snapshot not ready, `
                        +`polling again (attempt `
                        +`${attempts + 1}/${max_attempts})`);
                    attempts++;
                    await new Promise(resolve=>setTimeout(resolve, 1000));
                    continue;
                }
                console.error(`[web_data_${id}] snapshot data received `
                    +`after ${attempts + 1} attempts`);
                let result_data = JSON.stringify(snapshot_response.data);
                return result_data;
            } catch(e){
                console.error(`[web_data_${id}] polling error: `
                    +`${e.message}`);
                attempts++;
                await new Promise(resolve=>setTimeout(resolve, 1000));
            }
        }
        throw new Error(`Timeout after ${max_attempts} seconds waiting `
            +`for data`);
    }),
  • server.js:385-392 (registration)
    Dataset configuration entry that defines the 'linkedin_job_listings' ID, its BrightData dataset_id 'gd_lpfll7v5hcqtkxl6l', description, and input schema 'url'. This is used in the loop to register the tool as 'web_data_linkedin_job_listings'.
        id: 'linkedin_job_listings',
        dataset_id: 'gd_lpfll7v5hcqtkxl6l',
        description: [
            'Quickly read structured linkedin job listings data',
            'This can be a cache lookup, so it can be more reliable than scraping',
        ].join('\n'),
        inputs: ['url'],
    }, {
  • Dynamically builds the Zod input schema object for the tool based on the 'inputs' array from the dataset config (for this tool: { url: z.string().url() }).
    let parameters = {};
    for (let input of inputs)
    {
        let param_schema = input=='url' ? z.string().url() : z.string();
        parameters[input] = defaults[input] !== undefined ?
            param_schema.default(defaults[input]) : param_schema;
    }
  • server.js:683-686 (registration)
    Registers the tool by calling server.addTool() with the constructed name 'web_data_linkedin_job_listings', description, parameters schema, and execute handler.
    addTool({
        name: `web_data_${id}`,
        description,
        parameters: z.object(parameters),
  • Wrapper function 'tool_fn' used for all tools' execute handlers. Handles rate limiting, stats tracking, logging, error handling with API details, and timing.
    function tool_fn(name, fn){
        return async(data, ctx)=>{
            check_rate_limit();
            debug_stats.tool_calls[name] = debug_stats.tool_calls[name]||0;
            debug_stats.tool_calls[name]++;
            debug_stats.session_calls++;
            let ts = Date.now();
            console.error(`[%s] executing %s`, name, JSON.stringify(data));
            try { return await fn(data, ctx); }
            catch(e){
                if (e.response)
                {
                    console.error(`[%s] error %s %s: %s`, name, e.response.status,
                        e.response.statusText, e.response.data);
                    let message = e.response.data;
                    if (message?.length)
                        throw new Error(`HTTP ${e.response.status}: ${message}`);
                }
                else
                    console.error(`[%s] error %s`, name, e.stack);
                throw e;
            } finally {
                let dur = Date.now()-ts;
                console.error(`[%s] tool finished in %sms`, name, dur);
            }
        };
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions the cache lookup capability and reliability advantage over scraping, which are valuable behavioral insights. However, it doesn't address important aspects like rate limits, authentication requirements, error conditions, or what 'structured data' specifically means in terms of output format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with just two sentences that each earn their place. The first sentence establishes the core purpose, and the second adds crucial behavioral context about cache reliability. There's zero wasted language, and the information is front-loaded effectively.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (structured data extraction from LinkedIn), no annotations, no output schema, and 0% schema description coverage, the description is incomplete. While it establishes purpose and reliability advantages, it lacks details about parameter usage, output format, error handling, and limitations. For a web data extraction tool with many scraping alternatives, more guidance would be helpful.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 0%, so the description must compensate for the undocumented parameter. The description doesn't mention the 'url' parameter at all, nor does it explain what kind of LinkedIn URLs are supported (e.g., job search results, specific job postings, company job pages). With 1 parameter and 0% schema coverage, the baseline would be lower, but the tool's purpose is clear enough to warrant a 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Quickly read structured linkedin job listings data' specifies the verb ('read'), resource ('linkedin job listings data'), and key characteristic ('structured'). It distinguishes from siblings like 'scrape_as_html' by emphasizing structured data extraction rather than raw scraping. However, it doesn't explicitly differentiate from other LinkedIn tools like 'web_data_linkedin_company_profile'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: 'This can be a cache lookup, so it can be more reliable than scraping' suggests it should be preferred over scraping tools when reliability is important. It implicitly contrasts with scraping siblings but doesn't explicitly state when NOT to use it or name specific alternatives among the many sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dsouza-anush/brightdata-mcp-heroku'

If you have feedback or need assistance with the MCP directory API, please join our Discord server