Integrating mcp.run Tools with Mastra AI
Mastra is an open-source TypeScript framework for building sophisticated AI applications and features. It provides the core building blocks needed to create, manage, and deploy AI systems with a focus on practical application development. Think of it as a toolkit that bridges the gap between raw LLM capabilities and production-ready AI features. The framework is built around four main components:
- LLM Integration - A unified interface to work with multiple LLM providers (OpenAI, Anthropic, Google Gemini) through a consistent API, eliminating the need to handle different provider-specific implementations.
- Agents - Autonomous AI systems that can maintain memory, execute tools (functions), and handle complex interactions. These agents can be developed and tested in Mastra's local development environment.
- Workflows - A graph-based system for orchestrating complex LLM operations with features like branching, parallel execution, and state management. Workflows provide deterministic control over AI operations through a simple syntax for defining steps and control flow.
- RAG System - A comprehensive retrieval-augmented generation pipeline that handles document processing, embedding generation, vector storage, and context retrieval, supporting multiple vector stores and embedding providers.
What sets Mastra apart is its focus on developer experience and production readiness. It includes built-in support for deployment (compatible with React, Next.js, Node.js, and serverless platforms), comprehensive evaluation metrics for assessing LLM outputs, and observability features for monitoring and debugging AI systems in production. The framework is designed to handle the complex infrastructure needs of AI applications while letting developers focus on building features that matter to their users.
This tutorial will guide you through integrating mcp.run tools with Mastra AI for building intelligent agents and workflows. We'll see how we can create an agent that can use mcp.run tools to fetch information about github repositories.
Prerequisitesβ
Before starting, ensure you have:
- Node.js v20.0 or higher
- A GitHub account for mcp.run authentication
- An OpenAI API key
Step 1: Set up mcp.runβ
Generate a session ID for mcp.run:
npx --yes -p @dylibso/mcpx@latest gen-session
Note: keep this Session ID around for later in the tutorial! You'll use it as an environment variable in a following step.
Install the required mcp.run tools:
- Visit https://www.mcp.run/evacchi/github
- Click "Install" to add GitHub tools to your profile. Make sure your PAT has access to the repo you are interested in.
Step 2: Create a New Mastra Projectβ
Let's start by creating a new Mastra project using the create-mastra tool:
npx create-mastra@latest
You'll be prompted for the following:
What do you want to name your project? github-insights
Choose components to install:
β Agents
Select default provider:
β OpenAI (recommended)
Would you like to include example code? No
After the project is created, add your OpenAI API key to the .env.development
file:
OPENAI_API_KEY=<your-openai-key>
MCPX_SESSION_ID=<your-mcp.run-session-id>
Then set module
to ES2022
in your tsconfig.json
file and type
to
module
in your package.json
file.
Step 3: Add mcp.run Integrationβ
First, install the mcpx library:
npm install @dylibso/mcpx @dylibso/json-schema-to-zod-openai
Create a new file src/mastra/tools/mcpx.ts
and add the provided getMcpxTools
function.
import { Session } from "@dylibso/mcpx";
import { createTool } from "@mastra/core";
import { z } from "zod";
import { convertToZodSchema } from "@dylibso/json-schema-to-zod-openai";
// Define consistent types across both implementations
interface MCPXTool {
name: string;
description?: string;
inputSchema: Record<string, any>;
}
// Align with the more detailed content type structure
interface MCPXCallResult {
content?: Array<{
type: "text" | "image" | "resource";
data?: string;
mimeType?: string;
text: string;
}>;
isError?: boolean;
}
// Define the content type enum
const ContentTypeEnum = z.enum(["text", "image", "resource"]);
// Define consistent content schema
const Content = z.object({
data: z.string().nullable().describe("The base64-encoded data"),
mimeType: z.string().nullable().describe("The MIME type of the content"),
text: z.string().nullable().describe("The text content of the message"),
type: ContentTypeEnum,
});
// Define consistent call result schema
const CallToolResult = z.object({
content: z.array(Content),
isError: z.boolean().nullable().describe(
"Whether the tool call ended in an error",
),
});
export async function getMcpxTools(session: Session) {
try {
const { tools: mcpxTools } = await session.handleListTools({
method: "tools/list",
}, {} as any);
const tools = mcpxTools.map((mcpxTool: MCPXTool) => {
const zodSchema = convertToZodSchema(mcpxTool.inputSchema);
return createTool({
id: mcpxTool.name,
description: mcpxTool.description || "",
inputSchema: zodSchema,
outputSchema: CallToolResult,
execute: async ({ context }) => {
try {
const response = await session.handleCallTool({
method: "tools/call",
params: {
name: mcpxTool.name,
arguments: context,
},
}, {} as any) as MCPXCallResult;
console.log(
"called tool",
mcpxTool.name,
"with context",
context,
"succcss?",
!response.isError,
);
if (!response) {
return {
content: [{
type: "text",
text: "No response received from tool",
data: null,
mimeType: null,
}],
isError: true,
};
}
return {
content: response.content?.map((item) => ({
type: item.type,
text: item.text,
data: item.data,
mimeType: item.mimeType,
})) ?? [],
isError: response.isError,
} as any;
} catch (error) {
console.error(`Error executing tool ${mcpxTool.name}:`, error);
return {
content: [{
type: "text",
text:
`An error occurred while executing ${mcpxTool.name}: ${error}.`,
data: null,
mimeType: null,
}],
isError: true,
};
}
},
});
});
return tools.reduce((acc, tool) => ({
...acc,
[tool.id]: tool,
}), {});
} catch (error) {
console.error("Error getting MCPX tools:", error);
throw error;
}
}
Step 4: Create the GitHub Agentβ
Create a new file src/mastra/agents/githubAgent.ts
:
import { Agent } from "@mastra/core";
import { Session } from "@dylibso/mcpx";
import { getMcpxTools } from "../tools/mcpx";
import { openai } from "@ai-sdk/openai";
export async function createGitHubAgent(session: Session) {
const tools = await getMcpxTools(session);
return new Agent({
name: "GitHub Assistant",
instructions:
`You are a helpful GitHub assistant that can help users with repository management tasks.
You can:
- List and create issues
- Get repository details and contributors
- Create and update files
- Handle pull requests
Always provide clear explanations of the actions you take.
Rules:
- Be mindful of your context window limits.
- Tools can easily overload you with information.
- Use only what you need.
- Limit pages sizes to 10.
- Don't paginate unless the user asks for it.
- Don't use more than 3 tools in a single response. Unless the user asks for it.`,
model: openai("gpt-4o-mini"),
tools: tools,
});
}
Step 5: Register the Agentβ
Update src/mastra/index.ts
:
import { Mastra } from "@mastra/core";
import { Session } from "@dylibso/mcpx";
import { createGitHubAgent } from "./agents/githubAgent";
if (!process.env.MCPX_SESSION_ID) {
throw new Error("MCPX_SESSION_ID environment variable is required");
}
const session = new Session({
authentication: [
["cookie", `sessionId=${process.env.MCPX_SESSION_ID}`],
],
activeProfile: "default",
});
const githubAgent = await createGitHubAgent(session);
export const mastra = new Mastra({
agents: { githubAgent },
});
Step 6: Testing it outβ
- Start the Mastra development server:
npm run dev
Go to http://localhost:4111/agents/githubAgent
, and then you can start using
the GitHub agent:
You can find the complete code for this example at: dylibso/github-insights
Supportβ
If you get stuck and need some help, please reach out! VisitΒ our support pageΒ to learn how best to get in touch.