<?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: Modinat Adesola</title>
    <description>The latest articles on DEV Community by Modinat Adesola (@modinat_adesola_0ea6e1d30).</description>
    <link>https://dev.to/modinat_adesola_0ea6e1d30</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3594231%2F596cdf2f-5fb2-4fbb-9531-ffe7fb25a679.png</url>
      <title>DEV Community: Modinat Adesola</title>
      <link>https://dev.to/modinat_adesola_0ea6e1d30</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/modinat_adesola_0ea6e1d30"/>
    <language>en</language>
    <item>
      <title>Integrating Mastra Agents with Telex via A2A Requests</title>
      <dc:creator>Modinat Adesola</dc:creator>
      <pubDate>Mon, 03 Nov 2025 21:26:35 +0000</pubDate>
      <link>https://dev.to/modinat_adesola_0ea6e1d30/integrating-mastra-agents-with-telex-via-a2a-requests-28h8</link>
      <guid>https://dev.to/modinat_adesola_0ea6e1d30/integrating-mastra-agents-with-telex-via-a2a-requests-28h8</guid>
      <description>&lt;p&gt;In this guide, I’ll walk you through how I integrated a Mastra AI Agent with Telex, using A2A (App-to-App) requests to enable smooth communication between the two platforms.&lt;/p&gt;

&lt;p&gt;Telex is an educational platform similar to Slack, it supports apps and agents that interact using messages.&lt;br&gt;
Mastra, on the other hand, is a modern framework for building, deploying, and scaling AI agents in production.&lt;/p&gt;

&lt;p&gt;By combining the two, we can create a setup where Telex sends structured messages to Mastra, Mastra processes them intelligently using our agent, and then sends a meaningful response back, all through JSON-RPC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Goal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our goal is to create a two-way connection where we send messages through Telex such as:&lt;/p&gt;

&lt;p&gt;“word to describe not feeling like socializing”&lt;/p&gt;

&lt;p&gt;And Mastra responds intelligently with something like:&lt;/p&gt;

&lt;p&gt;“Reclusive — Meaning: Avoiding the company of other people; solitary. This often implies a longer-term tendency.....”&lt;/p&gt;

&lt;p&gt;Stack Used:&lt;/p&gt;

&lt;p&gt;🧩 Mastra&lt;br&gt;
 – For building and hosting AI agents&lt;/p&gt;

&lt;p&gt;⚙️ Node.js + TypeScript&lt;/p&gt;

&lt;p&gt;🔗 Telex&lt;br&gt;
 – For sending JSON-RPC based A2A requests&lt;/p&gt;

&lt;p&gt;🌐 Mastra Cloud – For easy deployment and public endpoint exposure&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installing and Setting Up Mastra&lt;/strong&gt;&lt;br&gt;
Before writing any code, we’ll need to set up Mastra locally.&lt;br&gt;
You can always check the official docs here → Mastra Getting Started &lt;a href="https://mastra.ai/docs/getting-started" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 1: Create and initialize your project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir telex-mastra-agent
cd telex-mastra-agent
npm init -y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Install Mastra&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @mastra/core @mastra/agents

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you plan to you typscript (Recommended)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D typescript ts-node @types/node
npx tsc --init

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3: Define your Agent&lt;/p&gt;

&lt;p&gt;Create a file src/agents/word-agent.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Agent } from "@mastra/agents";

