Tutorial // AI Agents2026-07-1320 min read

Creating an Autonomous Coding Agent using Vercel AI SDK and MCP

Learn how to build your own AI software engineer. We use the new Model Context Protocol (MCP) to give the Vercel AI SDK agent access to read your local file system, write code, and execute bash commands safely.

Varun Raj Manoharan
Varun Raj Manoharan
Vercel AI SDKMCPCoding AgentsTypeScriptTutorial

Summary

TL;DR: The Model Context Protocol (MCP) standardizes how AI agents access external tools. This tutorial shows how to build an autonomous coding agent using the Vercel AI SDK and an MCP File System server to read, write, and test code locally.

The era of copy-pasting code from a chat window into your IDE is ending. The next frontier of developer tooling is autonomous coding agents—systems that don't just tell you how to fix a bug, but actively open your files, read your codebase, write the patch, and run the tests to verify it works.

Building an autonomous coding agent used to require a massive amount of custom infrastructure. You had to build bespoke integrations for your file system, write parsers for bash output, and constantly battle with the LLM's context window.

Today, that has changed. With the introduction of the Model Context Protocol (MCP) and the robust tool-calling capabilities of the Vercel AI SDK, you can build a highly capable coding agent in a single afternoon. This massive, 2,000+ word deep-dive will walk you through exactly how to build an AI software engineer from scratch.

FeatureTraditional Custom API WrapperModel Context Protocol (MCP)
Tool DefinitionHardcoded per toolDynamically fetched from server
ReusabilityNone (specific to your app)High (Universal standard)
MaintenanceHigh (Breaks when API changes)Low (Handled by the MCP server)

What is the Model Context Protocol (MCP)?

Before we write any code, we need to understand the paradigm shift that MCP introduces.

Historically, if you wanted an LLM to interact with an external system—say, your local Postgres database, your GitHub repositories, or your local file system—you had to write custom API wrappers for every single integration. You had to define the OpenAPI schema, map the LLM's JSON output to the API parameters, and handle the serialization manually.

The Model Context Protocol (MCP) standardizes this. Created by Anthropic and adopted widely across the ecosystem, MCP acts like a universal USB port for AI models. An "MCP Server" exposes tools and context in a standardized format. An "MCP Client" (like the one we will build) connects to the server and automatically understands what tools are available and how to use them.

By leveraging an existing local File System MCP server, we can instantly give our Vercel AI SDK agent the ability to read_file, write_file, list_directory, and search_files without writing the implementation logic for those tools ourselves.

Architecture Overview

Our autonomous coding agent will consist of three main components:

  1. The MCP Server: A lightweight local process that runs on the host machine and has direct access to the file system and a sandboxed bash environment.
  2. The MCP Client Wrapper: A bridging layer that connects to the MCP Server, requests its list of tools, and dynamically converts them into Vercel AI SDK tool definitions.
  3. The Agent Loop: A recursive Node.js script powered by the Vercel AI SDK (generateText or streamText) that takes user input, decides which tools to call, executes them via the MCP bridge, reads the results, and continues until the coding task is complete.

Step 1: Project Setup and Dependencies

Let's initialize our project. We will use TypeScript and Node.js.

Shell
mkdir mcp-coding-agent
cd mcp-coding-agent
npm init -y
npm install ai @ai-sdk/openai @modelcontextprotocol/sdk dotenv
npm install -D typescript @types/node tsx
npx tsc --init

Create a .env file in the root of your project. We will use OpenAI's gpt-4o for this tutorial because coding agents require strong reasoning and massive context windows, but you can swap this for Anthropic's Claude 3.5 Sonnet using the @ai-sdk/anthropic provider if you prefer.

ENV
OPENAI_API_KEY=sk-your-api-key-here

Step 2: Defining the MCP Client Bridge

The Vercel AI SDK uses a specific schema for tools (usually defined via Zod). MCP servers also expose tools, but in their own JSON-RPC protocol. We need to write a bridge that connects to an MCP server, fetches its tools, and maps them to the AI SDK format.

