Security & Data
Last reviewed: 21 August 2026
Installing an MCP server means letting an unfamiliar service sit inside your AI assistant. The reasonable question is: what can it reach, what does it keep, and who else sees it? This page answers that. It is written from an internal audit of the server’s source code, and where something is imperfect it is stated rather than left out.
Who operates Liftli
Liftli is operated by Oded Tsamir (LinkedIn profile, a LinkedIn-verified identity). He is a second-time founder. Before Liftli he was VP Product at Optibus, a company that grew from 20 to 400 people, raised around $260M and became public transport’s first unicorn — and before that, more than 20 years in product.
Contact for anything on this page, including deletion requests: support@liftli.ai.
Liftli has three parts, and this page is mostly about the first: the MCP server that connects to your AI assistant, a web console at app.liftli.ai, and an optional messaging channel such as Telegram. The Privacy Policy covers the legal picture; this page covers the mechanics.
What the server can and cannot access
An MCP server has no channel for reading your conversation. That is a property
of the protocol rather than a promise: your AI client decides when to call a tool and which values
to put in it, and the server receives that call. Across all 28 tool definitions in the server there
is no history, messages, conversation or context
parameter — nothing a client fills with a transcript. What reaches Liftli is what your
assistant puts into a tool call.
How the tools actually work
Most tools receive only what you hand them: a draft to critique, an idea to plan around, a post
to save. A few work differently. When you ask for ideas,
playbook(kind='seed_extraction') returns a mining brief rather than an answer
— the mining is done by your assistant, which saves each seed via
remember(..., body_content=...) — and the sources it accepts tell your assistant
to fetch material from this chat or from another tool you have connected.
playbook(kind='voice_extraction') does the same for voice calibration: it returns a
prompt that mines your existing LLM history, and news_monitor returns a scan brief
your assistant executes with its own web search — the server itself searches nothing. So for
these tools the server does ask. It asks your assistant to find material in your own notes and
conversations and send back what it finds — which happens when you ask for ideas, or ask
Liftli to learn how you write.
Whatever your assistant sends arrives through an ordinary parameter. The tools that carry your
material: remember(text, body_content) (a body up to 30,000 characters, saved as a seed
file), critique(draft), ready_to_post(draft),
plan_comment(post_text), playbook(source_text),
analyze_results(posts, engagement),
save_strategy(content, pillars_json), save_post(text),
log_outcome(post_summary, published_text), distribute(text),
media(prompt) and channel(message).
contact_support takes a single message parameter — what you typed to
support — and collects nothing alongside it.
So the accurate line is not “Liftli never sees your content”. It is: Liftli sees the material you ask it to work on, plus whatever your assistant mines when you ask for ideas, and it has no channel for reaching the rest.
The server does not run a language model
Liftli’s MCP server holds no model-provider credential and calls no model API. The writing
happens in your assistant, on your subscription. What the server contributes is structure: a bundled knowledge base plus your own saved profile, assembled into a
brief. Two things sit outside the MCP server and do use models — image generation when you
call media(action='generate'), which the backend performs, and transcription of voice
notes you send to the Liftli bot. Both are covered under
Third parties.
The backend host is pinned to an allowlist
Every URL the MCP server builds for Liftli’s backend is checked against an exact host allowlist first. A host outside it resolves to an empty string and the feature goes inert instead of sending, so a misconfiguration — or a host someone tried to inject — cannot receive your data. The third parties below each have their own fixed endpoint set by configuration: no tool parameter chooses a destination host.
What is stored, and for how long
Everything Liftli saves for you is kept under your own account, and one account cannot read another’s data.
Your working data
- Your profile (role, company, headline, ideal audience, goals, positioning, writing voice, timezone); the memory atoms and seed bodies you save; your posts and drafts; your LinkedIn, X and Substack strategies; usage ledgers, plan snapshot, onboarding progress, and the cached result of a LinkedIn profile read.
- Review records. A critique’s review record stores a hash of the draft it judged rather than the draft text (a verdict adds a summary of up to 400 characters). The draft itself is captured separately in the interactions record below, because
draftis one of the 21 names. - If you link a messaging channel so Liftli can reach you there, the identifier you link is stored so replies find your account. Unlinking removes it.
The record of what your assistant sends to Liftli’s tools
The deployed telemetry setting is full. At that setting, when a hosted request runs
for an identified account, Liftli records one entry against your account: the tool name,
whether it succeeded, how long it took, and the values of a fixed list of
21 argument names:
- Twelve short intent fields:
idea,goal,theme,question,topic,angle,section,kind,mode,post_format,format,pillar. - Nine content-bearing fields:
text,draft,content,body_content,post_text,material,post_summary,notes,pillars_json.
Each value is truncated at 4,000 characters. Arguments outside that list of 21 are not written to this file. This capture requires a hosted request with an identified account, so a local install on your own machine records nothing. The file is written inside your own per-account folder, alongside everything else Liftli saves for you.
Which tools contribute is decided purely by parameter name — the list above
— not by what the tool does. So critique(draft),
remember(text, body_content) and plan_post(idea, goal) are captured, while
recall(query), contact_support(message) and
approve_post(post_id) are not: those parameter names are not on the list. The cut runs
through the middle of tools, and in both directions — playbook’s
source_text, the raw material you paste for seed mining, and
analyze_results’ pasted posts and engagement data are
NOT on the list either, so they are never captured anywhere.
How long it is kept: for the lifetime of your account. The files rotate monthly for housekeeping, but nothing expires and nothing is deleted automatically. If you want it gone, you have to ask — see Deletion.
Why it is kept. Seeing the actual inputs is how the prompts, briefs and gates get fixed when the output is wrong for a particular person. It is not sold, not shared with advertisers, and not used to train AI models.
Two related facts. This record lives on Liftli’s own disk: at the full setting
the free-text intent block is not sent onward, so the analytics provider receives metadata. And a
companion event log — tool name, success, duration and the account — is kept on the same
disk with no expiry either. That log is a single shared file per month with one line
per call tagged by account, rather than a file inside your folder; it holds no content.
Things that are deliberately not stored
- No OAuth tokens, passwords or payment data are stored by the MCP server. Your LinkedIn and X tokens live in Liftli’s separate backend. The audit behind this page found no card number, billing address, payment token or payment-method parameter anywhere in the server’s code. Your personal Liftli key passes through to be exchanged for your account id, but is not written to disk.
- The memory store refuses to save credentials. An item’s text and its long body are both scanned, and a match on
sk-…,api key,password:,secret:or-----BEGINraises an error instead of storing. - Voice-note audio is not written to disk. The bytes go straight to transcription and the resulting text is what gets saved; the usage ledger records seconds and provider rather than the transcript.
- Your uploaded media does not pass through the MCP server.
media(action='upload')returns a signed one-time upload URL (it expires in about 15 minutes) and your file goes straight from your machine to storage.
One weakness worth naming
There is no encryption at rest. The files are UTF-8 JSON on the server’s disk, and confidentiality rests on host and filesystem controls plus the hosting platform’s own security. Writes are crash-atomic (written to a temporary file and swapped into place). If encryption at rest is a hard requirement for you, Liftli does not meet it today.
Deletion
Email support@liftli.ai and ask for your data to be deleted. It is handled manually, and you get a confirmation when it is done. Being exact about what that means, because the mechanism matters:
- There is no self-service erase button and no automatic expiry. The MCP server has no account-purge routine, so asking is how deletion happens.
- What deletion removes. Your per-account folder: profile, memory, seed bodies, posts, strategies, review records, usage ledgers, and the interactions record above. Your account row, your stored LinkedIn and X authorisations and any queued posts go on the application side, and any messaging channel you linked is unlinked.
- What takes an extra step. The event log is one shared file per month, so your lines sit interleaved with everyone else’s rather than inside your folder. Removing them means filtering and rewriting those files — a deliberate step in the procedure rather than a side effect of the folder delete. Ask and it is done; it holds no content either way. Analytics events already sent to the analytics provider, and billing records held by the payment provider as merchant of record, sit outside both of Liftli’s disks, so a deletion request covers your content and account data rather than every system that has ever seen a timestamp.
- Liftli’s
forgetfeature marks memory retracted rather than erasing it.remember(op='forget')appends a copy flagged as retracted; the original line stays in the append-only file, hidden from normal recall. The 15-minute “cancel” on a captured seed works the same way. A memory item genuinely gone from disk is a deletion request rather than aforget. - Some things do delete for real: a deleted saved post, an unlinked messaging-channel entry, a redeemed or expired pairing code, and your opt-in entry when you turn off the daily news reminder.
- You can take your data with you.
remember(op='export')returns your whole memory store as JSON, archive included.
Deletion is also covered by the Privacy Policy, which sets a 30-day response commitment for verified requests. In practice it is far faster.
The two ways to connect
A personal key
You generate a key in the Liftli console and paste one command, which registers the connector in
your AI client’s own config file. The key travels as an Authorization: Bearer
header, or — for connector UIs that cannot set a header — in the connector URL. It is an
identifier Liftli exchanges for your account id, and it cannot spend money: the one billing-related
tool, upgrade, returns a link you open in your own browser, and payment happens at the
payment provider.
- It expires if unused — a freshly minted key never used within 15 minutes revokes itself, so a key pasted into a chat and forgotten goes dead on its own. You can revoke from the console at any time; that kills every key on the account, and minting a new one revokes the previous one, so there is one live key per account.
- How it is checked. Keys are stored hashed; the plaintext exists once, when minted. A key in a header is cached for 30 seconds, so it is verified at most twice a minute; a key in the URL is re-verified on every request, so revoking it takes effect immediately.
- What lives on your machine is the key itself, in your client’s config file. Treat it like a password: anyone with that file can act as you in Liftli.
OAuth sign-in
Your client runs a standard OAuth flow against Liftli’s identity provider and stores the token in its own credential store rather than in a config file you manage, so no Liftli secret ends up in a file you have to protect. In Claude Code this needs 2.1.186 or newer; the personal key exists so older versions and header-less connector UIs still work. Liftli sends nothing about you to the identity provider — the server fetches its public signing keys over a plain GET and verifies your token locally.
What the tools do
The source contains 24 hosted @mcp.tool functions plus 4
browser-bridge tools registered only for a local install, making 28 tool
definitions. (The count used to be 54; a deliberate 2026-08 consolidation merged and
retired thirty of them, which is why this page is shorter than it was.) How many your client is
offered depends on the door: the default connector advertises all 24; the ChatGPT app-store door
advertises 23, because that store’s policy bans in-app subscription upsells and the in-chat
checkout tool is hidden there — along with every mention of it in the served instructions.
One of the 24, the news scanner, is registered only when its feature flag is on (it is on in
production). Nothing is added for any client, so 24 is the maximum.
Two things that happen on essentially every call
A timing wrapper wraps all 24 hosted tools and records the tool name, whether it succeeded, how
long it took, which AI-client family called, and enum/counter flags; some tools also emit a named
funnel event (strategy locked, seed used, profile rewritten, credit consumed, paywall hit,
activated). Every hosted tool forwards this, so a claim that some tools contact nobody outside
Liftli would be false. Separately, almost every tool touches your onboarding-progress file so the
footer knows where you are — most through a shared footer, a few indirectly (the status
render, dismissal preferences, or a first-read backfill). The one tool with no path to that file is
upgrade, which keeps its own offer ledger instead.
Which tools can make something appear publicly under your name
One: distribute. It is the single door for publishing now or scheduling for later
(send), rescheduling (move), cancelling (cancel) and
replacing a queued post’s text (replace) — the three separate publishing
tools this page used to describe were merged into it, behavior intact.
connect_account returns an authorization link for you to open, and
approve_post stamps a saved post as approved; neither publishes. Substack is
deliberately not publishable at all — there is no Substack API behind it, so a Substack draft
is reminder-only — and LinkedIn articles are refused at every door for the same reason.
The gate is enforced by the server rather than by a prompt an assistant could be talked around,
and the decision lives in one rule that every ship path calls. Text that has never cleared a
critique is hard-blocked; the authorizing review is matched by a hash of the exact text, so any
material edit reads as unreviewed; and a review only clears the surface it examined — a
Substack review cannot clear a LinkedIn publish. A critique stamp alone is not enough either: the
executed review’s verdict has to be submitted back, so a review that was narrated but never
run keeps the gate shut. A first post additionally has to score at least 8.0 overall
and at least 8.0 on hook strength alone (a weighted total can hide a weak hook); after
three honest review rounds the best pass ships with a receipt saying so. One caveat stated plainly:
the score is graded by the reviewing model itself, and the server records it so drift is
detectable. distribute and upgrade are annotated as requiring user
interaction, so a client that honors that hint will not let a model fire them silently.
Where that is imperfect, stated plainly. The four
distribute actions are not equally guarded. send and
replace go through the review rule; move and attaching media do not, and
a move can revive a failed post so that it publishes after all. What closes most of
the old gap: a move that carries new text is refused outright, so timing can change
without review but the words cannot. Cancelling can only reduce what goes out. The remaining
exposure is timing and attached media on a post that already cleared review.
The 24 hosted tools, by group
Each group heading is true of every tool beneath it. Retention is decided separately, by parameter name — the 21-name list — rather than by what a tool does, so it is called out per group.
| Group | What it receives | What it stores | What leaves Liftli |
|---|---|---|---|
1. Read what you have saved (2 — strategist_briefing, recall) |
nothing, or a query | nothing new beyond housekeeping; neither takes a 21-name parameter | the analytics event; both also ask the backend for your scheduled queue (and recall for your media list) |
2. Build a brief, metered by plan (6 — plan_post, plan_comment, playbook, analyze_results, news_monitor, rewrite_profile) |
an idea, topic, question or pasted material | a usage credit keyed by a hash of your text, not the text; all 6 take a 21-name parameter | your account id, to ask the backend which plan you are on — no content |
3. Review drafts — the publish gate (2 — critique, ready_to_post) |
your draft | a review record: a hash of the draft, the verdict, two scores and up to 400 characters of findings — never the draft text itself (the draft can land in the interactions record, because draft is one of the 21 names); a cleared draft is saved as a reviewed post |
the analytics event only |
4. Save what you tell Liftli (7 — remember, save_post, save_profile, save_strategy, log_outcome, approve_post, dismiss_suggestion) |
memory items and seed bodies, posts, strategy sections, profile fields, outcome notes, dismissal flags | in your folder, as the thing you asked to save; 4 of the 7 take a 21-name parameter. remember refuses anything matching the credential pattern |
the analytics event. save_profile also sends your company, role and how you found Liftli — those three fields only — to Liftli’s own customer record via the backend |
5. Act through Liftli’s backend (6 — distribute, media, connect_account, onboard, upgrade, contact_support) |
post text, media handles, an image prompt, a LinkedIn profile URL, a support message | post status, media references and scrape results; 2 of the 6 take a 21-name parameter | your account id plus that payload, to the backend — which holds your LinkedIn and X tokens and reaches LinkedIn or X, the payment provider or the image-generation provider on your behalf. onboard alone also sends your LinkedIn profile URL directly to a third-party profile-data provider |
6. Your phone connection (1 — channel) |
a message, a post id, or a link/unlink action | the identifier you linked, while it is linked; unlinking removes it | the post text or digest to Telegram, or to a third-party messaging gateway if that is the channel you linked. Linking itself sends nothing at call time |
The tool-by-tool breakdown behind this table — every tool, its parameters, what it reads, what it writes and where it sends — is available on request at support@liftli.ai.
distribute can also reach the plan lookup: a free account’s
publish allowance is checked at the backend, and rescheduling a failed post re-books a
plan-counted slot.
Tools that exist only on a local install (4, never advertised by the hosted server)
If you run Liftli on your own machine with the Chrome extension paired, four more tools are registered: they report whether the extension is paired, read the LinkedIn post or profile on your screen, and type a comment into the focused box for you to submit. The browser protocol has exactly three commands — read the current post, read the current profile, insert a comment — and none submits, so the server has no way to post one. They emit the same tool-name analytics event as every other tool; on a local install the event log is a file on your own machine. Two things can leave your computer: the comment tool’s plan check, and that analytics event if the analytics key is configured in your install.
Third parties
These are described by role and guarantee rather than by brand. That is deliberate: a list of vendor names is a supply-chain map for anyone hostile, and tells you nothing the role and the guarantee do not. If you want them named — for a vendor review, a DPA, or your own diligence — ask support@liftli.ai. LinkedIn, X and Telegram are named throughout, because you connect those yourself.
Reached by the MCP server itself
| Destination | How many tools reach it | What it receives |
|---|---|---|
| A product-analytics provider | all 24 hosted tools | tool name, success flag, AI-client family, an internal-account flag, a timestamp and enum/counter flags; some calls add a named funnel event. Call duration stays in Liftli’s own log. At the deployed setting, no free-text intent fields. The account identity in these events is a hash, not your email or name |
| Liftli’s own backend | about half the tools | the acting group sends content or an action (post text, media handles, image prompt, support message); the metered group sends your account id to ask which plan you are on — no content |
| Telegram, once you link it | 1 — channel, plus scheduled digests and reminders | the post text, or a digest headline and source link, pushed to your phone |
| A LinkedIn profile-data provider | 1 — onboard | your LinkedIn profile URL; the rest of the payload is fixed scrape options |
| A messaging gateway provider | 1 — channel, if that is the channel you linked | the message text being pushed to your phone |
Two more appear in the server that no tool can reach. A speech-to-text provider transcribes voice notes — but only when you send one to the Liftli bot, from the inbound webhook handler rather than from a tool; the audio is not kept. An identity provider is fetched for the public signing keys used to verify your sign-in token; nothing about you is sent, and verification happens locally.
Reached by Liftli’s backend on your behalf — one hop further out
- LinkedIn and X — publishing and scheduling, once you have connected an account.
- A payment provider, acting as merchant of record — checkout and billing portal.
- An image-generation provider — images from
media(action='generate'), and vision-reading of images you send to the bot. - An email-delivery provider — onboarding and welcome email, sent by a scheduled job rather than by a tool.
- A Liftli-operated customer record — your company, role and how you found Liftli, from
save_profile; and, once per account on your first authenticated request, your email address and display name.
The MCP server holds no LinkedIn, X, payment, image-generation or email credential — those live in the backend. It does hold credentials for the five services it calls itself.
What a search of the source does not find
A full search of the MCP server’s package finds no call to any model API, none to a
web-search, team-chat or cloud-storage provider, none to SMTP, and none to the LinkedIn, X,
payment or email-delivery APIs. The distinction that keeps this honest: publishing, payments,
email and image generation are capabilities you get, but the MCP asks Liftli’s backend
to perform them and holds none of those provider credentials itself; genuinely absent — not
merely delegated — are model APIs, web search, cloud-storage SDKs and SMTP. A dormant
team-chat placeholder exists with no feature flag behind it, so it is off. onboard
builds a linkedin.com/in/<slug> string to hand to the profile-data provider; the
server itself does not fetch linkedin.com. And one pre-emption for anyone grepping the
source: the speech-to-text provider’s URL contains the substring /openai/
because that provider exposes an OpenAI-compatible route shape — no model-provider
account is involved.
Things that happen outside any tool call
- Key verification. A personal key goes to Liftli’s host-pinned backend to be exchanged for your account id, cached under a hash rather than its raw value. Sign in through OAuth and there is no key at all.
- First authenticated request. Your account id, email address, display name and AI-client family are recorded once in Liftli’s own customer record — the one place your email and name leave the MCP server, and they go to Liftli’s backend rather than to a third party.
- Voice notes, photos and PDFs sent to the bot. Audio goes to the speech-to-text provider; images and PDFs are uploaded to Liftli’s backend.
- The web console’s onboarding step can trigger the same LinkedIn profile read
onboarduses, so that provider is reachable from one tool and one console action — in both cases the only user data in the payload is the profile URL. - Scheduled jobs send the daily news reminder (one fixed sentence and a button — no content) and onboarding emails. Both are opt-in or flag-gated.
- Telegram post-card buttons and the console can cancel, reschedule or re-text a queued post through the same backend endpoints the tools use — your own actions on your own devices rather than model-initiated ones.
Questions, or something wrong on this page
If you or your AI assistant find a claim here that does not match the behaviour you observe, say so — support@liftli.ai. Corrections to this page are more useful than a good impression of it.
See also: Privacy Policy · Terms of Use · All legal documents