Resources

Architecture & implementation

How the MCP layer connects to the Caroush application, and where each part of the implementation lives.

Take the docs with youMarkdown for your editor or agent.

This guide describes the implementation in this repository. It does not mean the feature has been deployed or enabled on the live domains. Read the main guide for client setup and deployment instructions before enabling it.

Application architecture found in the audit

AreaExisting implementation
Framework/runtimeLaravel 13.14.0; PHP ^8.3; PHP 8.3 in the production Dockerfile
Web applicationReact/Inertia served by Laravel; native application routes are in the caroush.native branch of routes/console.php
Existing authenticationLaravel user authentication, session-based browser login and OAuth social account connections
Accounts/workspacesUser, Workspace, workspace_user membership and a browser-selected workspace
Subscription and creditsStripe subscription records, SubscriptionEntitlements, Billing, CreditLedger, CreditPricing; existing plan and credit checks remain authoritative
ProductsSaved product/editorial profiles, URL analysis and reusable audience context
CarouselsCarousel, CarouselContent, CarouselEngine, layered strategies, format registry, image rendering, approval and regeneration
Manual contentShared PostContent supports the existing text and stored/uploaded-media composer flows
Social publishingNative PostScheduling → Publishing → SocialPublisherManager; durable delivery rows and provider receipts
Generation automationsSeparate video and carousel definition/run services, snapshots, jobs, leases, credit reservations and publication state
Posting foldersLegacy queue folders publish existing approved drafts at configured daily/weekly slots
AnalyticsSaved platform-specific observations and snapshots for Caroush-published deliveries; daily sync jobs
StorageExisting Laravel filesystem abstraction, including configured Google Cloud Storage; stored files remain outside MCP filesystem access
Background processingDatabase queues for general work, video automation, carousel automation and mail; shared cache locks; Redis can provide configured cache/session services
Webhooks and mailExisting Stripe/social/Telegram handling and transactional mail delivery remain separate from MCP
MonitoringExisting Laravel log stack and Sentry; Mixpanel remains the separate consent-gated product analytics pipeline

Older controllers and migration-era provider code still exist in the repository. The MCP integration uses the native services. In particular, it does not publish through the older PublishScheduledPostJob, which has legacy billing behavior.

Protocol and request flow

The remote endpoint runs inside Laravel using laravel/mcp 1.0.1, the official Laravel MCP package. Protocol transport, JSON-RPC messages, initialization, version negotiation and tool discovery come from that package. Caroush does not implement a look-alike REST replacement for MCP.

Request flow through the existing Laravel application
  1. MCP client
  2. Laravel MCP HTTP endpoint
  3. Passport token and workspace grant checks
  4. Tool catalog, schemas and scopes
Immediate read
Durable mutation operationBrowser approvalWhen required by the toolExisting database queue
  1. Shared Caroush services
  2. PostgreSQL, filesystem and existing providers
View original Mermaid diagram
mermaid
flowchart TD
    Agent[MCP client] --> Endpoint[Laravel MCP HTTP endpoint]
    Endpoint --> Auth[Passport token and workspace grant checks]
    Auth --> Tools[Tool catalog, schemas and scopes]
    Tools --> Read[Immediate read]
    Tools --> Operation[Durable mutation operation]
    Operation --> Approval[Browser approval when required]
    Approval --> Queue[Existing database queue]
    Operation --> Queue
    Read --> Domain[Shared Caroush services]
    Queue --> Domain
    Domain --> Data[PostgreSQL, filesystem and existing providers]

The principal components are:

