Your last MCP to schedule all your social posts! 🀯
Nevo David

Nevo David @nevodavid

About: Founder of Postiz, an open-source social media scheduling tool. Running Gitroom, the best place to learn how to grow open-source tools.

Joined:
Feb 23, 2022

Your last MCP to schedule all your social posts! 🀯

Publish Date: Apr 15
303 27

MCP is the future

I'm pretty addicted to the Last Of Us series, Sorry about the cover πŸ˜‰
MCPs are everywhere and for a good reason.
It's the next step in the evolution of apps.

Being able to use everything from a single chat without accessing any app.
It feels native for Postiz to schedule all your social posts from the chat!
So, I started to dig into the Postiz code and add it!

MCPE


MCP repository is a bit weird 🧐

Each MCP has a transport, which is the method the LLMs use to talk to our system.

There are two primary methods at the moment: Stdio, which is basically a command line, and SSE.

I don't really understand why they chose SSEβ€”it's basically a long request that never ends and streams events to the client.

The problem with this method is that to send information back to the server, you must send another post request (as SSE is a one-way communication), which means you must hold the state.

In their example, they hold the state in the app's memory, and guess what? Many complain about memory leaks because the state is not erased when the user disconnects.

I would use WebSockets. They have a built-in sleep mode, and you don't have to maintain a state for it.


Digging in πŸͺ 

I dug into Anthropic typescript SDK and was not amazed.
It feels clunky. Many things are not being used in production, like "Resources." The way they require you to keep everything globally in memory is a disaster waiting to come.

Also, it is tough to implement authentication and get the user from the context so we can get their details.

I implemented my own "Transport" using rxjs observables - it's fun. Postiz is built with NestJS, so when using an SSE route, it closes the observable once it disconnects, allowing you to remove everything from memory.

import EventEmitter from 'events';
import { finalize, fromEvent, startWith } from 'rxjs';

@Injectable()
export class McpService {
  static event = new EventEmitter();
  constructor(
    private _mainMcp: MainMcp
  ) {
  }

  async runServer(apiKey: string, organization: string) {
    const server = McpSettings.load(organization, this._mainMcp).server();
    const transport = new McpTransport(organization);

    const observer = fromEvent(
      McpService.event,
      `organization-${organization}`
    ).pipe(
      startWith({
        type: 'endpoint',
        data: process.env.NEXT_PUBLIC_BACKEND_URL + '/mcp/' + apiKey + '/messages',
      }),
      finalize(() => {
        transport.close();
      })
    );

    console.log('MCP transport started');
    await server.connect(transport);

    return observer;
  }

  async processPostBody(organization: string, body: object) {
    const server = McpSettings.load(organization, this._mainMcp).server();
    const message = JSONRPCMessageSchema.parse(body);
    const transport = new McpTransport(organization);
    await server.connect(transport);
    transport.handlePostMessage(message);
    return {};
  }
}
Enter fullscreen mode Exit fullscreen mode

Decorators FTW πŸŽ–οΈ

This is for you if you are a big fan of OOP frameworks like NestJS / Laravel / Spring. I created a cool decorator to create tools like API "endpoints."

  @McpTool({ toolName: 'POSTIZ_GET_CONFIG_ID' })
  async preRun() {
    return [
      {
        type: 'text',
        text: `id: ${makeId(10)} Today date is ${dayjs.utc().format()}`,
      },
    ];
  }

  @McpTool({ toolName: 'POSTIZ_PROVIDERS_LIST' })
  async listOfProviders(organization: string) {
    const list = (
      await this._integrationService.getIntegrationsList(organization)
    ).map((org) => ({
      id: org.id,
      name: org.name,
      identifier: org.providerIdentifier,
      picture: org.picture,
      disabled: org.disabled,
      profile: org.profile,
      customer: org.customer
        ? {
            id: org.customer.id,
            name: org.customer.name,
          }
        : undefined,
    }));

    return [{ type: 'text', text: JSON.stringify(list) }];
  }

