<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eugeniya Ivanova</title>
    <description>The latest articles on DEV Community by Eugeniya Ivanova (@eugeniya_ivanova_4a58eadc).</description>
    <link>https://dev.to/eugeniya_ivanova_4a58eadc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4017574%2F67a20934-fb30-41ef-bfcc-79a85f515c48.jpg</url>
      <title>DEV Community: Eugeniya Ivanova</title>
      <link>https://dev.to/eugeniya_ivanova_4a58eadc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eugeniya_ivanova_4a58eadc"/>
    <language>en</language>
    <item>
      <title>Why Every AI Agent Eventually Fights Social Media APIs</title>
      <dc:creator>Eugeniya Ivanova</dc:creator>
      <pubDate>Tue, 07 Jul 2026 13:29:35 +0000</pubDate>
      <link>https://dev.to/eugeniya_ivanova_4a58eadc/why-every-ai-agent-eventually-fights-social-media-apis-35e0</link>
      <guid>https://dev.to/eugeniya_ivanova_4a58eadc/why-every-ai-agent-eventually-fights-social-media-apis-35e0</guid>
      <description>&lt;p&gt;AI agents have gotten weirdly good at writing.&lt;br&gt;
You can hand one a vague prompt and get back something publishable. The trouble starts one step later, when you ask it to actually press "post."&lt;br&gt;
"Post this to LinkedIn" sounds like one API call. In practice it's multiple OAuth flows, a few different media upload pipelines, review-gated permissions, token refresh logic, rate limits, and a scheduler for the moment you decide you'd rather not publish at 3am.&lt;br&gt;
The model isn't the hard part anymore.&lt;br&gt;
The integrations are.&lt;br&gt;
If you're building agents that publish, here's what that landscape actually looks like.&lt;/p&gt;
&lt;h2&gt;
  
  
  One network? Native is great.
&lt;/h2&gt;

&lt;p&gt;Let's start with the easy case. Posting to Bluesky via the AT Protocol is refreshingly straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a session&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://bsky.social/xrpc/com.atproto.server.createSession &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"identifier":"you.bsky.social","password":"'&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BLUESKY_APP_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s1"&gt;'"}'&lt;/span&gt;

