LinkedIn profiles in Dify: a LinkedIn tool through MCP or a Swagger API tool
You're building an agent in Dify, and it should read a LinkedIn profile from its URL: the job title, company, location and headline. Dify's docs say "Dify is an open-source platform for building AI applications." Dify 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 to Dify and give its tool to your Agent: no code. Or you can import one OpenAPI schema as a Swagger API tool, and decide what the agent sees. Either way, your agent calls 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. The model switches to Fetchin only when Up2Data hits its daily limit and returns a 429. Dify sends each call once. But Dify's new Agent has no setting to cap tool calls: in our test, it stopped only at 500 model requests, after 500 calls. To cap them, use a Chatflow's Agent node.
We ran Dify 1.17.1 on our machine with Docker Compose, with a script in place of the model and a test server in place of our API. We ran both ways 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, or on Dify Cloud.
Dify has no tool of its own that reads a LinkedIn profile URL
In Dify, an agent uses your workspace's tools: tool plugins from the Marketplace, MCP servers, Swagger API tools built from an OpenAPI schema, and workflows. On October 12, 2026, a search for "linkedin" on Dify's Marketplace returned 20 plugins. The only one by Dify's team is a data source for knowledge bases that turns a web page into Markdown.
Some community plugins read a profile from its URL through another company's API and key, or with your own LinkedIn account's token. Others post to LinkedIn or search the web. Dify's code and app templates have no LinkedIn profile reader either.
Our plugin, Datacircle, is on the Marketplace too. In Dify, install Datacircle from the Marketplace: it gets a LinkedIn profile from its URL, through Up2Data, HarvestAPI or Fetchin. We installed version 0.0.2 on Dify 1.17.1. With a wrong key, Dify showed our 401 and didn't save the key. With the plugin, the model picks the provider on each call. You can also build the same agent from our MCP server or from one OpenAPI schema, and test each step.
Before you start
- Dify, self-hosted. Its Docker Compose page lists 2 CPU cores, 4 GiB of memory and Docker Compose 2.24.0 or later:Then open http://localhost/install and create the admin account. The new Agent is in beta, and on by default with Docker Compose.
git clone --branch 1.17.1 https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d - 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. In Integrations, then Model Provider, install a provider from the Marketplace, such as OpenAI, and add its key. We tested with the OpenAI-API-compatible plugin pointed at a script that answers like OpenAI's API, and haven't tried a real model.
The MCP way: our MCP server in Integrations, then the Agent
Our MCP server is at https://. It gets a LinkedIn profile from its URL, through Up2Data, HarvestAPI or Fetchin. In Integrations, under Tools, open MCP and click Add MCP Server (HTTP). In its Headers tab, click Add Header. Fill in:
| Field | Value |
|---|---|
| Server URL | https:// |
| Name & Icon | Datacircle |
| Server Identifier | datacircle |
| Headers, Header Name | Authorization |
| Headers, Header Value | Bearer, a space, then your API key |
Click Add & Authorize. Dify lists our tools. In Agents, click Create, then Create from Blank, name the agent, and in Configure set:
| Setting | Value |
|---|---|
| Model | your model, such as OpenAI's gpt-5.4-mini |
| Prompt | the line below |
| Tools | Add, then MCP, then Datacircle's get_ only |
The prompt:
If get_linkedin_profile says up2data's daily limit is reached, call it again with provider fetchin.Publish the agent and ask it:
Read the LinkedIn profile at https://www.linkedin.com/in/example-profile: the job title, company, location and headline.Dify's Build an Agent page shows each setting. Under Access Point, the same agent answers through Dify's service API.
Dify gives the model our whole answer
The model got our tool's name, its whole description (804 characters) and its two inputs, url and provider, with their descriptions. It didn't get our output schema, our server's instructions or the three choices for provider, though the description names them. Dify gives the model four tools of its own, shell_run, shell_wait, shell_ and shell_, which run commands in the agent's sandbox. The first request was 11,278 bytes with only get_, and 13,338 with every tool on our server. Dify puts your prompt line first in a system message of 7,871 characters.
Dify reads our answer's text as JSON and gives the model the provider's JSON, plus datacircle_meta, what the call cost and your balance after it:
{"data": {…}, "meta": {…}, "datacircle_meta": {…}}The model got Up2Data's example answer as 1,027 characters, and a saved Fetchin answer of 65,229 characters with every field, as 65,082: Dify writes each character our JSON escapes as the character itself, which is shorter.
Dify 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 prompt. Dify passes our errors to the model like any answer, and sends each call once. At the limit, the model reads:
{"error": "daily up2data limit reached for your account …"}Our 429 was free, and our test model called again with fetchin and got the profile. Dify sent each of the other failing calls to our server once too, and the model read our JSON. If Fetchin can't find the profile, we bill one lookup. Our MCP server docs list every tool.
With a wrong key, Dify lists no tools
We added our live MCP server with a wrong key. Dify kept it, with no tools: its card says Unconfigured Server, and its page says Authorization is required. An agent with our tool stopped before any model call, with:
Dify Tool 'get_linkedin_profile' runtime construction failed: Tool with name get_linkedin_profile not foundEdit the server from its ⋯ menu, set the right key in its header, click Save, then Authorize: Dify lists our tools. If the key stops working after Dify listed them, the model calls the tool and reads this line instead of a profile:
tool invoke error: Failed to connect to MCP server: Authentication failed - no token receivedDify waits for our answer
On api.datacircle.dev, we answer 503, at no charge, when a provider hasn't answered within 45 seconds. Dify waits longer: our test server answered after 50 seconds, then after 65, and the model got the profile both times.
The Swagger API way: one OpenAPI schema for our API
You send the provider's own request to api.datacircle.dev, with your Datacircle key. That's the only change. The schema below describes Up2Data's and Fetchin's own requests, with X-Data-Provider naming the provider. Up2Data's request is in our API reference. In Integrations, under Tools, open Swagger API as Tool, click Add Swagger API as Tool, name it Datacircle and paste this schema into Schema:
{
"openapi": "3.1.0",
"info": {
"title": "Datacircle",
"description": "Read a LinkedIn profile from its URL through Datacircle's API.",
"version": "1.0.0"
},
"servers": [{ "url": "https://api.datacircle.dev" }],
"paths": {
"/v1/profiles/enrich": {
"post": {
"operationId": "up2data_get_linkedin_profile",
"description": "Get a LinkedIn profile from its URL through Up2Data. Call this first. In the answer, data has headline, location.raw and current_company with name and title. A 422 means the profile is private or deleted. A 429 means Up2Data's daily limit: call fetchin_get_linkedin_profile with the same URL. Each call may be billed to the Datacircle balance.",
"parameters": [
{ "name": "X-Data-Provider", "in": "header", "required": true, "description": "Always up2data", "schema": { "type": "string", "default": "up2data" } }
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["url"],
"properties": {
"url": { "type": "string", "description": "The LinkedIn profile URL, like https://www.linkedin.com/in/example-profile" }
}
}
}
}
}
}
},
"/api/v1/profile": {
"get": {
"operationId": "fetchin_get_linkedin_profile",
"description": "Get a LinkedIn profile from its URL through Fetchin. Call this only after up2data_get_linkedin_profile answers 429. The answer has jobTitle, companyName, location and title, the headline. A 404 means the profile is private or deleted, and the lookup is billed. A 429 means too many requests at once: call again in a second. Each call may be billed to the Datacircle balance.",
"parameters": [
{ "name": "X-Data-Provider", "in": "header", "required": true, "description": "Always fetchin", "schema": { "type": "string", "default": "fetchin" } },
{ "name": "profileUrlOrUrn", "in": "query", "required": true, "description": "The LinkedIn profile URL, like https://www.linkedin.com/in/example-profile", "schema": { "type": "string" } }
]
}
}
}
}Then set its Authorization method:
| Field | Value |
|---|---|
| Authorization type | Header |
| Auth Type | Bearer |
| Key | Authorization |
| Value | your API key |
Dify makes one tool per operation: up2data_ and fetchin_. Build the same agent as above, with no prompt, and add both tools. The model reads each description, which says when to call it and which keys hold the job title, company, location and headline.
The model also sees X-Data-Provider as an input. Dify sent the schema's default when our test model left it out. Fetchin takes 5 requests a second across all our customers, and returns a 429 past that. We tell the model, in Fetchin's description, to call again in a second.
The model reads our errors with their status code
For any status of 400 or more, Dify sends the call once, and the model reads the status and our JSON. At Up2Data's daily limit:
tool invoke error: Request failed with status code 429 and {"error": "daily up2data limit reached for your account …"}After the 429, our test model called fetchin_ and got the profile. We tried a wrong key on api.datacircle.dev, with the schema unchanged: the model read this line after one call, and the agent kept running:
tool invoke error: Request failed with status code 401 and {"error": "invalid api key"}A profile can reach the model twice
Dify gives the model our answer's text, then Dify's copy of the same JSON. It drops the copy only when both are equal. Our JSON escapes every character outside ASCII and Dify's copy doesn't, so Up2Data's example reached the model as 2,194 characters, and our long Fetchin answer as 130,311. With every character in ASCII, the example came once, 1,027 characters. Through our MCP server, each answer comes once.
A Swagger API tool waits 60 seconds for our answer. Our test server answered after 50 seconds, and the model got the profile. Then it took 65 seconds. Dify stopped waiting at 60, and the model read:
Tool is temporarily unavailable. Please continue without it if possible.Dify's new Agent has no setting to cap tool calls
Dify 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. Up2Data's 429 and Fetchin's 429 are free.
The new Agent calls a tool each time the model asks. A test model that asked for our tool at every turn made 500 model requests and 500 calls to a stand-in for our API in less than 90 seconds. At each turn, Dify sends the model every tool result so far: the last request was more than 790,000 bytes. Then Dify stopped the run, with no answer, and this error:
The next request would exceed the request_limit of 500. Consider raising the limit, or see the docs on usage limits for budget-aware patterns: […]To cap tool calls, build the agent as a Chatflow: in Studio, create a Chatflow from blank, and put an Agent node between Start and the Answer node. On its Agent node page, Dify calls this node the classic Agent. Set:
| Setting | Value |
|---|---|
| Agentic Strategy | FunctionCalling, from Dify's Agent Strategies plugin (install it when Dify asks) |
| Model | your model, such as gpt-5.4-mini |
| Tool list | Datacircle's get_, or the two Swagger API tools |
| Instruction | for MCP, the prompt line above |
| Query | the user's message, sys.query |
| Maximum Iterations | 5: at most 4 rounds of tool calls |
In the Answer node, write the Agent node's text. With Maximum Iterations at 5, a test model that never stopped calling our tool made 4 calls. At 3, the node's default, it made 2. It asked for 3 calls at once, and Dify ran all 3: a round can hold more than one call. In the last round, the node answers each call with this line in place of the tool's answer, then ends:
Maximum iteration limit (5) reached. Cannot call tool 'get_linkedin_profile'. Please consider increasing the iteration limit.Dify marked the run succeeded, and the answer was blank: one line break per round, no text. A model that stops calling tools before the last round answers as usual. Up2Data's 429, then Fetchin's profile, took two rounds of calls and a third to answer, at 5 as at 3.
Through this node, our MCP answers reach the model after the words tool response:, and a Swagger API tool's errors after read tool response failed: request failed:. We added the server with a wrong key, and the node failed before any model call, as the new Agent did.
None of Dify's three agents asks a person to approve a tool call. A workflow's Human Input node pauses a run between two nodes and can't stop a tool call the model asks for, so we didn't build one.
API answers: cost and what the model reads
| Answer | Meaning | Cost | The model reads |
|---|---|---|---|
| Up2Data 200 | the profile | $2.375 per 1,000 | our JSON, twice when it holds a character outside ASCII |
| Up2Data 422 | the profile is private or deleted | free | tool invoke error, the status and our JSON |
| Up2Data 400 | not a LinkedIn profile URL | free | tool invoke error, the status and our JSON |
| Up2Data 429 | your account, or all our customers together, hit Up2Data's daily limit | free | tool invoke error, the status and our JSON, then the model calls Fetchin |
| Fetchin 200 | the profile | $1.485 per 1,000 | our JSON |
Fetchin 404 with PROFILE_ | the profile is private or deleted | $1.485 per 1,000: Fetchin bills the lookup | tool invoke error, the status and our JSON |
| Fetchin 429 | our customers together hit Fetchin's rate limit | free | tool invoke error, the status and our JSON |
| 402 | your balance can't cover the call | free | tool invoke error, the status and our JSON |
| 500, 502, 503 or 504 | the provider failed, or didn't answer within 45 seconds | free | tool invoke error, the status and our JSON |
| 401 | your key is wrong | free | tool invoke error, the status and our JSON |
Through our MCP server, the model reads our JSON for every answer but a wrong key. 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
- We tested on October 12, 2026, with Dify 1.17.1 in Docker, its Agent Strategies plugin 0.0.50 and the OpenAI-API-compatible plugin 0.0.68.
- We saved the MCP server, the Swagger API tool, each agent and each Chatflow through Dify's console API, with the settings and the schema above. We sent each run through Dify's service API and pointed the model at a scripted stand-in for OpenAI's API.
- We tested the Swagger API tool against a stand-in for our API that returned each answer in the table. We pointed the schema's server URL at it. Dify's SSRF proxy blocks private addresses unless you list them in
SSRF_. We tested the MCP connection against a stand-in for our MCP server with the tools our live server lists, and tried each error, a 50 and a 65 second answer and the long answer. We ran the Agent, the Chatflow's Agent node and the Legacy Agent app with a test model that never stops calling tools.PROXY_ ALLOW_ PRIVATE_IPS - We didn't try a real Datacircle key, a real model or Dify Cloud. We checked the labels of each step above in Dify's web app, in a browser, and saved nothing through it.
Cost per 1,000 profiles
We charge your balance the prices on our pricing page, with no markup:
| Up2Data | HarvestAPI | Fetchin | |
|---|---|---|---|
| Per 1,000 found | $2.375 | $3.70 | $1.485 |
| Per 1,000 not found | free | $2.30 | $1.485 |
| Daily limit | 421 profiles per account | none | none |
Say your agent 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. Either way, your agent calls Up2Data first because it bills nothing for a profile it can't find. That costs less than Fetchin alone only when at least 38% of the profiles can't be found. Your agent may call the tool more than once per question. Your model's provider bills you for its tokens, and Dify asks your model for each new conversation's title.
The same agent in Flowise's or Langflow's visual editor: LinkedIn profiles in Flowise and LinkedIn profiles in Langflow. The same call as an n8n workflow, without an agent: LinkedIn profiles in n8n. In code, as a tool for an agent: LinkedIn profiles in LangChain and other frameworks. 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 Dify have a LinkedIn tool?
Dify's team hasn't built one. On Dify's Marketplace, some community plugins read a profile from its URL with another company's API key, or with your own LinkedIn account's token. Ours is there too. In Dify, install Datacircle from the Marketplace: it gets a LinkedIn profile from its URL, through Up2Data, HarvestAPI or Fetchin. Or add our MCP server at https://
How do I send an API key to a remote MCP server in Dify?
While adding the server in Integrations > Tools > MCP, open the Headers tab, click Add Header, and fill in Header Name Authorization, Header Value Bearer <your key>. Dify sends it with every request to the server.
Does Dify's Agent have a max iterations setting?
The new Agent in Dify 1.17.1 has no such setting: it calls tools as long as the model asks, up to 500 model requests per run. The classic Agent node, in a Chatflow, has Maximum Iterations, 3 by default. The Legacy Agent app has Maximum Iterations, 10 by default, but Dify marks it deprecated.
Why does my Dify agent read a Swagger API tool's answer twice?
Dify gives the model the answer's text, then Dify's copy of the same JSON. It drops the second copy only when both are equal. Our answers escape every character outside ASCII and Dify's copy doesn't, so a profile with an accent or a symbol reaches the model twice. Through our MCP server, it reaches the model once.
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