Build a LinkedIn posting agent

Real code: a Claude agent that researches a topic, drafts a post, and publishes it to LinkedIn — fully automated.

What you'll build A Node.js script that (1) takes a topic from the command line, (2) uses Claude to research and draft a LinkedIn post, (3) calls the SquareMCP linkedin_create_post tool to publish — all in one agentic loop.

Prerequisites

Step 1 — Install dependencies

npm init -y
npm install @anthropic-ai/sdk @modelcontextprotocol/sdk

Step 2 — Create the agent

Create linkedin-agent.mjs:

import Anthropic from '@anthropic-ai/sdk';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

const SQUAREMCP_URL  = 'https://hermes.squaremcp.com/mcp';
const SQUAREMCP_TOKEN = process.env.SQUAREMCP_TOKEN;  // your Bearer token
const topic = process.argv[2] ?? 'AI trends in 2026';

// ── 1. Connect to SquareMCP ──────────────────────────────────────
const transport = new StreamableHTTPClientTransport(new URL(SQUAREMCP_URL), {
  requestInit: { headers: { Authorization: `Bearer ${SQUAREMCP_TOKEN}` } },
});

const mcpClient = new Client({ name: 'linkedin-agent', version: '1.0.0' });
await mcpClient.connect(transport);

// Fetch available tools from SquareMCP
const { tools: mcpTools } = await mcpClient.listTools();

// Convert MCP tool descriptors to Anthropic tool format
const anthropicTools = mcpTools.map(t => ({
  name: t.name,
  description: t.description,
  input_schema: t.inputSchema,
}));

// ── 2. Run the agentic loop ──────────────────────────────────────
const anthropic = new Anthropic();
const messages = [
  {
    role: 'user',
    content: `You are a LinkedIn content strategist. Your job:
1. Think about the topic: "${topic}"
2. Draft a compelling LinkedIn post (150-250 words, professional tone, 3-5 hashtags)
3. Call linkedin_create_post to publish it
4. Report back what was posted.

Write the post now and publish it.`,
  },
];

console.log(`\n🤖 Agent starting — topic: "${topic}"\n`);

while (true) {
  const response = await anthropic.messages.create({
    model: 'claude-opus-4-7',
    max_tokens: 1024,
    tools: anthropicTools,
    messages,
  });

  // Append assistant turn
  messages.push({ role: 'assistant', content: response.content });

  if (response.stop_reason === 'end_turn') {
    const text = response.content
      .filter(b => b.type === 'text')
      .map(b => b.text)
      .join('\n');
    console.log('\n✅ Agent finished:\n', text);
    break;
  }

  if (response.stop_reason !== 'tool_use') break;

  // Execute each tool call against SquareMCP
  const toolResults = [];
  for (const block of response.content) {
    if (block.type !== 'tool_use') continue;

    console.log(`🔧 Calling ${block.name}...`);
    let result;
    try {
      result = await mcpClient.callTool({ name: block.name, arguments: block.input });
      console.log(`   ✓ ${JSON.stringify(result.content[0]).slice(0, 120)}...`);
    } catch (err) {
      result = { content: [{ type: 'text', text: `Error: ${err.message}` }] };
      console.error(`   ✗ ${err.message}`);
    }

    toolResults.push({
      type: 'tool_result',
      tool_use_id: block.id,
      content: result.content,
    });
  }

  messages.push({ role: 'user', content: toolResults });
}

await mcpClient.close();

Step 3 — Run it

export ANTHROPIC_API_KEY=sk-ant-...
export SQUAREMCP_TOKEN=your-bearer-token-here

node linkedin-agent.mjs "The future of AI agents in enterprise software"

Expected output:

🤖 Agent starting — topic: "The future of AI agents in enterprise software"

🔧 Calling linkedin_create_post...
   ✓ {"id":"urn:li:share:7194...","success":true}...

✅ Agent finished:
 I've published the following LinkedIn post:

"Enterprise software is undergoing a quiet revolution..."
[full post text]

The post has been published successfully to your LinkedIn feed.

Step 4 — Extend it

Now that you have the agentic loop working, you can extend it:

Post to multiple platforms at once

// Replace the user message with:
content: `Draft a post about "${topic}" and publish it on both
LinkedIn (professional tone) and Twitter (punchy, max 280 chars, 2 hashtags).
Use linkedin_create_post and twitter_create_tweet.`

Schedule with a cron job

# Post every weekday at 9am
0 9 * * 1-5 SQUAREMCP_TOKEN=... ANTHROPIC_API_KEY=... \
  node /path/to/linkedin-agent.mjs "$(cat /path/to/topics.txt | shuf -n1)"

React to inbound WhatsApp messages

Configure a webhook in the SquareMCP dashboard. When a WhatsApp message arrives, SquareMCP POSTs to your server. Run the same agent loop but start with the inbound message as context:

import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.json());

app.post('/webhook', async (req, res) => {
  // Verify signature
  const sig = req.headers['x-squaremcp-signature'];
  const expected = `sha256=${crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex')}`;
  if (sig !== expected) { res.status(401).end(); return; }

  res.status(200).end(); // acknowledge immediately

  const { platform, data } = req.body;
  console.log(`Inbound from ${platform}: ${data.text}`);

  // Run agent in background...
  runAgent(data).catch(console.error);
});

app.listen(3000);

Going further

← Getting started

Configure Claude Desktop, Codex CLI, or opencode.

Platform guides

Connect TikTok, WhatsApp, Instagram, and more.

API reference ↗

Full tool schemas for every platform.

Anthropic tool use ↗

Deep dive into Claude's tool-use API.