@McpTool({
    toolName: 'POSTIZ_SCHEDULE_POST',
    zod: {
      type: eenum(['draft', 'scheduled']),
      configId: string(),
      generatePictures: boolean(),
      date: string().describe('UTC TIME'),
      providerId: string().describe('Use POSTIZ_PROVIDERS_LIST to get the id'),
      posts: array(object({ text: string(), images: array(string()) })),
    },
  })
  async schedulePost(
    organization: string,
    obj: {
      type: 'draft' | 'schedule';
      generatePictures: boolean;
      date: string;
      providerId: string;
      posts: { text: string }[];
    }
  ) {
    const create = await this._postsService.createPost(organization, {
      date: obj.date,
      type: obj.type,
      tags: [],
      posts: [
        {
          group: makeId(10),
          value: await Promise.all(
            obj.posts.map(async (post) => ({
              content: post.text,
              id: makeId(10),
              image: !obj.generatePictures
                ? []
                : [
                    {
                      id: makeId(10),
                      path: await this._openAiService.generateImage(
                        post.text,
                        true
                      ),
                    },
                  ],
            }))
          ),
          // @ts-ignore
          settings: {},
          integration: {
            id: obj.providerId,
          },
        },
      ],
    });

    return [
      {
        type: 'text',
        text: `Post created successfully, check it here: ${process.env.FRONTEND_URL}/p/${create[0].postId}`,
      },
    ];
  }
Enter fullscreen mode Exit fullscreen mode

All the code can be found in Postiz here:
https://github.com/gitroomhq/postiz-app/tree/main/libraries/nestjs-libraries/src/mcp

And here:
https://github.com/gitroomhq/postiz-app/tree/main/apps/backend/src/mcp


Force the LLM to do stuff πŸ’ͺ🏻

It would be nice to have a built-in option to force the LLM to do different stuff before it accesses our stuff.

I faced some interesting problems. Whenever I told Cursor to schedule a post for me, it tried to schedule it for 2024. This is the last time the model was trained.

I needed to pass some config details, so I created the POSTIZ_CONFIGURATION_PRERUN tool. Hopefully, the LLM will always call it before doing stuff.

But it ignored it many times (typical), so I had to be creative.
In my POSTIZ_SCHEDULE_POST, I added a new property called configId and changed the config tool name to POSTIZ_GET_CONFIG_ID, the output of the config is:
id: ${makeId(10)} Today date is ${dayjs.utc().format()}

It forced the LLM always to call it before, and the date was fixed! :)

It was even better for me because I knew it would send me UTC dates from now on.


Use-cases

I think that it works best when it is combined with multiple sets of tools, for example:

  • Connect it to Cursor and ask it to schedule a post about your work today.

  • Connect it to Notion and ask to schedule all the team's latest work on social media - check out Composio MCPs.

  • Connect it to any SaaS that has CopilotKit and schedule posts based on the app.


Postiz MCP

Postiz is the most robust open-source social media scheduling tool - and now the only scheduler that offers MCP (natively, not with Zapier or something like that)

With the new MCP, you can schedule all your posts from Cursor / Windsurf and Anthropic clients.

Everything is 100% free, of course :)

If you like it, please don't forget to star us ⭐️
https://github.com/gitroomhq/postiz-app

OG

