Last updated: August 31, 2026

Give a Mastra agent a Twitter tool

Point Mastra MCPClient at mcp.opentweet.io/mcp and your agent gets 36 typed tools for posting, scheduling, threads, articles, and analytics on X. Prefer a narrow contract? Wrap the REST endpoint in createTool with a zod schema. No X developer account either way.

Mastra is a TypeScript framework people put in production, so the two things that matter here are typed tool schemas and behaviour across restarts. The hosted server is stateless, which means no MCP session to lose on a cold start.

7-day free trial. No X developer account needed.

What your Mastra agent can do on X

Take the whole toolset over MCP, or expose exactly one action.

Post now

opentweet_create_tweet publishes when the agent decides to.

Schedule

opentweet_schedule_tweet and opentweet_batch_schedule queue work and let the process exit.

Threads and articles

opentweet_create_thread and opentweet_create_article for long-form output.

Typed tools

MCPClient hands Mastra the schemas, so your agent gets typed arguments without you writing them.

Analytics

Feed results back into the next workflow run.

Stateless

No MCP session to lose across a serverless cold start or a deploy.

Option 1: MCPClient, all 36 tools

One server entry, one call to getTools, and the agent can post, schedule, batch schedule, thread, and read its own analytics. The key lives in the request headers, so it never enters the model context.

src/mastra/agents/x-agent.ts
import { Agent } from "@mastra/core/agent";
import { MCPClient } from "@mastra/mcp";
import { openai } from "@ai-sdk/openai";

const mcp = new MCPClient({
  servers: {
    opentweet: {
      url: new URL("https://mcp.opentweet.io/mcp"),
      requestInit: {
        headers: { Authorization: `Bearer ${process.env.OPENTWEET_API_KEY}` },
      },
    },
  },
});

export const xAgent = new Agent({
  name: "x-poster",
  instructions: "You publish, schedule, and thread on X for the team. Prefer scheduling over posting now unless told otherwise.",
  model: openai("gpt-4o"),
  tools: await mcp.getTools(),
});

Every tool name and argument is in the MCP docs.

Option 2: createTool over the REST API

When the agent should be able to do exactly one thing, define that one thing. A zod input schema, a fetch, and an error you can read in a log.

src/mastra/tools/post-to-x.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";

export const postToX = createTool({
  id: "post-to-x",
  description: "Publish a post to X, or schedule it for a future time.",
  inputSchema: z.object({
    text: z.string().max(25000),
    scheduledDate: z.string().datetime().optional(),
  }),
  execute: async ({ context }) => {
    const body = context.scheduledDate
      ? { text: context.text, scheduled_date: context.scheduledDate }
      : { text: context.text, publish_now: true };

    const res = await fetch("https://opentweet.io/api/v1/posts", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.OPENTWEET_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    if (!res.ok) throw new Error(`OpenTweet ${res.status}: ${await res.text()}`);
    return res.json();
  },
});

Pick the narrow tool when the agent is autonomous

A supervised agent benefits from the full toolset. An unattended one usually should not have delete_tweet or update_evergreen_settings within reach. Scoping the tool is cheaper than scoping the prompt.

The REST fallback, outside the framework

The same endpoint your createTool calls works from anywhere: a cron job, a webhook handler, a deploy script.

post.sh
curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -d '{"text":"The workflow wrote this, the scheduler sent it.","scheduled_date":"2026-09-02T09:00:00Z"}'

The route is /api/v1/posts, not /api/v1/tweets. Full reference in the API docs, and see post to Twitter from Node for the plain TypeScript version.

Good fits

Content workflows with a review step

A Mastra workflow drafts, a human approves in your own UI, and the approved item is scheduled through one tool call.

Product changelog agents

Read the release, write the post, queue it for a working hour rather than the deploy time.

Multi-account teams

Every posting tool takes x_account_id, so one key drives several X accounts from one deployment.

Serverless deployments

A stateless MCP endpoint plays well with functions that get recycled between invocations.

Other frameworks: Vercel AI SDK, LangGraph, Pydantic AI, OpenAI Agents SDK.

Frequently asked questions

How does a Mastra agent post to X?

Two ways. Create an MCPClient with a server entry pointing at https://mcp.opentweet.io/mcp and pass await mcp.getTools() into your Agent, which gives it all 36 OpenTweet tools. Or wrap the REST endpoint in a createTool definition when the agent only needs to publish one kind of thing.

MCPClient or createTool, which should I use?

MCPClient when you want the surface: scheduling, batch scheduling, threads, articles, evergreen, and analytics arrive with no tool code. createTool when you want a narrow, typed contract the model cannot misuse, for example a single publish action with a zod schema you control.

Does the OpenTweet MCP server work with Mastra in production?

It is a Streamable HTTP endpoint with bearer auth, which is the shape Mastra MCPClient is built for. It runs stateless, so there is no session to lose across a serverless invocation or a rolling deploy, which matters if your Mastra app runs on a platform that recycles instances.

Do I need an X developer account?

No. OpenTweet holds the X connection, OAuth, and token refresh. Your Mastra app carries one ot_ bearer key. You never register an X developer app, and you never pay the X pay-per-use rates of $0.015 per post or $0.20 per post containing a link.

Can a Mastra workflow schedule posts instead of publishing immediately?

Yes. Call opentweet_schedule_tweet with an ISO 8601 time, or opentweet_batch_schedule to queue many at once. Over REST, send scheduled_date in place of publish_now. The queue runs on OpenTweet servers, so a workflow can queue a week of posts and exit.

How do I keep the API key out of the agent context?

Put it in the transport, not the prompt. With MCPClient the key lives in the request headers, and with createTool it lives in the function body reading process.env. The model never sees it either way, which is what you want when tool arguments are logged.

What does it cost?

Pro is $11.99/month with the API included and a 7-day free trial. Advanced is $29 and Agency is $49 for teams running several X accounts through one key.

Ship a Mastra agent that posts to X

One MCPClient entry, or one createTool. Both take about five minutes.

$11.99/month, API included. Cancel anytime.