File/groupResponsibility
routes/mcp.phpProtocol, metadata, OAuth, connection-management and documentation routes
config/caroush_mcp.phpEnable flag, resource URL, issuer, documentation URL, scopes, limits and queue configuration
app/Mcp/CaroushServer.phpSDK server and scope-filtered tool discovery
app/Mcp/CaroushTool.phpSDK tool adapter
app/Mcp/ToolCatalog.phpCombines domain definitions and adds request idempotency requirements
app/Mcp/SchemaValidator.phpValidates strict JSON input and documented output schemas
app/Mcp/McpContext.phpAuthenticated user, immutable authorized workspace, grant, client and current operation context
app/Mcp/Domains/*Small adapters to existing account/content/operations services
app/Mcp/OperationService.phpOperation ledger, replay handling, approval and result persistence
app/Jobs/ExecuteMcpOperation.phpAsynchronous work with authorization rechecked at execution
app/Mcp/Auth/*Passport/League OAuth grant handling and Caroush workspace authorizations
app/Mcp/Audit.phpRequest metadata and argument names, excluding argument values
app/Http/Controllers/Mcp/*OAuth browser consent, connection management and documentation

Authentication and workspace isolation

OAuth uses Passport 13.7.6 and League OAuth2 Server 9.4.1. Supported grants are authorization code with PKCE S256 and refresh token. The current public-client registration flow uses token_endpoint_auth_method=none; it does not issue a shared Caroush API key or a client secret for desktop agents.

  1. The client reads protected-resource metadata and authorization-server metadata.
  2. It registers callback URLs when dynamic registration is enabled. HTTPS and localhost redirects use exact matching; numeric HTTP loopback redirects allow variable ports under RFC 8252. Code exchange still requires the exact redirect used during authorization.
  3. It sends the advertised resource URL, requested scopes and a PKCE challenge to the authorization endpoint.
  4. The user signs into the existing Caroush browser session, chooses a workspace and approves scopes.
  5. The client exchanges the authorization code with the PKCE verifier and matching resource URL.
  6. Subsequent MCP calls use the access token in the Authorization header.

Access tokens last one hour. Refresh tokens last 30 days and rotate after use. Workspace grants retain the user, registered client, approved scopes and exact resource URL. Revocation invalidates the grant and its associated access tokens, refresh tokens and unused authorization codes.

Account::useWorkspace() pins request-local service context. It does not alter users.current_workspace_id, so changing the browser workspace cannot silently move an MCP connection. Membership is rechecked, including when an approved background action starts. Nested records are authorized through their parent post or carousel run. MCP-owned data checks constrain both creator and workspace, including when another user's record is located in the same workspace.

Raw social-account models are never public results: their encrypted casts decrypt credentials when accessed, so serialization requires an explicit allowlist. Tool outputs omit social tokens, refresh tokens, internal provider configuration, claim tokens, raw generation snapshots and storage descriptors.

Shared services rather than duplicate implementations

The integration extracts existing controller behavior into these application services:

  • PostContent: existing content creation and deletion behavior.
  • CarouselContent: existing carousel creation/review operations.
  • PostScheduling: composer validation, destination checks, approval checks, TikTok consent validation, duplicate prevention and native publication orchestration.
  • AutomationManagement: list/run history plus lifecycle actions shared with the browser. Pausing remains possible when a product or account disappears. Deleting an automation cancels unfinished work and preserves existing publication safeguards and refunds.
  • SocialOperations: owner-scoped connected-account and delivery DTOs.
  • StoredMediaUpload: converts an owned stored media asset into a bounded temporary upload for existing CTA validators; it accepts an asset ID, never a local path or arbitrary remote URL.

Video/carousel automation saves still use their original AutomationService::save() methods. Native run requests still use Scheduler::runNow() and the same UUID occurrence ledger as the web application. Existing browser controller responses are preserved by thin service delegates.

Operations, idempotency and approval

Every mutating tool requires a UUID idempotency_key. The operation ledger is unique for authorization, tool name and key. Repeating the same request returns its existing operation; reusing the key with different arguments returns idempotency_conflict.

Publishing, scheduling, automation activation/changes/runs and deletion require approval through the authenticated Caroush browser. A tool call initially returns approval_required with an approval_url. The browser reviews the stored request; the agent cannot manufacture approval by adding approved=true or inserting instructions into content. Approval requests expire after 30 minutes by default.

Approval permits only that stored action. The queue rechecks the grant, membership and required scope before execution. If permission was revoked while work waited, the action fails without receiving new authority from the old approval.

MCP operation IDs and native automation run IDs have different meanings:

IdentifierMeaning
MCP operation UUIDAgent request/approval/background execution record; poll get_job_status
Generated post IDSaved content that can be reviewed or delivered to platforms
Carousel run IDExisting carousel generation/planning execution
Automation ID plus kindSaved video or carousel definition; their numeric IDs can overlap
Automation run ID plus kindOne native occurrence; poll get_automation_run
Schedule IDOne delivery to one connected account; read get_schedule

A successful queued request is not evidence that the resulting content exists or was published. A completed run_automation MCP request can mean its native run was accepted; continue polling the returned native run. Delivery status and confirmed platform receipts determine publication success.

If an unexpected worker failure could have happened after an external effect, the operation is marked outcome_unknown. Do not generate a fresh key and blindly retry it. Inspect Caroush and the destination platform first.

Actual social and automation capabilities

Existing publisher implementations cover Instagram, TikTok, Facebook, LinkedIn, X/Twitter, Threads and Bluesky. Platform permissions, media constraints and publication approval requirements still apply. Current image limits are Instagram 10, TikTok 35, Facebook 10, LinkedIn 20, Threads 20, X 4 and Bluesky 4; the app rejects oversized carousels instead of dropping slides.

Direct TikTok submission through generic MCP publish_post or schedule_post is intentionally rejected. The user must view that post in the Caroush composer and complete creator-specific privacy, media-preview and consent controls. Automation definitions may target TikTok, but the existing pipeline holds the completed TikTok output for per-post review.

Generation automations support:

KindExisting templatesTriggerOutput
Video2×2 grid; single fadeDaily HH:mm times in an IANA timezone; manual runGenerated portrait video and publication destinations
Video/UGCPresenter clip, written overlay, required CTA video, optional musicDaily times; manual runMerged portrait UGC video and publication destinations
CarouselIllustrated comparison; PIE editorial; relatable POVDaily times; manual runOrdered carousel slides and publication destinations

New MCP definitions are drafts. Enabling and running are separate approval-required actions. Prices come from existing runtime credit configuration: at current defaults, generated images are 5 credits each, 2×2 is 20 credits, single fade is 5 credits, and UGC automation is 10 credits. Uploaded carousel CTA artwork replaces one generated slide and reduces the generated-image charge. The credit ledger performs reservation, capture and refunds; clients cannot submit a price.

Legacy posting folders support weekly slots for existing approved drafts. They are distinct from the daily generation automation tool family. No first-class campaign model, arbitrary trigger graph, RSS/event-triggered generation or optimal posting-time predictor was found; do not describe these as available MCP tools. A folder named “Campaign” is not a campaign API.

Analytics semantics

MCP analytics read saved real snapshots and observations for posts actually delivered through Caroush. Reads do not fetch an account feed or contact providers. The existing Pro analytics entitlement applies.

The daily sync runs at 00:00 America/New_York by default. This timezone changes with New York daylight-saving time. The configured application scheduler dispatches individual jobs to the existing database queue. Each scheduled daily sync has a unique post/source/date ledger entry.

Reported metrics depend on platform and granted permissions:

PlatformExisting supported post metrics, when returned by the provider
InstagramLikes, comments, views, reach, saves, shares, reposts
FacebookReactions/likes, comments, shares, eligible Page/video views and reach
LinkedInReactions, comments, reshares, impressions, reach, clicks, eligible video views; newer member API saves/sends where available
TikTokConfirmed video views, likes, comments, shares; photo/inbox metrics may be unavailable
X/TwitterLikes, replies, reposts, quotes, bookmarks and impressions; shared-media video views are deliberately excluded
ThreadsViews, likes, replies, shares, reposts, quotes
BlueskyLikes, replies, reposts, quotes

A missing metric stays unavailable, not zero. Publication-date filtering selects a cohort of posts; headline metrics are lifetime totals at their last sync. activityTrend reports observed changes between consecutive stored observations and exposes coverage. Summing post reach does not produce unique people across posts. get_best_performing_content ranks up to five posts only where a views metric exists, preserving platform differences.

Persistence and operational boundaries

Two additive migrations create the required Passport/workspace authorization tables and MCP operation/audit tables. Application content, credit and publishing tables remain authoritative. Operation arguments and results use encrypted casts; preserve the existing APP_KEY. Browser consent nonces are hashed. Access/refresh-token persistence follows Passport/League formats; clients never receive database or platform secrets.

The SDK endpoint uses normal PHP-FPM. No additional MCP daemon, sidecar or container is required. MCP background work uses the database connection and caroush queue with the existing 1800-second worker. Video/carousel native runs then execute on their existing dedicated queues.

Audit events record user/workspace/grant/request/operation identifiers, tool name, result status, timing, error code and argument names. They do not record prompts, captions, uploaded contents, tokens or raw provider errors. Existing error reporting routes unexpected failures to Sentry. This does not add a second product-analytics SDK.

Implementation file inventory

Paths below are relative to the Laravel repository. The complete tool inventory and exact schemas are generated into catalog.json and tools.md in the documentation download.

Created

PathsPurpose
app/Mcp/CaroushServer.php, CaroushTool.php, ToolCatalog.php, SchemaValidator.php, ToolExecutor.phpProtocol adapter, catalog, validation and invocation
app/Mcp/McpContext.php, McpFailure.php, Audit.php, OperationService.php, ApprovalReview.php, Models/McpOperation.phpScoped context, safe failures, audit, durable operations and review projections
app/Mcp/Domains/CoreTools.php, ContentTools.php, OperationsTools.phpAccount, content and social/automation tool definitions
app/Mcp/Auth/OAuth configuration/provider, authorization service/model, authentication, token/code/scope repositories and encrypted token response
app/Mcp/Middleware/Enable/host/Origin checks, CORS, context binding, scopes and preserved OAuth challenges
app/Http/Controllers/Mcp/DocumentationController.php, IntegrationController.php, OAuthController.phpDocumentation, connections, browser approvals and OAuth endpoints
app/Providers/McpServiceProvider.php, routes/mcp.phpRegistration, routes and scheduled maintenance
app/Jobs/ExecuteMcpOperation.php, app/Console/Commands/McpMaintain.phpBackground execution and bounded recovery
app/Mcp/Documentation.php, app/Console/Commands/ExportMcpDocs.phpGenerated website, schemas and portable ZIP export
app/Services/Caroush/AutomationManagement.php, CarouselContent.php, ContentLibrary.php, PostContent.php, PostScheduling.php, ProductContent.php, SocialOperations.php, StoredMediaUpload.php, UgcHook.phpShared native application services and owner-scoped projections
config/caroush_mcp.php, config/passport.php, .env.exampleRuntime configuration and safe placeholders
database/migrations/2026_09_28_210000_create_mcp_oauth_tables.phpOAuth records, workspace grants and consent nonces
database/migrations/2026_09_28_211000_create_mcp_operations_tables.phpEncrypted operations and audit events
resources/views/mcp/authorize.blade.php, integration.blade.php, review.blade.php, docs.blade.php, styles.blade.phpConsent, settings, approvals and documentation UI
tests/Caroush/McpOAuthTest.php, McpProtocolTest.php, McpExecutorTest.php, McpContentToolsTest.php, McpOperationsToolsTest.php, McpDocumentationTest.php, McpApprovalReviewTest.phpProtocol, security, domain integration and UI projection coverage
docs/mcp.md, docs/mcp-architecture.md, docs/mcp-deployment.mdDeveloper reference, architecture and deployment handover

Modified

PathsChange
composer.json, composer.lockLocked Laravel MCP, Passport and JSON Schema dependencies
bootstrap/providers.php, config/auth.php, app/Models/User.phpRegister MCP/OAuth and support Passport without replacing browser authentication
app/Services/Caroush/Account.phpPin request-local authorized workspace context
app/Http/Controllers/Caroush/CarouselController.php, PostController.php, ProductController.php, UgcVideoController.phpDelegate existing behavior to shared services
app/Services/Caroush/CarouselAutomation/AutomationController.php, app/Services/Caroush/VideoAutomation/AutomationController.phpShare lifecycle handling with MCP
app/Support/SentrySanitizer.php, tests/Caroush/SentrySanitizerTest.phpFilter MCP/OAuth/queued-operation payloads from error telemetry
resources/js/app/(app)/settings/settings-client.tsxLink to AI connections
Dockerfile.coolify, Dockerfile.coolify.dockerignoreInclude maintained documentation in the runtime image
.gitignorePermit the safe environment example while keeping private configuration excluded
public/build/manifest.json, public/build/assets/*Rebuilt frontend assets for the settings change

Private .env and .env.production files were not changed. The populated application database and production configuration were not migrated or modified during implementation; automated migration checks ran against isolated test databases.