MCP Patterns

MCP Tool Inspection

Check, filter, validate, and wrap MCP tools before exposing them to an agent.

MCP tools are adapted automatically, but a production harness should still inspect what the server exposed. Tool names, descriptions, input schemas, and permission expectations decide whether a tool is safe to show to a model.

Scenario

A remote MCP server exposes 40 tools. Your support agent should use only read-only documentation tools, while an internal admin agent can use a smaller set of write tools behind approval.

When to Use It

Use this pattern when:

  • a server exposes more tools than one agent should see
  • tool names are unclear or conflict with local tools
  • a tool needs product permissions or audit records
  • you need to verify required tools exist before startup succeeds

Architecture Shape

StepPurpose
connect serverget adapted Anvia tools
inspect definitionsverify name, description, and schema
validate required toolsfail fast for missing required capabilities
filter safe toolsexpose only the tools this agent should use
wrap toolsrename, audit, permission-check, or normalize output when needed

Inspect Definitions

import { connectMcp, mcp, type McpServer } from "@anvia/core";

const docsServer = await connectMcp(
  mcp.http({
    name: "docs",
    url: "https://mcp.example.com/mcp",
  }),
);

for (const tool of docsServer.tools) {
  const definition = await tool.definition("");
  logger.info({
    server: docsServer.name,
    tool: definition.name,
    description: definition.description,
    parameters: definition.parameters,
  });
}

Validate Required Tools

async function requireMcpTools(server: McpServer, names: string[]) {
  const available = new Set(server.tools.map((tool) => tool.name));
  const missing = names.filter((name) => !available.has(name));

  if (missing.length > 0) {
    throw new Error(`MCP server ${server.name} is missing tools: ${missing.join(", ")}`);
  }
}

await requireMcpTools(docsServer, ["search_docs", "read_doc"]);

Filter Tools

function pickMcpTools(server: McpServer, allowedNames: string[]) {
  const allowed = new Set(allowedNames);
  return server.tools.filter((tool) => allowed.has(tool.name));
}

const safeDocsTools = pickMcpTools(docsServer, ["search_docs", "read_doc"]);

const agent = new AgentBuilder("support", model)
  .instructions("Use docs tools for public support documentation.")
  .tools(safeDocsTools)
  .defaultMaxTurns(3)
  .build();

Use .mcp([server]) when the agent should receive every tool from that server. Use .tools(filteredTools) when the agent should receive only selected tools.

Wrap Tools

Wrap an MCP tool when you need product-specific names, permissions, audit records, or normalized output.

import { createTool } from "@anvia/core";
import { z } from "zod";

const searchDocs = docsServer.tools.find((tool) => tool.name === "search_docs");

if (!searchDocs) {
  throw new Error("docs MCP server is missing search_docs");
}

const searchInternalDocs = createTool({
  name: "search_internal_docs",
  description: "Search internal support documentation for the current tenant.",
  input: z.object({
    query: z.string().min(1),
  }),
  async execute({ query }) {
    await permissions.require(scope.userId, "docs:read");

    const result = await searchDocs.call({
      query: `${query}\ntenant:${scope.tenantId}`,
    });

    await audit.write({
      actorId: scope.userId,
      action: "docs.search",
      tenantId: scope.tenantId,
    });

    return result;
  },
});

Failure Modes

FailureFix
server exposes unsafe toolsfilter or wrap before registering
tool names conflictwrap with product-specific names
schema is too loosewrap with a stricter Zod schema
server changes tool namesvalidate required tools at startup
remote tool returns noisy outputwrap and normalize result shape

Test Checklist

  • Assert required tools exist after connection.
  • Snapshot provider-facing tool definitions for critical MCP tools.
  • Test wrapped tools with fake permission and audit services.
  • Verify agents receive only allowed MCP tools.
  • Inspect MCP metadata in Studio when available.