Datacircle

LinkedIn profiles in Open WebUI: a LinkedIn tool through MCP or a Python Tool

You run Open WebUI, and your model should read a LinkedIn profile from its URL in a chat: the job title, company, location and headline. Open WebUI's docs call it "a self-hosted AI platform" for Ollama and OpenAI-compatible APIs. Open WebUI ships no tool that reads a LinkedIn profile.

Datacircle is a data co-op. Step 1: Query your favorite B2B data APIs through us. Same request, same price, no markup. Step 2: You're DONE. Every morning, you get the flat file of your data plus everyone else's. Add $50 to your account: you get $50 of API PLUS the flat file. Right now we have 3 live LinkedIn profile APIs that we trust: Up2Data, HarvestAPI and Fetchin.

You can add our MCP server in Open WebUI's admin settings: no code. Or you can paste one Python Tool into your workspace, and the Tool's code decides when to call Fetchin. Both call Up2Data first. Up2Data costs $2.375 per 1,000 profiles it finds, and nothing for a profile it can't find. Fetchin is cheaper at $1.485 per 1,000, but it charges for a profile it can't find, and all our customers share its rate limit. Your model, or the Tool, calls Fetchin only when Up2Data hits its daily limit and returns a 429. Open WebUI doesn't retry a failed call. But by default, Open WebUI allows 256 rounds of tool calls per reply: the command below sets the limit to 5.

We ran Open WebUI 0.12.0 on our machine with Docker, with a script in place of the model and a test server in place of our API. We ran the MCP server and the Python Tool against api.datacircle.dev with a wrong key: each got a 401, at no charge. We haven't run either with a real key or a real model.

Open WebUI has no tool that reads a LinkedIn profile URL

In Open WebUI, a model uses tools: Python Tools in your workspace, MCP servers, OpenAPI servers, and tools built into Open WebUI. On October 12, 2026, a search for "linkedin" on openwebui.com, where people share tools, returned 16 items. One tool searches the web through another company's API, LinkedIn among its sites. The others are forum posts, and models and prompts that write LinkedIn posts.

The site's search doesn't cover a tool's code, so we read all 922 tools and 1,285 functions on the site. One more tool posts to LinkedIn and other networks. None reads a profile from its URL. Open WebUI's own code on GitHub has no LinkedIn reader either.

Before you start

  • Open WebUI, self-hosted. Start it with the Docker command its README gives for OpenAI, plus a setting we added that caps each reply at 5 rounds of tool calls:
    docker run -d -p 3000:8080 \
      -e OPENAI_API_KEY=your_openai_key \
      -e CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS=5 \
      -v open-webui:/app/backend/data \
      --name open-webui --restart always \
      ghcr.io/open-webui/open-webui:main
    Then open http://localhost:3000 and create the first account, which makes you the admin.
  • A Datacircle API key: Sign up at datacircle.dev with your work email: a $5 credit, that's 2,105 LinkedIn profiles at $2.375 per 1,000. Log in at datacircle.dev/login with your work email. Your API key is on the page once you're in.
  • A model with tool calling. With OPENAI_API_KEY set, Open WebUI lists OpenAI's models.

The MCP way: our MCP server in Integrations

Our MCP server is at https://api.datacircle.dev/mcp. It gets a LinkedIn profile from its URL, through Up2Data, HarvestAPI or Fetchin. In Open WebUI, only an admin can add an MCP server. Click your picture at the bottom left, then Settings. Under Admin, open Integrations, and click + next to External Tool Servers. In Add Connection, click OpenAPI next to Type so it reads MCP Streamable HTTP, then fill in:

The MCP connection's settings
FieldValue
NameDatacircle
Connection IDdatacircle: Open WebUI fills it in from the name
URLhttps://api.datacircle.dev/mcp
AuthBearer
API Keyyour API key
Function Name Filter Listget_linkedin_profile
Access Controlthe users or groups who may use it (only admins, until you add some)

Click the arrows next to the URL, Verify Connection: Open WebUI says Connection successful. Click Save. In Workspace, open Models, click Create and set:

The model's settings for the MCP way
SettingValue
Model NameLinkedIn reader
Base Model (From)your model, such as OpenAI's gpt-5.4-mini
System Promptthe line below
ToolsDatacircle

The system prompt:

If datacircle_get_linkedin_profile says up2data's daily limit is reached, call it again with provider fetchin.

Click Save & Create, pick LinkedIn reader in a new chat and ask it:

Read the LinkedIn profile at https://www.linkedin.com/in/example-profile: the job title, company, location and headline.

You see View Result from datacircle_get_linkedin_profile above the answer. You need mcpo, Open WebUI's proxy from MCP to OpenAPI, only for servers that run over stdio or SSE (Open WebUI's MCP page). Ours runs over Streamable HTTP, so it needs no proxy.