Create a file named mcp-bridge.ts.

TypeScript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { tool } from "ai";
import { z } from "zod";

export class MCPBridge {
  private client: Client;
  private transport: StdioClientTransport;

  constructor(serverCommand: string, serverArgs: string[]) {
    // We use stdio to communicate with a local MCP server process
    this.transport = new StdioClientTransport({
      command: serverCommand,
      args: serverArgs,
    });
    
    this.client = new Client(
      { name: "vercel-ai-sdk-client", version: "1.0.0" },
      { capabilities: { tools: {} } }
    );
  }

  async connect() {
    await this.client.connect(this.transport);
    console.log("Connected to MCP Server via stdio.");
  }

  async getAiSdkTools() {
    // 1. Ask the MCP server what tools it has
    const response = await this.client.listTools();
    const toolsRecord: Record<string, any> = {};

    // 2. Map each MCP tool to a Vercel AI SDK tool
    for (const mcpTool of response.tools) {
      toolsRecord[mcpTool.name] = tool({
        description: mcpTool.description,
        // For simplicity in this tutorial, we assume the MCP server uses JSON Schema 
        // that we can loosely map, or we accept a generic record.
        // In a production app, you would parse the JSON Schema into a Zod object.
        parameters: z.record(z.any()),
        execute: async (args) => {
          console.log(`Executing tool: ${mcpTool.name}`);
          const result = await this.client.callTool({
            name: mcpTool.name,
            arguments: args,
          });
          return result.content;
        },
      });
    }

    return toolsRecord;
  }
}

This bridge is the secret sauce. By using this.client.listTools(), our agent is completely agnostic to what the server actually does. If we connect it to a File System server, it becomes a coder. If we connect it to a Postgres server, it becomes a database administrator.

Step 3: Initializing the Local MCP Server

For our coding agent, we need a server that can read and write files. We will use the official filesystem MCP server provided by the community. You can run it via npx.

Let's create the main agent file: agent.ts.

TypeScript
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
import { MCPBridge } from './mcp-bridge';
import * as readline from 'readline';

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

async function main() {
  // Initialize the MCP Bridge targeting the local filesystem
  // We restrict it to the current working directory for safety
  const cwd = process.cwd();
  const bridge = new MCPBridge("npx", [
    "-y", 
    "@modelcontextprotocol/server-filesystem", 
    cwd
  ]);

  await bridge.connect();
  
  // Dynamically load the tools into the Vercel AI SDK format
  const systemTools = await bridge.getAiSdkTools();
  console.log(`Loaded ${Object.keys(systemTools).length} tools from MCP.`);

  // Start the interactive terminal loop
  chatLoop(systemTools);
}

main().catch(console.error);

Step 4: Building the Core Agent Loop

An autonomous coding agent cannot just run once and exit. If it modifies a file and causes a syntax error, it needs to see the error and fix it. We need a recursive loop that maintains the conversation history.

Let's implement the chatLoop inside agent.ts.

TypeScript
import { CoreMessage } from 'ai';

async function chatLoop(tools: any) {
  const messages: CoreMessage[] = [
    {
      role: 'system',
      content: `You are an elite autonomous software engineer. 
You have access to the local file system via MCP tools.
When asked to build a feature or fix a bug:
1. Explore the directory to understand the codebase.
2. Read the relevant files.
3. Plan your changes.
4. Write the updated code back to the files.
Do not ask for permission to write code. Just do it.`
    }
  ];

  const askUser = () => {
    rl.question('\nUser: ', async (input) => {
      if (input.toLowerCase() === 'exit') {
        process.exit(0);
      }

      messages.push({ role: 'user', content: input });

      try {
        // The Vercel AI SDK handles the tool calling loop automatically
        // when maxSteps is greater than 1!
        const result = await generateText({
          model: openai('gpt-4o'),
          messages: messages,
          tools: tools,
          maxSteps: 10, // Allow the agent to call tools up to 10 times autonomously
          onStepFinish: (step) => {
            if (step.toolCalls.length > 0) {
              console.log(`\n[Agent is using tools...]`);
              step.toolCalls.forEach(t => console.log(`-> ${t.toolName}`));
            }
          }
        });

        console.log(`\nAgent: ${result.text}`);
        
        // Save the assistant's response to history
        messages.push({ role: 'assistant', content: result.text });
      } catch (error) {
        console.error("Error generating response:", error);
      }

      askUser();
    });
  };

  askUser();
}

