Introduction
As part of an assignment to integrate AI agents with Telex.im, an AI-augmented chat platform that also serves as a Slack alternative for education, communities, and bootcamps. I set out to build something simple yet useful: an agent that fetches Google Play Store app ratings on demand. The requirements were straightforward - create an agent that could look up data from an API. What started as a simple idea turned into a fascinating journey through the Mastra framework and the A2A protocol.
In this post, I'll walk you through the entire process - from initial setup to deployment and integration with Telex.im, including the challenges I faced and how I solved them.
π Try the live agent: PlayStore Rating Agent on Telex.im - Ask it about any Android app and get instant ratings, install counts, reviews, and developer information from the Google Play Store.
The Vision
- Before diving into code, I needed to define what success looked like:
- On-Demand Lookup: Users should be able to ask "What's the rating for Instagram?" and get instant, detailed results
- Rich Information: Beyond just ratings, provide installs, reviews, developer info, and more
- Seamless Integration: Work perfectly with Telex.im using the A2A protocol
Getting Started with Mastra
Initial Setup
The Mastra CLI made getting started incredibly smooth. I ran:
npm create mastra@latest -y The wizard walked me through setup, asking for:
- Project name: playstore-rating-agent
- Model provider: I chose Google Gemini 2.0 Flash (no credit card required!) and added my API key
- Example setup: Started with the weather agent template
Within minutes, I had a working project structure:
src/ βββ mastra/ β βββ agents/ β β βββ weather-agent.ts β βββ tools/ β β βββ weather-tool.ts β βββ workflows/ β β βββ weather-workflow.ts β βββ scorers/ β β βββ weather-scorer.ts β βββ index.ts βββ .env.example βββ package.json βββ tsconfig.json What Worked: The CLI's project scaffolding gave me a perfect template to adapt. Having real, working examples made understanding the framework much easier.
Mastra Features I Used
Throughout this project, I leveraged several key Mastra features that made development smooth and efficient:
1. Mastra Agents
The core feature I used was Mastra's Agent system. Agents in Mastra are AI-powered entities that can understand user queries, make decisions, and execute tools. My playStoreAgent was configured with:
- Custom instructions defining its behavior and personality
- Integration with Google Gemini 2.0 Flash model
- Access to custom tools for fetching Play Store data
- Built-in memory for maintaining conversation context
2. Mastra Tools
I created a custom tool using Mastra's createTool function. Tools are the actions your agent can perform. Key features I used:
- Zod Schema Validation: Both input and output schemas with type safety
- Async Execution: Native support for async operations like API calls
- Error Handling: Built-in error propagation and handling
- Type Inference: Automatic TypeScript types from Zod schemas
3. Mastra Memory
The Memory feature allowed my agent to remember previous conversations using LibSQLStore:
- Persistent conversation history across sessions
- Automatic context management
- Easy retrieval of past interactions
- Built-in storage adapters (I used LibSQLStore with SQLite)
4. Mastra Server & API Routes
- Mastra's server capabilities made integration straightforward:
- Built-in OpenAPI documentation generation
- Swagger UI for testing endpoints
- Custom route registration with registerApiRoute
- JSON-RPC 2.0 support for A2A protocol compliance
5. Mastra Logger
- The PinoLogger integration provided excellent observability:
- Structured logging with configurable levels
- Request/response tracking
- Error logging with stack traces
- Performance monitoring
6. Mastra Bundler Configuration
I used the bundler settings to handle external dependencies:
bundler: { externals: ["google-play-scraper"], } This ensured the google-play-scraper package was properly handled during deployment.
Building the Core Components
1. The Play Store Scraping Tool
My first task was creating a tool that could actually fetch app data. I installed google-play-scraper:
pnpm add google-play-scraper Then adapted the weather tool template to create playstore-tool.ts:
export const playStoreRatingTool = createTool({ id: 'get-playstore-rating', description: 'Get current ratings and information for an app from Google Play Store', inputSchema: z.object({ appName: z.string().describe('Name of the app to search for'), }), outputSchema: z.object({ appId: z.string(), title: z.string(), rating: z.number(), ratingsCount: z.number(), reviews: z.number(), installs: z.string(), price: z.union([z.string(), z.number()]), developer: z.string(), lastUpdated: z.string(), version: z.string(), url: z.string(), }), execute: async ({ context }) => { // Search and fetch app details const searchResults = await gplay.search({ term: context.appName, num: 1, }); const appDetails = await gplay.app({ appId: searchResults[0].appId }); return { // ... formatted app data }; }, }); 2. Creating the Agent
Next, I created playstore-agent.ts by adapting the weather agent:
export const playStoreAgent = new Agent({ name: 'PlayStore Rating Agent', instructions: ` You are a helpful assistant that provides Google Play Store app ratings and information. Your primary function is to help users get app ratings and details from the Google Play Store. // ... detailed instructions `, model: 'google/gemini-2.0-flash', tools: { playStoreRatingTool }, memory: new Memory({ storage: new LibSQLStore({ url: 'file:../mastra.db', }), }), }); What Worked: Mastra's Memory system worked out of the box. The agent could remember previous conversations seamlessly.
What Didn't (The Big Issue): My agent was returning raw JSON to users! Instead of a nice formatted message, users saw:
{"type":"tool-result","runId":"d880b4a8-a8d5-49db-bee9-316e70f38e7f"...} This was messy and unprofessional. I realized the agent instructions needed to be much more explicit about formatting.
3. Fixing the Formatting Issue
I updated the agent instructions with very specific formatting guidance:
instructions: ` // ... previous instructions - IMPORTANT: Format the response in a clean, readable way. DO NOT include raw JSON or tool output. - Present the information like this: [App Name] has a rating of [X.X]/5.0 with [number] total ratings. It has been installed [installs] times and was last updated on [date]. The current version is [version] and it is offered for [price] by [developer]. - Keep responses natural and conversational - Never show the raw tool results or JSON data to the user `, What Worked: Being explicit in the instructions solved the problem completely. The agent now formats responses beautifully:
"WhatsApp Messenger has a rating of 4.39/5.0 with 212,153,070 total ratings. It has been installed 10,000,000,000+ times and was last updated on 2025-10-29. The current version varies and it is offered for free by WhatsApp LLC."
Lesson Learned: AI agents need very explicit instructions. Don't assume they'll figure out formatting on their own.
The A2A Protocol Integration
This was the most crucial part - making the agent work with Telex.im, a Slack alternative for communities that also functions as an AI agent platform like Make.
Understanding A2A
The A2A (Agent-to-Agent) protocol is based on JSON-RPC 2.0. It standardizes how agents communicate, ensuring:
- Consistent message formats
- Proper context management
- Structured artifacts and results
- Standard error handling
- Creating the A2A Route Handler
I created a2a-agent-route.ts to bridge Mastra with the A2A protocol, using Mastra's registerApiRoute feature:
export const a2aAgentRoute = registerApiRoute('/a2a/agent/:agentId', { method: 'POST', handler: async (c) => { const body = await c.req.json(); const { jsonrpc, id: requestId, method, params } = body; // Validate JSON-RPC 2.0 format 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); } // Convert A2A messages to Mastra format const mastraMessages = messagesList.map((msg) => ({ role: msg.role, content: msg.parts?.map((part) => { if (part.kind === 'text') return part.text; if (part.kind === 'data') return JSON.stringify(part.data); return ''; }).join('\n') || '' })); // Execute agent and return A2A-compliant response const response = await agent.generate(mastraMessages); return c.json({ jsonrpc: '2.0', id: requestId, result: { id: taskId || randomUUID(), contextId: contextId || randomUUID(), status: { state: 'completed', /* ... */ }, artifacts: [/* ... */], history: [/* ... */], kind: 'task' } }); } }); What Worked: Following the JSON-RPC 2.0 spec strictly ensured compatibility. The validation caught malformed requests early.
What Didn't: Initially, I forgot to handle the artifacts and history arrays properly. These are crucial for Telex to display results correctly.
Registering Everything with Mastra
In index.ts, I wired everything together using Mastra's central configuration:
import { Mastra } from '@mastra/core/mastra'; import { PinoLogger } from '@mastra/loggers'; import { LibSQLStore } from '@mastra/libsql'; import { playStoreAgent } from './agents/playstore-agent'; import { scheduledRatingCheckWorkflow } from './workflows/playstore-workflow'; import { playStoreScorer } from './scorers/playstore-scorer'; import { a2aAgentRoute } from './routes/a2a-agent-route'; export const mastra = new Mastra({ agents: { playStoreAgent }, workflows: { scheduledRatingCheckWorkflow }, scorers: { playStoreScorer }, storage: new LibSQLStore({ url: 'file:./mastra.db' }), logger: new PinoLogger({ name: 'PlayStoreAgent', level: 'debug', }), observability: { default: { enabled: true }, }, server: { build: { openAPIDocs: true, swaggerUI: true, }, apiRoutes: [a2aAgentRoute], }, bundler: { externals: ["google-play-scraper"], }, }); What Worked: Mastra's centralized configuration made it easy to see the full picture and manage all components in one place.
Deployment to Mastra Cloud
Deployment was surprisingly straightforward:
# Build and test locally first mastra dev You can use the above to build your work locally. If all is fine, you should see this on your terminal:
β Preparing development environment... β Initial bundle complete β Starting Mastra dev server... WARN [2025-11-01 12:47:40.680 +0100] (PlayStoreAgent): Mastra telemetry is deprecated and will be removed on the Nov 4th release. Instead use AI Tracing. More info can be found here: https://github.com/mastra-ai/mastra/issues/8577 and here: https://mastra.ai/en/docs/observability/ai-tracing/overview mastra-cloud-ai-tracing-exporter disabled: MASTRA_CLOUD_ACCESS_TOKEN environment variable not set. π Sign up for Mastra Cloud at https://cloud.mastra.ai to see your AI traces online and obtain your access token. mastra 0.17.7 ready in 25760 ms β Playground: http://localhost:4111/ β API: http://localhost:4111/api To deploy and get your URL:
- Simply push your code to GitHub
- Go to Mastra Cloud
- Import your GitHub repo and start your deployment
If all is successful, you should get your domain URL:
https://playstore-rating-fetcher-agent.mastra.cloud/a2a/agent/playStoreAgent What Worked: The deployment process was seamless. Mastra Cloud handles infrastructure, scaling, and monitoring automatically - no complex configuration needed.
What Didn't: Initially confused about whether I needed to set up infrastructure. Turns out Mastra Cloud handles everything. Also tried deploying using mastra deploy command, but it didn't work. The GitHub integration approach was more reliable.
Testing the Integration
Before integrating with Telex, I tested the endpoint directly:
curl -X POST https://playstore-rating-fetcher-agent.mastra.cloud/a2a/agent/playStoreAgent \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "test-001", "method": "message/send", "params": { "message": { "kind": "message", "role": "user", "parts": [{"kind": "text", "text": "What is the rating for Instagram?"}], "messageId": "msg-001", "taskId": "task-001" }, "configuration": {"blocking": true} } }' What Worked: Getting a proper JSON response confirmed the A2A implementation was correct.
Integrating with Telex.im
The final step was creating the Telex workflow configuration. Following the weather agent example, I created:
{ "active": false, "category": "utilities", "description": "A workflow that gives Google Play Store app ratings", "id": "pR8sT0r3aG3nT1dX", "long_description": "\n You are a helpful assistant...", "name": "playstore_rating_agent", "nodes": [ { "id": "playstore_agent", "name": "playstore agent", "parameters": {}, "position": [816, -112], "type": "a2a/mastra-a2a-node", "typeVersion": 1, "url": "https://playstore-rating-fetcher-agent.mastra.cloud/a2a/agent/playStoreAgent" } ], "pinData": {}, "settings": { "executionOrder": "v1" }, "short_description": "Get app ratings from Google Play Store" } What Worked: Once I matched the exact format of the weather agent example (including lowercase naming, position arrays, etc.), it integrated perfectly with Telex.im.
Try it yourself: Check out the live PlayStore Rating Agent on Telex.im - just ask it about any Android app like "What's the rating for Spotify?" and it will instantly fetch real-time data from the Google Play Store including ratings, review counts, install numbers, and developer information.
Key Challenges and Solutions
Challenge 1: Raw JSON in Responses
Problem: Agent was showing tool output directly to users
Solution: Updated agent instructions to explicitly format responses conversationally
Challenge 2: Telex Workflow Format
Problem: My initial workflow JSON didn't match Telex's expected format
Solution: Followed the weather agent example exactly - lowercase names, specific position format, no extra fields
Challenge 3: A2A Protocol Compliance
Problem: Understanding the artifacts and the history structure
Solution: Studied the blog post example carefully and implemented the exact same structure
Results and Performance
The final agent works beautifully on Telex.im (a Slack alternative for bootcamps and communities with AI agent capabilities):
β
Fast: Responses in 1-2 seconds
β
Accurate: Pulls real-time data from Play Store
β
User-Friendly: Clean, formatted responses
β
Reliable: Proper error handling for edge cases
β
Integrated: Works seamlessly with Telex.im
Lessons Learned
Start with Examples: The weather agent template was invaluable. Don't reinvent the wheel.
Be Explicit with AI: Agent instructions need to be very detailed. The formatting issue taught me this.
Follow Standards Strictly: The A2A protocol has specific requirements. Don't deviate.
Test Incrementally: Testing each component (tool β agent β workflow β A2A) separately made debugging much easier.
Error Handling is Critical: Always assume external APIs can fail. Handle errors gracefully.
Documentation Matters: Reading the Mastra docs and the integration blog post saved hours of trial and error. It would have saved me more if I had started with it first.
Leverage Mastra's Features: Using built-in features like Memory, Scorers, and Workflows saved me from building infrastructure from scratch.
Future Enhancements
Some ideas for v2:
Trend Analysis: Track rating changes over time and alert on significant drops
Competitor Comparison: Compare multiple similar apps side-by-side
iOS Support: Add App Store integration using a similar pattern
Review Sentiment: Analyze user reviews for sentiment trends
Automated Reports: Generate weekly summaries for monitored apps
Conclusion
Building this PlayStore Rating Agent was an excellent learning experience. The Mastra framework made it surprisingly easy to create a production-ready AI agent with features like custom tools, persistent memory, workflow orchestration, and scoring systems. The A2A protocol ensured seamless integration with Telex.im, an AI agent platform like Zapier that doubles as a Slack alternative for education and communities.
The key takeaways:
- Mastra's feature-rich framework (Agents, Tools, Memory, Workflows, Scorers) accelerates development
- The A2A protocol provides real standardization for agent communication
- Starting with good examples accelerates development significantly
- Proper error handling and clear agent instructions are non-negotiable
- Mastra Cloud's deployment process eliminates infrastructure headaches
If you're building AI agents that need to integrate with platforms like Telex.im, I highly recommend the Mastra + A2A approach. It saves you from reinventing the wheel while maintaining flexibility for your specific use case.
Want to try it? Check out the PlayStore Rating Agent on Telex.im and ask it about any Android app!
Resources
Mastra Documentation: https://docs.mastra.ai
Telex.im: https://telex.im - An AI agent platform like Slack alternative for communities, education, and bootcamps
A2A Protocol Blog: https://fynix.dev/blog/telex-x-mastra
Source Code: github.com/toluwanithepm/playstore-rating-fetcher-agent
Live Agent: PlayStore Rating Agent on Telex.im
Have you built any AI agents with Mastra? What challenges did you face? I'd love to hear about your experience in the comments!
Top comments (0)