Open WebUI gives the model our description and our server's instructions

The model got our tool as datacircle_get_linkedin_profile: the Connection ID, then our tool's name. It got our whole description (804 characters) and both inputs, url and provider, with the three choices for provider and its default. It didn't get our output schema. Open WebUI puts the system prompt first, then our server's instructions, under a line that names the server. With the filter list empty, the model gets every tool our server lists.

In the chat page, Open WebUI gives the model 39 tools of its own, including memory, notes, knowledge and the calendar. Our scripted model's first request was 28,437 bytes.

Open WebUI puts each key of our JSON on its own line: 14% to 32% more characters for the model to read

Open WebUI reads our answer as JSON and gives the model the provider's JSON, plus datacircle_meta, what the call cost and your balance after it. It writes each key on its own line:

{
  "data": {…},
  "meta": {…},
  "datacircle_meta": {…}
}

Up2Data's example answer is 1,027 characters in our JSON and reached the model as 1,355. A saved Fetchin answer of 65,082 characters reached it as 74,222, with every field. Through the Python Tool, the model reads our JSON unchanged.

Open WebUI doesn't retry a call, and the model reads our errors

The tool takes url, and provider: up2data (the default), harvestapi or fetchin. At Up2Data's limit, the server tells your agent to call again through Fetchin or HarvestAPI. HarvestAPI costs more per 1,000 profiles than the other two, so we name Fetchin in the system prompt. Open WebUI sends each failing call once, and wraps our error in its own. At the limit, the model reads:

{
  "error": "[{'type': 'text', 'text': '{\"error\": \"daily up2data limit reached for your account …\"}', 'annotations': None, 'meta': None}]"
}

Our JSON is inside it. We didn't bill the 429, and our scripted model called again with fetchin and got the profile. The model read our JSON in the other errors too. If Fetchin can't find the profile, we bill one lookup. Our MCP server docs list the tools.

With a wrong key, the model gets no tool

We added our live MCP server with a wrong key. Verify Connection showed Connection failed, but we could save it. We sent a message: our server refused Open WebUI with a 401, and the chat showed:

Failed to connect to MCP server 'datacircle'

Then the model answered without our tool. Edit the connection from its gear in Integrations, set the right key, and verify it before you save.

Open WebUI waits for our answer

On api.datacircle.dev, we answer 503, at no charge, when a provider hasn't answered within 45 seconds. To see how long Open WebUI waits, we made our test server answer after 50 seconds, then after 65. Both times, the model got the profile. So our 503 at 45 seconds reaches the model before Open WebUI gives up.

The Python Tool way: one Tool in your workspace

You send the provider's own request to api.datacircle.dev, with your Datacircle key. That's the only change. The Tool below sends Up2Data's own request. On Up2Data's 429, it sends Fetchin's, with X-Data-Provider naming the provider. Up2Data's request is in our API reference. We put the switch to Fetchin in the Tool's code, so the model makes one call, in Native and in Legacy mode.

To add a Tool, you need to be an admin, or a user with the Tools Access permission, which is off until an admin turns it on. Open WebUI's Tools page warns that a Tool runs as Python code on your Open WebUI server. In Workspace, open Tools, click Create, and paste this code over the example:

"""
title: Datacircle
description: Read a LinkedIn profile from its URL through Datacircle's API, Up2Data first, then Fetchin at Up2Data's daily limit.
"""

import aiohttp
from pydantic import BaseModel, Field

API = "https://api.datacircle.dev"


class Tools:
    class Valves(BaseModel):
        api_key: str = Field("", description="Your Datacircle API key", json_schema_extra={"input": {"type": "password"}})

    def __init__(self):
        self.valves = self.Valves()

    async def get_linkedin_profile(self, url: str) -> str:
        """
        Get a LinkedIn profile from its URL, live. Through Up2Data, data has headline, location.raw and current_company with name and
        title. Through Fetchin, the answer has jobTitle, companyName, location and title, the headline. Each call may be billed.
        :param url: The LinkedIn profile URL, like https://www.linkedin.com/in/example-profile
        """
        async with aiohttp.ClientSession(headers={"Authorization": f"Bearer {self.valves.api_key}"}) as session:
            up2data = {"X-Data-Provider": "up2data"}
            async with session.post(f"{API}/v1/profiles/enrich", headers=up2data, json={"url": url}) as answer:
                if answer.status != 429:
                    return await self._read(answer, "Up2Data")
            # Up2Data's daily limit: the same profile through Fetchin
            fetchin = {"X-Data-Provider": "fetchin"}
            async with session.get(f"{API}/api/v1/profile", headers=fetchin, params={"profileUrlOrUrn": url}) as answer:
                return await self._read(answer, "Fetchin")

    async def _read(self, answer, provider):
        text = await answer.text()
        return text if answer.status == 200 else f"Error: {provider} answered {answer.status}: {text}"