&lt;span class="c"&gt;# Create a post&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://bsky.social/xrpc/com.atproto.repo.createRecord &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_JWT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "repo": "&amp;lt;your-did&amp;gt;",
    "collection": "app.bsky.feed.post",
    "record": {
      "text": "Hello Bluesky 👋",
      "createdAt": "2026-07-10T09:00:00Z"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two requests. That's the whole thing.&lt;br&gt;
Now imagine doing that for LinkedIn, X, Instagram, Facebook, Threads, and Mastodon—none of which were designed together, or, from the look of it, designed to be aware the others exist.&lt;br&gt;
There isn't really a "social media API." There are half a dozen unrelated APIs that happen to share a hobby.&lt;/p&gt;
&lt;h2&gt;
  
  
  Every platform has its own rules
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Authentication&lt;/th&gt;
&lt;th&gt;Biggest friction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LinkedIn&lt;/td&gt;
&lt;td&gt;OAuth 2.0&lt;/td&gt;
&lt;td&gt;App review for advanced publishing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;OAuth 2.0&lt;/td&gt;
&lt;td&gt;Pay-per-use since Feb 2026 — ~$0.015/post, &lt;strong&gt;$0.20 if it has a link&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram / Facebook / Threads&lt;/td&gt;
&lt;td&gt;Meta Graph API&lt;/td&gt;
&lt;td&gt;Business account + App Review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bluesky&lt;/td&gt;
&lt;td&gt;App password or OAuth&lt;/td&gt;
&lt;td&gt;Almost no friction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mastodon&lt;/td&gt;
&lt;td&gt;Token per instance&lt;/td&gt;
&lt;td&gt;Every instance is effectively its own API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern shows up fast. Open networks like Bluesky and Mastodon are easy to build against; the big commercial platforms want app reviews, business verification, paid access, or all three.&lt;br&gt;
X earns its own line here. Writing isn't just paid—it's paid per link. A plain post runs about $0.015, but a post with a URL costs $0.20. Which is a delightful surprise for an agent whose entire job is sharing links. You built automation to save time, and now it's quietly running up a tab, twenty cents at a time.&lt;/p&gt;
&lt;h2&gt;
  
  
  The integration work sneaks up on you
&lt;/h2&gt;

&lt;p&gt;Generating content is easy. Keeping the integrations alive is the actual job.&lt;br&gt;
Every platform authenticates differently, uploads media differently, scopes differently, fails differently, and expires its tokens on its own private schedule. Scheduling, half the time, isn't supported at all.&lt;br&gt;
At some point your AI project quietly turns into an OAuth project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where MCP fits
&lt;/h2&gt;

&lt;p&gt;One way out is to stop teaching the agent about every platform individually, and instead expose publishing as a single tool.&lt;/p&gt;

&lt;p&gt;With the Model Context Protocol (MCP), an agent discovers available tools with tools/list and calls them with tools/call. Under the hood it's plain JSON-RPC.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create_post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello from an agent 👋"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"platforms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"linkedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"bluesky"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"scheduledTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-10T09:00:00Z"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The interesting part isn't MCP itself. It's the abstraction.&lt;/p&gt;

&lt;p&gt;The agent calls one tool. Something behind that tool deals with OAuth, retries, uploads, scheduling, and whatever mood each platform is in today.&lt;/p&gt;

&lt;p&gt;It's a pattern engineers already know by heart: hide the provider-specific mess behind a stable interface, and try not to look at it too often.&lt;/p&gt;

&lt;p&gt;I'm skipping the protocol tour on purpose—teaching MCP from scratch would pull this post somewhere it doesn't need to go. If you want the proper walkthrough of tools/list, tools/call, and the JSON-RPC plumbing underneath, other people have already done it well:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/_d7eb1c1703182e3ce1782/mcp-server-tutorial-build-your-first-model-context-protocol-server-step-by-step-1ih" class="crayons-story__hidden-navigation-link"&gt;MCP Server Tutorial: Build Your First Model Context Protocol Server Step by Step&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/_d7eb1c1703182e3ce1782" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3834003%2Fe97eead8-8240-4d24-9909-25d6c8d411ce.png" alt="_d7eb1c1703182e3ce1782 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/_d7eb1c1703182e3ce1782" class="crayons-story__secondary fw-medium m:hidden"&gt;
              楊東霖
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                楊東霖
                
              
              &lt;div id="story-author-preview-content-3374386" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/_d7eb1c1703182e3ce1782" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3834003%2Fe97eead8-8240-4d24-9909-25d6c8d411ce.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;楊東霖&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/_d7eb1c1703182e3ce1782/mcp-server-tutorial-build-your-first-model-context-protocol-server-step-by-step-1ih" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/_d7eb1c1703182e3ce1782/mcp-server-tutorial-build-your-first-model-context-protocol-server-step-by-step-1ih" id="article-link-3374386"&gt;
          MCP Server Tutorial: Build Your First Model Context Protocol Server Step by Step
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tools"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tools&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/_d7eb1c1703182e3ce1782/mcp-server-tutorial-build-your-first-model-context-protocol-server-step-by-step-1ih#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            18 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;&lt;br&gt;
…and the official MCP docs are the canonical reference. No point in me repeating what they cover better.

&lt;h2&gt;
  
  
  Connecting an MCP server
&lt;/h2&gt;

&lt;p&gt;A hosted MCP server is usually just an endpoint and a key. Here's how I connect the one we built at Publora:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add publora &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://mcp.publora.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$PUBLORA_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Publora, your own server, someone else's implementation—it doesn't matter for the point. The architecture stays the same: your agent calls one tool instead of maintaining a relationship with five different APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that cost far more time than expected
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scheduling&lt;/strong&gt;&lt;br&gt;
Most APIs publish immediately. If you want scheduled posts, you're building a queue, retries, and a scheduler yourself—congratulations, you now maintain infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media uploads&lt;/strong&gt;&lt;br&gt;
Uploading media is almost never one request. Usually it's three:&lt;/p&gt;

&lt;p&gt;Ask for an upload target.&lt;br&gt;
Upload the file.&lt;br&gt;
Reference the returned media ID.&lt;/p&gt;

&lt;p&gt;And every platform has its own opinion about steps one through three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partial failures&lt;/strong&gt;&lt;br&gt;
"Publish everywhere" is never atomic. Three platforms succeed, one rate-limits you, and one rejects your image for reasons it declines to specify. It's a group project, and one member has gone quiet.&lt;br&gt;
So now you need retry policies and a way to tell the user what actually happened without lying to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formatting&lt;/strong&gt;&lt;br&gt;
Character limits, mentions, hashtags, markdown, media rendering—every platform supports roughly the same ideas and implements none of them the same way. The same post rarely looks identical in two places, and occasionally it shows up in one of them looking like a ransom note.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token management&lt;/strong&gt;&lt;br&gt;
OAuth refresh tokens, app passwords, per-instance tokens—each with its own expiration rules and its own refresh flow. Authentication itself isn't the hard part. Supporting all of it at the same time, forever, is what quietly eats your week.&lt;/p&gt;

&lt;h2&gt;
  
  
  So... should you build it yourself?
&lt;/h2&gt;

&lt;p&gt;If you're targeting one open network like Bluesky—absolutely, go native. The APIs are clean and you'll come out understanding the protocol properly.&lt;br&gt;
Once you add several networks, plus scheduling, media, and retries, the math flips. Not because any single request is difficult, but because maintaining six integrations is not the reason any of us got into this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;AI didn't make social media publishing easier. It just made it impossible to ignore how fragmented the whole thing already was.&lt;br&gt;
The hard part isn't generating text anymore. It's everything wrapped around it: auth, permissions, uploads, scheduling, retries, and a long tail of platform-specific edge cases.&lt;br&gt;
Whether you handle that with direct integrations or hide it behind MCP is an architectural call. Knowing where the complexity actually lives is the part worth keeping.&lt;/p&gt;




&lt;p&gt;I work on Publora, so that's the MCP server I know best—and it's open source (MIT) if you want to poke at it. But even if you never touch it, try wiring something up to Bluesky's AT Protocol, or stand up a tiny MCP server of your own. It's one of those weekend projects that makes all the trade-offs obvious by Sunday.&lt;br&gt;
What are you using to connect your agents to the outside world these days?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI, then read start to finish by an actual human—which, given the topic, felt like the least I could do.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>api</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