Comments 27 total

  • Yonatan Lavy
    Yonatan LavyApr 15, 2025

    Very cool and useful MCP! I'll try using it to send social media updates on the tasks I complete, do you think it will work well?

    And thank you for sharing your implementation details and struggles, very informative for when I'll make my own MCP for Dotallio.com !
    (Though I wish I had those cool decorators in nextjs as well haha)

    • Nevo David
      Nevo DavidApr 15, 2025

      Well MCP is the thing right now, so I am sure!

      • TikTok Download Bonus!
        TikTok Download Bonus!Apr 15, 2025

        πŸš€ Check Reward: 5000 Points On TikTok Download Bonus! πŸŽ‰
        Want to earn 5000 FREE points on TikTok just by downloading an app? πŸ€‘ This limited-time bonus is the easiest way to boost your TikTok rewards!

        πŸ‘‰ Click Here to Claim Your 5000 Points Now! πŸ‘ˆ

  • William
    WilliamApr 15, 2025

    MCP FTW!!

  • Arindam Majumder
    Arindam Majumder Apr 15, 2025

    This is soo cool

    I'm working on a playlist using MCPs

    I'll give it a try

  • πš‚πšŠπšžπš›πšŠπš‹πš‘ πšπšŠπš’
    πš‚πšŠπšžπš›πšŠπš‹πš‘ πšπšŠπš’Apr 15, 2025

    Really awesome @nevodavid I'm gonna plug into my Claude Desktop and try it out!

  • TikTok Download Bonus
    TikTok Download BonusApr 15, 2025

    πŸš€ Check Reward: 5000 Points On TikTok Download Bonus! πŸŽ‰
    **
    Want to earn **5000 FREE points
    on TikTok just by downloading an app? πŸ€‘ This limited-time bonus is the easiest way to boost your TikTok rewards!

    πŸ‘‰ Click Here to Claim Your 5000 Points Now! πŸ‘ˆ

  • tim brandom
    tim brandomApr 16, 2025

    Cool stuff!

  • Athreya aka Maneshwar
    Athreya aka ManeshwarApr 16, 2025

    Awesome feature @nevodavid :)

  • johny walker
    johny walkerApr 16, 2025

    Awesome!

  • Henry Willz
    Henry WillzApr 16, 2025

    Pretty awesome, I want to try to connect it to a Figma MCP to document my work.

  • Nathan Tarbert
    Nathan TarbertApr 16, 2025

    Really awesome article!

  • Animesh Pathak
    Animesh PathakApr 23, 2025

    This is next-level stuff πŸ”₯ @nevodavid ! excited to try it out!!

  • Bap
    BapApr 23, 2025

    MCP to the moon!

  • εΌ ζ–‡θΆ…
    εΌ ζ–‡θΆ…Apr 25, 2025

    Fantastic breakdown of the MCP implementation challenges! As someone exploring AI-powered automation, your rxjs transport solution is incredibly clever. I've been comparing different MCP server list options for my own projects, and your approach to solving the memory leak issue is exactly what I needed. Will definitely be starring Postiz on GitHub!RetryClaude can make mistakes. Please double-check responses.

  • Ultimate HTML To PDF Converter
    Ultimate HTML To PDF ConverterApr 28, 2025

    πŸ‘‰ Need to turn your web page into a clean, professional PDF? Try our HTML to PDF converter – it's fast, easy, and totally free to use! Click here to get started! πŸš€

  • Armon B
    Armon BMay 1, 2025

    Love this - wonder if you're building any open source agent that could potentially be uploaded to airies. Would love to chat!

  • zaheetdev
    zaheetdevMay 12, 2025

    this is really good! Im gonna try it

  • chl
    chlMay 16, 2025

    Hi @nevodavid, I really appreciated your post on this MCP. I’m currently deep in a similar challenge around forcing the LLM to do what I want, and it’s helpful to see others thinking out loud about it. Would love to hear more about your approach, if you’re open to it.

  • Marlene
    Marlene May 16, 2025

    Awesome πŸ‘Œ did you receive the Palliative updates for 2025

  • Vijay Kumar
    Vijay KumarJun 8, 2025

    Great !

  • DevOps Fundamental
    DevOps FundamentalJun 28, 2025

    This was such a well-written and thoughtful postβ€”I really enjoyed the way you explained your ideas and offered a fresh perspective. Looking forward to reading more from you!

Add comment