Datacircle

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:
    git clone --branch 1.17.1 https://github.com/langgenius/dify.git
    cd dify/docker
    cp .env.example .env
    docker compose up -d
    Then open http://localhost/install and create the admin account. The new Agent is in beta, and on by default with Docker Compose.
  • 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://api.datacircle.dev/mcp. 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:

The MCP server's settings
FieldValue
Server URLhttps://api.datacircle.dev/mcp
Name & IconDatacircle
Server Identifierdatacircle
Headers, Header NameAuthorization
Headers, Header ValueBearer, 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:

The Agent's settings for the MCP way
SettingValue
Modelyour model, such as OpenAI's gpt-5.4-mini
Promptthe line below
ToolsAdd, then MCP, then Datacircle's get_linkedin_profile 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_input and shell_interrupt, which run commands in the agent's sandbox. The first request was 11,278 bytes with only get_linkedin_profile, 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 found

Edit 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 received

Dify 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:

The Swagger API tool's authorization
FieldValue
Authorization typeHeader
Auth TypeBearer
KeyAuthorization
Valueyour API key

Dify makes one tool per operation: up2data_get_linkedin_profile and fetchin_get_linkedin_profile. 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_get_linkedin_profile 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:

The classic Agent node's settings for a cap
SettingValue
Agentic StrategyFunctionCalling, from Dify's Agent Strategies plugin (install it when Dify asks)
Modelyour model, such as gpt-5.4-mini
Tool listDatacircle's get_linkedin_profile, or the two Swagger API tools
Instructionfor MCP, the prompt line above
Querythe user's message, sys.query
Maximum Iterations5: 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

Our API's answers to the Swagger API tool
AnswerMeaningCostThe model reads
Up2Data 200the profile$2.375 per 1,000our JSON, twice when it holds a character outside ASCII
Up2Data 422the profile is private or deletedfreetool invoke error, the status and our JSON
Up2Data 400not a LinkedIn profile URLfreetool invoke error, the status and our JSON
Up2Data 429your account, or all our customers together, hit Up2Data's daily limitfreetool invoke error, the status and our JSON, then the model 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 lookuptool invoke error, the status and our JSON
Fetchin 429our customers together hit Fetchin's rate limitfreetool invoke error, the status and our JSON
402your balance can't cover the callfreetool invoke error, the status and our JSON
500, 502, 503 or 504the provider failed, or didn't answer within 45 secondsfreetool invoke error, the status and our JSON
401your key is wrongfreetool 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_PROXY_ALLOW_PRIVATE_IPS. 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.
  • 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:

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 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://api.datacircle.dev/mcp in Integrations > Tools > MCP, or import the OpenAPI schema on this page as a Swagger API tool.

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
Ask AI about Datacircle

Each opens with our question