Open WebUI fills in Tool Name Datacircle, Tool ID datacircle and the description from the code's first lines. Click Save & Create. In the list, click the gear next to Datacircle to open Valves, paste your key into Api Key and click Save. The key stays on the server, and the form hides it.

Create the LinkedIn reader model as above, with this Datacircle under Tools and no system prompt. Or, in any chat, click the Integrations button next to +, then Tools, and turn Datacircle on.

The Python Tool passes our JSON to the model unchanged

The model got get_linkedin_profile, the docstring as its description, and url. It read all1,027 characters of Up2Data's example answer, and all 65,082 of the long Fetchin answer. In the docstring, we tell the model where the job title, company, location and headline are in each provider's JSON.

The model reads our errors with their status

For any status but a 200 or Up2Data's 429, the Tool returns the provider, the status and our API's answer, without a retry. We tried a wrong key on api.datacircle.dev, without changing the code. The model read this line and went on with the chat:

Error: Up2Data answered 401: {"error": "invalid api key"}

After Up2Data's 429, the Tool called Fetchin once, and the model got the profile or Fetchin's error. Fetchin takes 5 requests a second for all our customers together, then answers 429. Open WebUI sets no time limit on a Tool's call, and aiohttp waits up to five minutes, so our 503 at 45 seconds reaches the model. We made our test server answer after 50 seconds, then after 65, to see how long Open WebUI waits. Both times, the model got the profile.

Native or Legacy function calling

In a chat, open Controls, then Advanced Params: Function Calling reads Default. Since Open WebUI 0.10.0, that's Native: Open WebUI sends the tools with each request, and the model calls them as often as it needs. We ran every test above in Native, unless it says Legacy.

In Legacy, Open WebUI first asks the model which tools to call, runs them once, and puts their results in the prompt. Then the model answers, with no tools. Through our MCP server, when Up2Data returned a 429, the model read our error in the prompt and couldn't call Fetchin. The Python Tool got the profile from Fetchin in its own code. A scripted model that asked for our tool at every turn made one call. Open WebUI's docs call Legacy unsupported, so keep the default.

Open WebUI allows 256 rounds of tool calls per reply by default

Open WebUI sends each tool call to our API. We bill each call that gets a profile, and each call for a profile Fetchin or HarvestAPI can't find, at the price on our pricing page. We don't bill Up2Data's 429 or Fetchin's 429.

Open WebUI runs a tool each time the model asks, up to CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS rounds per reply, 256 by default. With Function Calling set to Native, a scripted model that asked for our tool at every turn made 256 calls to our test server in less than 5 seconds, through the Python Tool and through our MCP server. At each turn, Open WebUI sends the model every tool result so far: the last request was more than 380,000 bytes. Then Open WebUI ended the reply with no answer and showed this error:

Tool-call limit reached (256 iterations).

The command above sets the limit to 5, for every model and chat in your Open WebUI. With it, the same scripted model made 5 calls. If it asked for 3 calls at once, Open WebUI ran all 3, 15 in all: a round can hold more than one call. Through our MCP server, the model took two rounds, Up2Data's 429 and then Fetchin's profile, before it answered.

By default, Open WebUI runs each call without asking. An admin can turn on Tool Permissions, which Open WebUI marks experimental, in Settings, Admin, Interface. Then the chat's + menu has Tool Permissions. If you pick Ask for approval there, Open WebUI stops the reply at each call and shows Allow and Deny. We allowed a call through the Python Tool and through our MCP server: each time, one call reached our test server, and the model got the profile. We denied one through each: no call reached it, and the model read:

Error: tool call rejected by user.

API answers: cost and what the model reads

Our API's answers to the Python Tool
AnswerMeaningCostThe model reads
Up2Data 200the profile$2.375 per 1,000our JSON
Up2Data 422the profile is private or deletednot billedError, the provider, the status and our API's answer
Up2Data 400not a LinkedIn profile URLnot billedError, the provider, the status and our API's answer
Up2Data 429your account, or all our customers together, hit Up2Data's daily limitnot billednothing: the Tool calls Fetchin
Fetchin 200the profile$1.485 per 1,000our JSON
Fetchin 404 with PROFILE_NOT_FOUNDthe profile is private or deleted$1.485 per 1,000: Fetchin bills the lookupError, the provider, the status and our API's answer
Fetchin 429our customers together hit Fetchin's rate limitnot billedError, the provider, the status and our API's answer
402your balance can't cover the callnot billedError, the provider, the status and our API's answer
500, 502, 503 or 504the provider failed, or didn't answer within 45 secondsnot billedError, the provider, the status and our API's answer
401your key is wrongnot billedError, the provider, the status and our API's answer

