August 27, 2026
How I Built Postavel: From Publish Everywhere to an MCP-Native Social Media Tool
By Vladimir Nikolic

August 27, 2026
By Vladimir Nikolic

I did not start Postavel because I wanted to build another social media management product. I started it because I was not publishing enough about the products I was already building.
I had Coding Wisely projects to promote, community work around Laravel Serbia, and my wife’s Thai massage salon. Publishing consistently meant writing short posts in English, adapting them for several networks, finding or creating images, and then opening each platform separately. I did not have enough time for that process. I also did not feel that my English was strong enough to write good short-form content quickly.
The obvious alternative was to hire someone or work with an agency. Coding Wisely could not justify that additional expense, so I decided to build the tool I needed.
My first requirement sounded simple: write one post and publish it everywhere.
That requirement did not survive contact with the APIs.
At first, I treated social networks as different destinations for the same payload. I soon learned that they are different publishing systems with different content models, terminology, authorization rules, media requirements, limits, and failure modes.
Some of the differences are basic but still affect the entire design:
| Platform | Text and media constraints in Postavel |
|---|---|
| X | 280 characters, up to four images or one video |
| Bluesky | 300 characters, text required, up to four images or one video |
| 500 characters, one image, no video | |
| Media required; feed, story, and reel formats; up to ten images or one video | |
| TikTok | Video-only publishing model |
| YouTube | Video required, with a separate title, description, tags, category, privacy state, and audience metadata |
| Feed publishing, with different rules for member and organization destinations | |
| Feed, story, reel, image, and video flows through different Graph API endpoints |
Media made the problem more complicated. A post containing both images and video cannot be sent unchanged to every destination. Some networks accept a carousel, some prefer or require video, and some accept only one image. A cross-platform reel also needs to become a regular feed post on networks that do not have a corresponding reel format.
I eventually stopped thinking in terms of copying a post. Postavel now treats the user’s text as master content and creates a platform-specific delivery plan. The plan decides which text, post type, account, and media are valid for each destination.
That is also why AI became part of the product. It was not added only to generate generic marketing copy. It was needed to transform one idea into several valid versions while preserving the original meaning.
Postavel currently uses separate platform prompts and validation rules. An Instagram version can use line breaks and a small set of relevant hashtags. LinkedIn receives a more professional version. X and Bluesky must fit hard character limits. Pinterest copy is written for searchability without hashtags. YouTube receives structured metadata rather than only a caption.
The AI output is not trusted blindly. Postavel validates it after generation. If a result exceeds a platform limit, it retries with a stricter instruction. If it is still too long, it truncates at a sentence boundary. The same platform requirements are used by the web composer, the validation service, and the MCP tools so that they do not gradually develop different rules.
I started with a fresh Laravel 12 application and chose the Livewire ecosystem. The project currently uses Laravel 12, Livewire 3, Filament 4, Flux UI, Volt, Tailwind CSS 4, and Pest 4.
Part of the motivation was technical curiosity. The Laravel and Filament ecosystem was moving quickly, and I wanted to learn the newer versions by building a real product rather than a demonstration application.
I built the application myself. Ivana Nikolić, our in-house designer, created the logo and occasionally suggested small UI improvements, but the application architecture and implementation remained my responsibility.
I also used several AI coding tools during development. I do not remember one tool dominating the beginning; I used a mixture of what was available. At that time, the models hallucinated much more than they do now. I did not delegate architecture to them. I defined the structure and used AI mainly to implement bounded pieces and write Pest tests around the behavior I wanted.
That distinction was important. An AI assistant was useful when the task had explicit boundaries: this service receives a publication, this API call must be faked, these status transitions must be tested. It was much less reliable when asked to infer how an undocumented third-party API should behave.
The first version did not begin with a complete agency data model. I only needed a place where I could publish my own content.
Then I wanted my wife to manage her massage salon inside my account without mixing it with Coding Wisely. That led to the idea of multiple clients and brands. From there, it became clear that the same model could support an agency managing many clients, while each client could have several brands.
The hierarchy became:
Workspace
└── Client
└── Brand
├── Social accounts
├── Posts
└── Media
This structure now also supports team roles, brand assignments, client approvals, tone of voice, target audience, brand colours, preferred hashtags, and separate social destinations.
I did not design all of that before writing the first line of code. It emerged from using the product and recognizing that “my account” was the wrong boundary. The real boundary was the brand whose content, identity, accounts, and approval rules had to remain consistent.
One of the most important architectural decisions was to stop treating a multi-platform post as a single publishing operation.
A Post describes the user’s intention. Postavel then creates one PostPublication for every selected social account. Each publication has its own platform, status, external identifier, URL, retry count, error, and timestamps.
Conceptually, the dispatcher does this:
foreach ($targetAccounts as $account) {
PostPublication::firstOrCreate([
'post_id' => $post->id,
'social_account_id' => $account->id,
]);
}
Every publication is processed as a separate queued job. Facebook can succeed while Instagram fails. The parent post can represent partial success without losing the error attached to one destination.
The publishing job uses a dedicated publisher for each platform. It prevents overlapping execution, checks whether the account is still publishable, applies retry rules, records detailed publishing logs, and marks authentication failures as needs_reconnection. It does not retry authentication errors as though they were temporary network failures.
This per-platform model also prevents a dangerous shortcut: setting the post-level status to published is not proof that anything was published. Postavel considers a destination successful only when its publication record contains the result returned by the external platform.
YouTube required an additional workflow. A scheduled video is uploaded privately in advance. At the scheduled time, Postavel changes its visibility instead of starting a large upload at the exact publication time. This reduces the chance that a slow upload will make the post late.
Facebook video publishing has another multi-stage flow. Postavel first attempts the Reels resumable-upload protocol: initialize an upload session, upload the binary data, and finalize the reel. If that path fails, it can fall back to the standard video endpoint.
These are examples of why a generic publish($payload) abstraction is not sufficient. The common interface is small; the platform implementations remain deliberately specific.
The first working publication took a few weeks to build. Getting production access took longer because the APIs were only one part of the work. The review systems controlled whether real users could connect their accounts.
Meta’s review process was the closest I came to abandoning Postavel.
The documentation was difficult to follow, permissions overlapped or changed, and every requested permission needed a concrete justification, a working production flow, a reviewer account, test assets, written instructions, and a screencast showing the feature in use.
At one stage, the application requested 13 Meta permissions across authentication, Facebook Pages, Business Manager, Instagram publishing, and analytics. I removed another ten permissions because the product did not actively use them. Requesting permissions for possible future features only made the review harder.
The final review package documented where each permission was used in the code and how a reviewer could verify it. It included a Facebook test account, a test Page, an Instagram professional account linked to that Page, production credentials for Postavel, expected results, and troubleshooting instructions.
AI helped me complete this process. It was useful for comparing the implementation with Meta’s requirements, reducing the permission set, and preparing the submission material. I do not remember which particular model I used at that point, but without that assistance I might not have finished the review.
Google’s YouTube review was more structured. Postavel requested sensitive scopes for uploading videos, reading channels, managing uploaded-video metadata, and retrieving analytics. I created a dedicated reviewer account and explicitly exempted it from the normal free-trial expiration, because a reviewer must still be able to enter the application when the submission reaches the front of the queue.
The submission also required a verified domain, a matching OAuth consent screen, a privacy policy covering Google user data, and a video demonstrating each requested scope. Google approved the application after approximately two weeks.
That experience changed how I view integrations. The code that calls an API may be a small part of the total implementation. Production access, test identities, token lifecycle, platform policy, reviewer communication, and evidence are part of the feature.
The largest conceptual change came when Laravel released its MCP package and AI SDK.
Until then, Postavel was a web application with AI-assisted content features. MCP made it possible for ChatGPT, Claude, and other compatible clients to use Postavel as an external system. The conversational interface could prepare content, but Postavel would remain responsible for identity, permissions, validation, approvals, media storage, scheduling, and reliable publishing.
The first end-to-end MCP use case was a post for the Thai massage salon. I asked ChatGPT to create content for Facebook and Instagram. It generated the copy and created the post in Postavel without requiring me to open the Postavel interface.
At that time it could not upload the image. I added media support in later updates.
The Postavel MCP server now exposes 26 tools. They cover:
The most useful part is not the number of tools. It is the workflow encoded in the server instructions.
Before generating content, an MCP client must request the brand context. That response contains the description, tone of voice, target audience, brand colours, preferred hashtags, connected accounts, and current platform rules. The assistant is instructed not to invent missing brand attributes.
The intended flow is:
This separation matters because an LLM should not be able to turn a vague discussion into a live social post without an explicit approval step.
Images exposed a practical limitation of MCP clients: they do not all provide files in the same way.
Postavel now supports several transfer paths:
For generated media, the tool returns a preview and marks review as required. The MCP client must show the image and proposed copy before it creates the draft. It must also avoid claiming that an attachment was uploaded until a Postavel media tool has actually succeeded.
Media is then routed independently for each target. Order is preserved, platform limits are applied, and unsupported media is skipped for a destination rather than silently breaking every publication.
Pest is the basis of the test suite. External HTTP calls are isolated with Laravel’s HTTP fakes, while feature tests cover the workflows around authentication, platform validation, media handling, scheduling, approval, publishing, retries, partial failure, and MCP tools.
The production application is managed through Laravel Forge and deploys automatically from the repository. It uses MySQL for application data, Redis for queues, S3-compatible object storage for media, Resend for email, OpenAI for content adaptation and image generation, and Laravel Cashier for subscriptions.
Laravel Scheduler checks for due posts every minute. It also runs token refresh, expiring-account checks, analytics collection, storage checks, and cleanup of temporary MCP uploads. The scheduler identifies work; queue workers execute each platform publication independently.
That division keeps scheduled execution short and makes failures observable. It also allows expensive work, such as video processing or a YouTube upload, to have its own lifecycle rather than blocking the scheduler.
I use Postavel in production for Coding Wisely projects and for the Laravel Serbia accounts on X and Facebook. It is also used outside my own projects.
We have also produced a short tutorial series with AI that follows the Postavel workflow from beginning to end. It covers creating and verifying an account, setting up a workspace, client, and brand, connecting social accounts, adapting content for each platform, handling approvals, scheduling posts, publishing, and checking the final publication status. The complete series is available on the Postavel YouTube channel. Product updates and new tutorials are also published on LinkedIn and X.
The product has moved well beyond my initial requirement, but the original problem remains the same. Small businesses and individuals often have something worth publishing and no dedicated person to turn it into platform-specific content consistently.
Postavel’s web interface remains important for calendars, review, account management, and visibility. MCP provides another interface: I can describe what I need in a conversation, let the assistant read the relevant brand rules, review the proposed result, and then use Postavel as the controlled execution system.
That MCP integration is probably the part I am most proud of. It connects the reason I started the project with the architecture it eventually required. I wanted to spend less time opening social networks and rewriting the same idea. Now I can start with that idea in a conversation while Postavel handles the parts that should remain deterministic: context, permissions, validation, approval, scheduling, and delivery.
Ready to take the next step? Let's work together to transform your ideas into reality. Contact us today to discuss how we can help you create impactful, user-centered solutions that drive success.
Contact Us