MCP Is the New API, And Nobody's Testing It AI Infrastructure

MCP Is the New API, And Nobody's Testing It

AR
Alex Rivera · April 4,2026 · 8 min read

TL;DR

Model Context Protocol (MCP) is becoming the standard for AI-to-tool communication, but testing practices haven't caught up. We'll show you what MCP is, why it matters, the critical test gaps, and concrete code examples for testing MCP servers, tool integrations, and AI agent pipelines.

If you've been paying attention to the AI infrastructure world, you've probably heard about Model Context Protocol. If you haven't, don't worry, but you should probably stop reading this paragraph and start thinking about it, because MCP is quietly becoming the plumbing layer that connects AI agents to the real world.

APIs are how systems talk to each other. MCP is how AI talks to systems. And unlike APIs, which have had decades of testing practices, tooling, and best practices baked in, MCP is still running hot with almost zero quality infrastructure.

What is MCP, Actually?

Model Context Protocol is a standardized way for AI models (Claude, GPT, open-source LLMs) to request and execute actions in external systems. Instead of building custom integrations for every tool, you define an MCP server that exposes resources and tools in a standard format.

Think of it as the opposite of an API. With an API, you write code that calls external services. With MCP, the AI calls your code based on what it needs to accomplish.

The core insight: MCP turns every tool your application uses into something an AI agent can directly interact with. That's powerful. That's also terrifying if you haven't tested it.

Here's a concrete example. Imagine your system has a database, a file storage service, and a logging system. Traditionally:

  • You write code that talks to these systems
  • You expose that through an API
  • An AI app calls your API
  • You test each layer separately

With MCP, you define three MCP servers (database, file storage, logging) and hand them directly to the AI. The AI figures out which ones to use and when.

Why This Changes Everything (And Breaks Everything)

MCP's power comes from directness: AI agents can access your tools without human-written orchestration code. But this creates test gaps that traditional API testing never prepared you for.

Gap 1: Tool Discovery and Context

The AI needs to know what tools exist, what they do, and when to use them. This lives in tool definitions, schemas that describe inputs, outputs, and behavior. If these descriptions are vague or wrong, the AI will call your tools incorrectly.

Traditional API testing catches this because you write the call site. MCP testing can't rely on that, the AI is the call site, and it makes decisions based on imperfect context.

Gap 2: Edge Case Divergence

APIs fail predictably. MCP tools fail in novel ways because the AI is invoking them in combinations you never imagined. Your delete tool is supposed to delete files, but what if the AI calls it during a critical operation and it fails? What if it races with another operation?

Gap 3: Agent-Tool Interaction Patterns

You can unit test a tool. You can integration test an API. But testing an AI agent that chains multiple tools together? That requires understanding whether the agent can recover from partial failures, retry correctly, and maintain consistency across tool calls.

Testing MCP Servers: Where to Start

Let's get concrete. to test an MCP server that exposes a simple database tool.

Step 1: Unit Test the Tool Definition

Start with schema validation. Your tool definitions are contracts, test that they're unambiguous.

import { test, expect } from 'vitest';
import { DatabaseTool } from './database-tool';

test('database query tool schema is valid', () => {
 const tool = new DatabaseTool();
 const schema = tool.getSchema();

 // Validate required fields
 expect(schema).toHaveProperty('name');
 expect(schema).toHaveProperty('description');
 expect(schema).toHaveProperty('inputSchema');

 // Validate input schema clarity
 expect(schema.inputSchema.properties).toHaveProperty('query');
 expect(schema.inputSchema.properties.query.description).toBeTruthy();
 expect(schema.inputSchema.properties.query.description.length).toBeGreaterThan(10);

 // Ensure all required fields are documented
 schema.inputSchema.required?.forEach(field => {
 expect(schema.inputSchema.properties[field].description).toBeTruthy();
 });
});

test('tool input validation catches invalid queries', async () => {
 const tool = new DatabaseTool();

 // Empty query should fail
 await expect(tool.execute({ query: '' })).rejects.toThrow();

 // SQL injection-like patterns should be sanitized or rejected
 await expect(
 tool.execute({ query: "SELECT * FROM users; DROP TABLE users;" })
 ).rejects.toThrow();
});

Step 2: Integration Test Tool Behavior

Now test what happens when the tool actually executes. Focus on the tool's contract, does it return what the schema promises?

test('database query tool returns data in schema format', async () => {
 const tool = new DatabaseTool();
 const result = await tool.execute({ query: 'SELECT * FROM products' });

 // Verify response shape matches schema
 expect(result).toHaveProperty('rows');
 expect(result).toHaveProperty('rowCount');
 expect(Array.isArray(result.rows)).toBe(true);

 // Each row should match expected structure
 if (result.rows.length > 0) {
 const firstRow = result.rows[0];
 expect(firstRow).toHaveProperty('id');
 expect(firstRow).toHaveProperty('name');
 }
});