Notice the magic of maxSteps: 10. The Vercel AI SDK v7 introduced multi-step tool calling. When the agent realizes it needs to read a file, it will pause generation, execute the read_file tool via our MCP bridge, read the result, and automatically continue reasoning. It can loop like this up to 10 times before finally returning the final text to the user.

Step 5: Handling Sandboxed Command Execution

Reading and writing files is powerful, but a true coding agent needs to run terminal commands. It needs to run npm run build to see if its TypeScript compiles, or npm test to verify its logic.

You should never give an LLM raw, unrestricted access to your bash terminal using child_process.exec. It might accidentally delete your root directory. Instead, you should use a sandboxed execution environment.

While building a secure Docker sandbox is outside the scope of this specific tutorial (look into E2B or Daytona for production sandboxes), you can add a simple mock terminal tool directly into the AI SDK alongside your MCP tools to see how the agent interacts with it.

TypeScript
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

// Add this to your tools object before passing it to generateText
const terminalTool = tool({
  description: "Execute a bash command in the current directory. Use this to run tests, linting, or builds.",
  parameters: z.object({
    command: z.string().describe("The bash command to run"),
  }),
  execute: async ({ command }) => {
    console.log(`[Executing bash]: ${command}`);
    try {
      const { stdout, stderr } = await execAsync(command);
      return `STDOUT:\n${stdout}\nSTDERR:\n${stderr}`;
    } catch (e: any) {
      return `COMMAND FAILED:\n${e.message}`;
    }
  }
});

When you pass terminalTool alongside the systemTools fetched from MCP, the agent can now write a file and immediately run a bash command to test it. If the bash command returns a STDERR containing a compiler error, the agent will see it, apologize, rewrite the file to fix the typo, and run the command again—all autonomously.

Running Your Agent

To run your new coding agent, simply execute:

Shell
npx tsx agent.ts

Try giving it a complex prompt: "User: Read the package.json file, see what dependencies we have, and then create a new file called utils.ts that exports a function to slugify a string. Write a jest test for it, and run the test to make sure it works."

Watch your terminal. You will see the agent autonomously read the directory, write the implementation file, write the test file, and execute the bash command to run Jest. It is entirely self-directed.

The Future of Engineering

What we have built here is the foundation of the next generation of software engineering. By combining the Vercel AI SDK's multi-step tool orchestration with the Model Context Protocol's universal system access, you have abstracted away the hardest parts of building agentic systems.

You no longer have to worry about the wiring. You can focus entirely on the prompt engineering, the evaluation metrics, and the product experience. The agent takes care of the code.

Frequently Asked Questions (FAQ)

Can I use Vercel AI SDK with local models for coding agents? Yes. You can swap the OpenAI provider for the Ollama provider (@ai-sdk/ollama) to use models like Llama 3 or Qwen2 locally, ensuring your codebase never leaves your machine.

Why use MCP instead of writing custom AI tools? MCP provides a universal standard. Instead of writing custom API wrappers for every external service (GitHub, Postgres, File System), you simply connect an MCP client, and your Vercel AI SDK agent instantly inherits all available tools.

How does maxSteps work in Vercel AI SDK v7? The maxSteps parameter allows the LLM to autonomously orchestrate multiple tool calls sequentially without returning control to the user. If an agent writes code and the bash test fails, it will read the error and try again until maxSteps is reached.

Available for new projects

Let's build something great.

Have a project in mind? We are an elite software and AI development studio ready to bring your ideas to production. Let's talk about your roadmap.