What it does
Draft a message for a person to approve. The approver can edit the text before it goes out; the agent sees the outcome with get_approval.
This tool drives a real LinkedIn account
Arguments
| Name | Type | Required | Meaning |
|---|---|---|---|
| profile | string | yes | Profile URL, public identifier or provider id of the recipient |
| text | string | yes | The message text |
| reason | string | no | Why this message, shown to the approver |
| account | string | no | Sender account id or name to send from. |
| dry_run | boolean | no | Check everything (target, do-not-contact, duplicates, text, limits) and return the verdict without proposing anything |
This table is generated from the literal inputSchema that tools/list returns, so what your client sees and what this page says are the same object:
{
"type": "object",
"properties": {
"profile": {
"type": "string",
"description": "Profile URL, public identifier or provider id of the recipient"
},
"text": {
"type": "string",
"description": "The message text"
},
"reason": {
"type": "string",
"description": "Why this message, shown to the approver"
},
"account": {
"type": "string",
"description": "Sender account id or name to send from."
},
"dry_run": {
"type": "boolean",
"description": "Check everything (target, do-not-contact, duplicates, text, limits) and return the verdict without proposing anything"
}
},
"required": [
"profile",
"text"
]
}Request
Paste this, swap the key, and you have called the tool.
curl -s https://topclozer.com/api/mcp \
-H "Authorization: Bearer tcz_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "propose_message",
"arguments": {
"profile": "dana-whitfield",
"text": "Thanks for connecting, Dana — would a 15-minute call next week be useful?",
"reason": "Accepted our request yesterday."
}
}
}'Returns
{ approval_id, status, duplicate, target, account, next } — the same envelope as propose_connection_request.
The payload arrives inside an MCP content block — one text block whose body is this JSON, pretty-printed. Parse the string; there is no structured-content field.
{ "approval_id": "apr_mf3k4c1z0", "status": "pending", "duplicate": false, "target": { "name": "Dana Whitfield", "headline": "CTO at Northbeam", "providerId": "ACoAAB1x…", "profileUrl": "https://www.linkedin.com/in/dana-whitfield" }, "account": "Marcus Feld", "next": "Waiting for a person in the TopClozer console → Approvals. Poll get_approval." }Worth knowing
Needs the linkedin:propose scope. Messages reach 1st-degree connections; to anyone else the approved send fails with the reason recorded on the approval.
Rate limit
30 LinkedIn tool calls per 5 minutes, per workspace. Exceeding it returns HTTP 429 with JSON-RPC error -32002 and a Retry-After header. The budget is shared by every LinkedIn tool and counted per workspace, so minting a second key does not buy a second allowance.
The limit exists because an agent retrying in a loop is the request pattern that gets a LinkedIn account restricted, and a restricted account is a much worse outcome for you than a 429. Workspace tools do not spend this budget.
Related tools
get_approval
The status of a proposal made with any propose_* tool: pending, approved, sent, rejected, failed or expired
propose_connection_request
Propose a LinkedIn connection request. It is NOT sent: it waits in the workspace's Approvals queue until a person approves it, then goes out under the account's Smart Limits.
list_linkedin_connections
First-degree connections of a connected sender account
All 65 tools are listed on the tool index. Connecting a client is on the Claude setup page, and the protocol details are on the server page.