test('database tool handles errors gracefully', async () => {
 const tool = new DatabaseTool();

 // Simulate database failure
 const result = await tool.execute({ query: 'SELECT * FROM nonexistent' });

 // Tool should return error info, not throw
 expect(result).toHaveProperty('error');
 expect(result.error).toBeTruthy();
});

test('database tool respects rate limits', async () => {
 const tool = new DatabaseTool({ maxQueriesPerMinute: 10 });

 // Simulate rapid queries
 for (let i = 0; i < 15; i++) {
 const result = await tool.execute({ query: 'SELECT 1' });
 if (i < 10) {
 expect(result.error).toBeUndefined();
 } else {
 expect(result).toHaveProperty('error');
 }
 }
});

Testing AI Agent Pipelines Built on MCP

Now comes the hard part: testing the AI's interaction with your tools. You need to simulate agent behavior and verify it uses your tools correctly.

Agent Tool Integration Test

test('agent can query database and format results', async () => {
 const agent = new AIAgent({
 model: 'claude-3-sonnet',
 tools: [databaseTool, loggerTool, fileStorageTool]
 });

 // Give the agent a task that requires tool use
 const response = await agent.run({
 prompt: "Find all customers from California and save them to a CSV file"
 });

 // Verify the agent used the correct tools in correct order
 expect(response.toolCalls).toEqual(
 expect.arrayContaining([
 expect.objectContaining({
 toolName: 'database_query',
 args: expect.objectContaining({ query: expect.stringContaining('California') })
 }),
 expect.objectContaining({
 toolName: 'file_write',
 args: expect.objectContaining({ filename: expect.stringMatching(/\.csv$/) })
 })
 ])
 );

 // Verify final output
 expect(response.text).toContain('saved');
});

test('agent recovers from tool failures', async () => {
 const agent = new AIAgent({
 tools: [databaseTool, fallibleTool]
 });

 // Simulate tool failure on first try
 fallibleTool.failNextCall = true;

 const response = await agent.run({
 prompt: "Query the database"
 });

 // Agent should retry or use fallback tool
 expect(response.success).toBe(true);
 expect(response.toolCalls.length).toBeGreaterThan(1);
});

Testing Tool Combinations and State

The real danger: when tools interact with shared state. If two tools modify the same resource, you need to test that interaction.

test('agent maintains consistency across tool calls', async () => {
 const agent = new AIAgent({
 tools: [updateTool, readTool]
 });

 // Agent should read after write and see updated value
 const response = await agent.run({
 prompt: "Update user age to 30, then read their profile"
 });

 // Find the tool calls
 const updateCall = response.toolCalls.find(c => c.toolName === 'update_user');
 const readCall = response.toolCalls.find(c => c.toolName === 'read_user');

 // Read call should come after update
 expect(response.toolCalls.indexOf(readCall)).toBeGreaterThan(
 response.toolCalls.indexOf(updateCall)
 );

 // Read result should reflect the update
 const readResult = response.toolResults[readCall.id];
 expect(readResult.age).toBe(30);
});

Validating Tool Schema Clarity

Here's a practical checklist for ensuring your MCP tool schemas are testable:

  • Description clarity: Can a human read the tool description and understand exactly when to use it?
  • Input documentation: Each parameter should have a description with examples
  • Output documentation: The response schema should clearly describe what the tool returns
  • Error handling: Document what happens when things go wrong
  • Side effects: If the tool modifies state, make it explicit
Poor schema clarity doesn't just fail tests, it fails your AI. An agent with vague tool definitions will make poor decisions about when to use them.

The Missing Piece: Agent-Tool Monitoring

Testing in development is one thing. Monitoring in production is another. You need visibility into:

  • Which tools the agent actually calls (vs. which you expected)
  • Tool failure rates and error patterns
  • Agent retry behavior and recovery success
  • Tool interaction chains (which tools call which in sequence)

This is where most MCP deployments fail. You test your tools individually and assume the agent will use them correctly. Then in production, the agent finds edge cases your tests never covered.

Practical Takeaways

MCP is powerful because it removes orchestration code. But that directness requires more rigorous testing, not less. Start here:

  1. Test tool schemas for clarity and completeness
  2. Test tool behavior independently (unit tests)
  3. Test tool integration (can they work together?)
  4. Test agent-tool interaction patterns (does the agent use them correctly?)
  5. Monitor tool usage in production (what's actually happening?)

MCP isn't going away. It's going to become the standard way AI interacts with systems. The companies that get testing right will ship faster and with fewer surprises. The ones that skip this work will spend months debugging why their agent does weird things in production.

Ready to test your MCP infrastructure?

alt.qa helps teams build confidence in AI agent behavior. From tool validation to agent monitoring, we've got the infrastructure for the MCP era.

Get started free
Alex Rivera is a Senior AI Engineer at alt.qa, where he helps teams build reliable AI infrastructure. He's obsessed with testing standards that scale as AI gets more autonomous.