export const wordAgent = new Agent({
  name: "wordAgent",
  instructions: "Analyze a user's message and determine the emotional tone or meaning.",
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Understanding the A2A Request Format&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When Telex sends data to an AI agent, it follows a strict JSON-RPC 2.0 format.&lt;br&gt;
Here’s what a sample Telex request looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "jsonrpc": "2.0",
  "id": "request-001",
  "method": "message/send",
  "params": {
    "message": {
      "kind": "message",
      "role": "user",
      "parts": [
        {
          "kind": "text",
          "text": "not feeling like socializing"
        }
      ],
      "messageId": "msg-001"
    },
    "configuration": {
      "blocking": true
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is importatnt to make sure Mastra understands this format, extract the relevant message, and then send it to the agent for processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up the Custom A2A Endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mastra allows you to extend its API by registering custom routes.&lt;br&gt;
We created one called /a2a/agent/:agentId to handle requests from Telex.&lt;/p&gt;

&lt;p&gt;Here’s the full code for a2aRouter.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { registerApiRoute } from "@mastra/core/server";
import { randomUUID } from "crypto";
import { wordAgent } from "../src/mastra/agents/word-agent";

export const a2aAgentRoute = registerApiRoute("/a2a/agent/:agentId", {
  method: "POST",

  handler: async (c) =&amp;gt; {
    try {
      const mastra = c.get("mastra");
      const agentId = c.req.param("agentId");
      const body = await c.req.json();

      const { jsonrpc, id: requestId, method, params } = body || {};

      // --- Basic JSON-RPC validation ---
      if (jsonrpc !== "2.0" || !requestId) {
        return c.json(
          {
            jsonrpc: "2.0",
            id: requestId || null,
            error: {
              code: -32600,
              message:
                'Invalid Request: "jsonrpc" must be "2.0" and "id" is required',
            },
          },
          400
        );
      }

      // --- Expect only Telex's "message/send" method ---
      if (method !== "message/send") {
        return c.json(
          {
            jsonrpc: "2.0",
            id: requestId,
            error: {
              code: -32601,
              message: `Unsupported method: "${method}". Only "message/send" is allowed.`,
            },
          },
          400
        );
      }

      // --- Extract text from Telex message ---
      const userText =
        params?.message?.parts
          ?.find((p: any) =&amp;gt; p.kind === "text")
          ?.text?.trim() || "";

      if (!userText) {
        return c.json(
          {
            jsonrpc: "2.0",
            id: requestId,
            error: {
              code: -32602,
              message: 'Invalid params: "message.parts[0].text" is required',
            },
          },
          400
        );
      }

      // --- Prepare input for Mastra agent ---
      const input = {
        action: userText,
        context: userText,
      };

      // --- Resolve agent ---
      const agent =
        agentId === "wordAgent" ? wordAgent : mastra.getAgent(agentId);

      if (!agent) {
        return c.json(
          {
            jsonrpc: "2.0",
            id: requestId,
            error: {
              code: -32602,
              message: `Agent '${agentId}' not found`,
            },
          },
          404
        );
      }

      // --- Call agent ---
      let agentResponse: any;
      let agentText = "";

      if (typeof (agent as any).run === "function") {
        agentResponse = await (agent as any).run(input);
        agentText =
          agentResponse?.output?.text ??
          agentResponse?.result?.text ??
          agentResponse?.text ??
          String(agentResponse ?? "");
      } else if (typeof (agent as any).generate === "function") {
        agentResponse = await (agent as any).generate(userText);
        agentText = agentResponse?.text ?? String(agentResponse ?? "");
      } else {
        throw new Error("Agent does not support run() or generate()");
      }

      // --- Build A2A Telex-style response ---
      const taskId = randomUUID();
      const contextId = randomUUID();
      const messageId = randomUUID();

      const result = {
        id: randomUUID(),
        status: {
          state: "completed",
          timestamp: new Date().toISOString(),
          message: {
            kind: "message",
            role: "agent",
            parts: [
              {
                kind: "text",
                text: agentText,
              },
            ],
            messageId,
            taskId,
            contextId,
          },
        },
        kind: "task",
      };

      // --- Send successful JSON-RPC response ---
      return c.json({
        jsonrpc: "2.0",
        id: requestId,
        result,
      });
    } catch (error: any) {
      console.error("A2A route error:", error);
      return c.json(
        {
          jsonrpc: "2.0",
          id: null,
          error: {
            code: -32603,
            message: error?.message || "Internal server error",
          },
        },
        500
      );
    }
  },
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linking the Route to Mastra&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the mastra/index.ts, register the new route like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Mastra } from "@mastra/core/mastra";
import { PinoLogger } from "@mastra/loggers";
import { LibSQLStore } from "@mastra/libsql";

import { wordAgent } from "./agents/word-agent";
import { wordWorkflow } from "./workflows/word-workflow";
import { toolCallAppropriatenessScorer, completenessScorer } from "./scorers/word-scorer";
import { a2aAgentRoute } from "./a2aRouter";

export const mastra = new Mastra({
  workflows: { wordWorkflow },
  agents: { wordAgent },
  scorers: { toolCallAppropriatenessScorer, completenessScorer },
  storage: new LibSQLStore({ url: ":memory:" }),
  logger: new PinoLogger({ name: "Mastra", level: "info" }),
  observability: { default: { enabled: true } },
  server: {
    build: { openAPIDocs: true, swaggerUI: true },
    apiRoutes: [a2aAgentRoute],
  },
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your Mastra server will automatically expose the route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4111/a2a/agent/wordAgent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Deployment to Mastra Cloud&lt;/strong&gt;&lt;br&gt;
Once you’ve created your project and agent locally, simply push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx mastra deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After deployment, you’ll get a public URL like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://white-cloud-noon.mastra.cloud/a2a/agent/wordAgent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the endpoint you’ll register on Telex under your A2A app configuration.&lt;/p&gt;

&lt;p&gt;Now, Telex will send messages directly to your agent and receive responses in real time 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;br&gt;
Mastra Agents can be extended with custom routes to handle specialized integrations.&lt;/p&gt;

&lt;p&gt;Telex uses JSON-RPC 2.0, so your response format must be strict and well-structured.&lt;/p&gt;

&lt;p&gt;The A2A integration provides a clean, real-time bridge between conversational platforms and intelligent backend agents.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>api</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