Through our MCP server, the model reads our JSON for every answer but a wrong key, Up2Data's 429 included. After that 429, our scripted model called Fetchin. Up2Data takes $1 a day per account (421 profiles), with a shared daily limit for all customers, then answers 429 until 00:00 UTC. HarvestAPI has no daily limit. Fetchin has no daily limit either.

The tests we ran

  • On October 12, 2026, we tested with Open WebUI 0.12.0 in Docker.
  • We saved the MCP connection, the Python Tool and its key through Open WebUI's API, with the settings and the code above. We sent each message through the same API the chat page uses, and pointed Open WebUI's OpenAI connection at a scripted stand-in for OpenAI's API.
  • We tested the MCP connection and the Python Tool against a stand-in for our API and our MCP server, with the tools our live server lists. We tried each answer in the table, a 50 second answer, a 65 second answer and the long answer, in Native and in Legacy. We tried a scripted model that never stops calling tools, and Ask for approval.
  • We didn't try a real Datacircle key or a real model. We checked the labels of each step above in Open WebUI's web app, and sent three messages from its chat page.

Cost per 1,000 profiles

We charge your balance the prices on our pricing page, with no markup:

Our price per 1,000 profiles and daily limit, by provider
Up2DataHarvestAPIFetchin
Per 1,000 found$2.375$3.70$1.485
Per 1,000 not foundfree$2.30$1.485
Daily limit421 profiles per accountnonenone

Say your model looks up 1,000 profiles in a day, one call each, and the providers find every one. You pay us at most $1.86: $1.00 for 421 through Up2Data and $0.86 for the other 579 through Fetchin. Through Fetchin alone, the same 1,000 would cost less: $1.485. The Python Tool, and our MCP tool by default, call Up2Data first: Up2Data bills nothing for a profile it can't find, and all our customers share Fetchin's rate limit. Calling Up2Data first costs less than Fetchin alone only when Up2Data misses 38% or more of the profiles. Your model may call the tool more than once per question. Your model's provider bills you for its tokens. Open WebUI asks your model for each new chat's title and tags, and for follow-up questions after each answer.

The same tool for an agent you build in Dify, Flowise or Langflow: LinkedIn profiles in Dify, LinkedIn profiles in Flowise and LinkedIn profiles in Langflow. The same call as an n8n workflow, without an agent: LinkedIn profiles in n8n. The same call from a script: get LinkedIn profile data with Python. In Claude, ChatGPT or Cursor: our LinkedIn MCP server. Other vendors' prices per 1,000: LinkedIn profile API pricing compared.

Questions

Does Open WebUI have a LinkedIn tool?

Open WebUI's team hasn't built one, and none of the tools on openwebui.com reads a profile from its URL. Add our MCP server at https://api.datacircle.dev/mcp in Settings > Admin > Integrations, or paste the Python Tool on this page into Workspace > Tools.

How do I send an API key to a remote MCP server in Open WebUI?

In Settings > Admin > Integrations, click + next to External Tool Servers. Set Type to MCP Streamable HTTP and Auth to Bearer, then paste the key into API Key. Open WebUI sends it as a Bearer token with every request to the server.

How do I limit tool calls in Open WebUI?

Set CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS when you start Open WebUI. By default, Open WebUI allows 256 rounds of tool calls per reply, in every chat and with every model. At the limit, Open WebUI ends the reply with "Tool-call limit reached" and no answer.

Should I use Native or Legacy function calling?

Use Native, the default since Open WebUI 0.10.0. In Legacy, Open WebUI runs the tools once before the model answers, so after Up2Data's 429 the model can't call Fetchin. Our Python Tool falls back to Fetchin itself, in both modes.

How much does a LinkedIn profile cost?

$2.375 per 1,000 through Up2Data (a profile it can't find is free), $3.70 per 1,000 through HarvestAPI. $1.485 per 1,000 through Fetchin, a profile it can't find billed the same. HarvestAPI bills a profile it can't find at $2.30 per 1,000.

Is there a daily limit?

Up2Data takes $1 a day per account (421 profiles), with a shared daily limit for all customers, then answers 429 until 00:00 UTC. HarvestAPI has no daily limit. Fetchin has no daily limit either.

Is each request live, or cached?

Live. Each request goes to the provider and gets the profile as it is today.

Do I need a LinkedIn account?

No. You send the profile's URL with your Datacircle key: no LinkedIn login, no cookies, no browser.

What happens when my balance runs out?

A call your balance can't cover answers 402. Add funds, from $5, on your dashboard.

Get started

Sign up at datacircle.dev with your work email: a $5 credit, that's 2,105 LinkedIn profiles at $2.375 per 1,000.

Sign up
Ask AI about Datacircle

Each opens with our question