Your Agent Toolkit: MCP Server, SDK, or Both?
Featured

Your Agent Toolkit: MCP Server, SDK, or Both?

MCP promises standardization but framework support varies wildly. SDKs give control but mean vendor lock-in. The hybrid approach fills gaps that pure options leave open.

mcpaiagentsinfrastructuresdk
On this page

Every developer building AI agents faces the same question: how should my agent consume tools?

The obvious answer used to be “just use function calling.” Define schemas inline, let the model pick tools, handle the results. Simple enough for a demo. Then you need approval workflows, tool filtering, output transformations, and suddenly you’re rebuilding infrastructure that should already exist.

MCP promised to standardize this. One protocol, any client. Connect to any MCP server and discover tools dynamically. A year later, 10,000+ MCP servers exist and adoption includes Claude, ChatGPT, Cursor, VS Code, and Copilot.

But the promise doesn’t match reality for everyone. Framework support varies dramatically. Vercel AI SDK’s MCP integration can’t deploy stdio transport to production. Missing features include session management, resumable streams, and approval workflows. Security and multi-tenant isolation? You’re on your own.

So how should you actually consume tools in your agent?

Three Approaches

There are three ways to give your agent access to tools. Each optimizes for different constraints.

Pure MCP Client: Connect to MCP servers, discover tools dynamically. The protocol handles discovery, you handle everything else.

Pure SDK (Function Calling): Import tools as functions directly in your codebase. Define schemas with JSON Schema or Zod. No external dependencies.

Hybrid Toolset SDK: Libraries like StackOne that pull tool definitions dynamically but wrap them with utilities the protocol doesn’t provide (filtering, approvals, framework adapters, output transformations).

The right choice depends on how many integrations you need, whether you need runtime flexibility, and what utilities you can’t build yourself.

Pure MCP Client: Dynamic Discovery, Variable Support

Connecting to MCP servers gives you access to thousands of pre-built integrations. Any MCP-compatible server exposes tools your agent can discover at runtime.

// Connect to a remote MCP server (Sentry's hosted endpoint)
import { experimental_createMCPClient } from "ai";

const mcpClient = await experimental_createMCPClient({
  transport: {
    type: "sse",
    url: "https://mcp.sentry.dev/sse",
  },
});

// Discover available tools dynamically
const tools = await mcpClient.tools();
// Returns: [{ name: "get_issue", ... }, { name: "search_errors", ... }]

Remote MCP servers like Sentry’s handle OAuth, scaling, and state management. Local stdio servers work for development but can’t deploy to production in most frameworks.

Pure MCP Client

✓Pros
✓
10,000+ servers

Connect to existing MCP servers without writing integration code

✓
Dynamic discovery

Tools discovered at runtime, not hardcoded

✓
Model-agnostic

Same MCP server works with Claude, GPT, Gemini, local models

✓
Ecosystem momentum

Major player adoption, Linux Foundation governance

✗Cons
✗
Framework variance

Vercel AI SDK's stdio transport 'cannot be deployed to production'

✗
No approvals

Protocol doesn't define human-in-the-loop patterns

✗
Auth complexity

OAuth/PKCE/token refresh left to implementer

✗
Network overhead

Every tool call goes through the server

The framework variance issue is real. I’ve seen teams spend days working around the gap between what MCP specifies and what their framework actually implements. Session management, notifications, and resumable streams exist in the spec but not consistently in SDKs.

What Developers Actually Say

The frustration isn’t theoretical. Developers report:

“Yeah MCP is the worst documented technology I have ever encountered… I have read so much about MCP and have zero fucking clue except vague marketing speak.” — epistasis, Hacker News

“This is a stunningly bad specification, perhaps the worst I have seen in my career.” — jes5199, Hacker News

Heavy MCP setups can consume 55-100k+ tokens before you type a word. That’s 27-50% of a 200k context window gone on tool definitions alone. — Mario Giancini, “The Hidden Cost of MCP Servers”

And on client-side implementation issues specifically:

MCP servers don’t reload when code changes. Must fully restart Claude Code CLI, losing entire conversation context every time. This has been broken for 6+ months. — GitHub Issue #7174

Server support is fine. Client implementations lag behind the spec. Custom headers, OAuth flows, and session management work differently (or not at all) across frameworks.

If your tools are for broad ecosystem consumption (open source, community contribution, cross-platform) and you can live with lowest-common-denominator features, pure MCP works.

Pure SDK: Full Control, Limited Reach

When you control both the agent and the tools, SDK-based function calling gives you type safety, embedded utilities, and no network overhead.

// SDK function calling with Zod
import { z } from "zod";
import { tool } from "ai";

const searchDocs = tool({
  description: "Search documentation",
  parameters: z.object({
    query: z.string().describe("Search query"),
  }),
  execute: async ({ query }) => {
    const results = await searchIndex(query);
    return results.slice(0, 5);
  },
});

const result = await generateText({
  model: anthropic("claude-sonnet-4-20250514"),
  tools: { searchDocs },
  prompt: "Find docs about authentication",
});

Pure SDK (Function Calling)

✓Pros
✓
Direct control

Tool behavior is your code, not protocol-mediated

✓
Type safety

Zod schemas, TypeScript inference, compile-time checks

✓
No server

Tools are functions, no infrastructure to deploy

✓
Embedded utilities

Add caching, approvals, transformations inline

✗Cons
✗
Vendor-specific

OpenAI, Anthropic, Vercel each have different patterns

✗
Rebuild per service

New integration = new tool code

✗
Manual discovery

Hardcoded tool imports, no runtime querying

✗
Redeploy for updates

Tool changes require code changes

Pure SDK makes sense for single-framework projects with custom tools. When you’re building internal tools for your specific agent, the overhead of running an MCP server doesn’t pay off.

Hybrid: SDK Utilities with MCP Discovery

The hybrid approach recognizes that MCP’s value is in discovery and standardization, but the protocol has real gaps that SDKs fill better.

// Hybrid: dynamic discovery + SDK utilities
const toolset = new StackOneToolSet();

// Fetch tools dynamically, filter by provider and action pattern
const tools = await toolset.fetchTools({
  providers: ["hibob", "slack"],
  actions: ["*_list_*", "*_create_*"],
});

// Convert for your framework
const openaiTools = tools.toOpenAI();
const anthropicTools = tools.toAnthropic();
const vercelTools = await tools.toAISDK();

The hybrid approach pulls tool definitions from an MCP-style endpoint but wraps them with utilities the protocol doesn’t provide.

Hybrid Approach

✓Pros
✓
Dynamic discovery

Tools fetched at runtime, always current

✓
Multi-framework

Single source, converts to OpenAI/Anthropic/Vercel/etc.

✓
Filtering

Glob patterns, provider scopes, action filters

✓
SDK utilities

Approvals, transformations, file handling built-in

✗Cons
✗
Provider dependency

Relies on the hybrid provider's implementation

✗
Extra abstraction

One more layer between agent and tools

✗
Feature coverage

May not expose all raw MCP capabilities

Tool Filtering in Action

Try filtering tools by pattern and provider. Watch how token costs drop:

Filter tools dynamically

Reduce token overhead by selecting only the tools you need

Read-only tools (no writes)
Matched 5 of 30 tools
hibob_list_employeeshibob_list_departmentshibob_list_time_offslack_list_channelsslack_list_users
Output:
tools.toOpenAI()
// Returns:
[
  { type: "function", function: { name: "hibob_list_employees", ... } },
  { type: "function", function: { name: "hibob_list_departments", ... } },
  // ... 1 more
]
💰Token savings:
83%(30 → 5 tools = 11,250 tokens saved)

What Your Framework Doesn’t Give You

You’ve seen the three approaches. But whichever you choose, your framework probably doesn’t handle everything you need. SDKs vary wildly in what utilities they provide.

The Variance Is Real

The same feature works differently (or not at all) across frameworks. Try switching between MCP support, approval workflows, and execution hooks to see what each framework actually provides:

Framework Feature Support

Same feature, different implementations. See what each framework actually provides.

Connect to MCP servers and discover tools dynamically

●Full Support—Native MCP with stdio and SSE transports
import { Agent, MCPServerStdio } from "@openai/agents";

const agent = new Agent({
  name: "assistant",
  tools: [
    new MCPServerStdio({
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem"],
    }),
  ],
});

// Tools discovered automatically from MCP server
MCP Client Support

The interactive grid above lets you explore each feature in detail. Here’s the same data as a quick-reference matrix:

Framework Feature Matrix

Click a framework name to see code examples. Hover cells for details.

●Full◐PartialβBeta○None
Feature
MCP Support
Model Context Protocol integration
●◐◐β●●●
Custom Headers
Auth headers for HTTP transport
●◐●◐●●●
Tool Filtering
Limit available tools via patterns/permissions
◐◐◐●◐●◐
Tool Search
Semantic discovery from large tool sets
○○◐●○○○
Human-in-Loop
Approval workflows and interrupts
●●●◐◐●◐
Code Execution
Sandboxed code interpreter
●◐●○●○●
Execution Hooks
Step callbacks and lifecycle events
●●●◐◐◐●
Streaming
Real-time response streaming
●●●●◐●●
Key Insights
●OpenAI & Vercel have the most mature hooks and approval workflows
◐Claude SDK MCP support still in beta, no native HITL
βCloudflare unique with Code Mode — tools become TypeScript
!Multi-tenant filtering is underserved across all frameworks

The gaps below are what you’ll need to build yourself, or find a toolset SDK that provides them.

1. Approval Workflows

MCP has no concept of human-in-the-loop. The protocol says “here’s a tool, here’s how to call it.” What it doesn’t say: should this call require approval? From whom? Under what conditions?

Human-in-the-Loop Approvals

SDKs provide approval workflows that MCP doesn't specify

Mode:
🤖

I'll execute bamboohr_delete_employee

Delete an employee record from BambooHR

bamboohr_delete_employeehigh risk
{
  "employeeId": "12345",
  "reason": "Termination"
}
Tool 1 of 4
View SDK code pattern
const tools = await toolset.fetchTools({
  needsApproval: (tool) => {
    // Auto-approve reads, require approval for writes
    return tool.name.includes("create")
        || tool.name.includes("delete")
        || tool.name.includes("update");
  },
});
// SDK-level approval pattern
const tools = await toolset.fetchTools({
  needsApproval: true, // All tools require approval
});

// Or conditional approval
const tools = await toolset.fetchTools({
  needsApproval: (tool) => {
    // Auto-approve reads, require approval for writes
    return tool.name.includes("create") || tool.name.includes("delete");
  },
});

2. Output Transformations

Tools return data. Sometimes that data is massive (file contents, search results, API responses). Raw MCP sends everything to the model, burning tokens on data the agent doesn’t need to see in full.

Output Transformation: What the model actually needs

Raw API responses waste tokens. SDK transforms extract what matters.

{
  "query": "employee onboarding policy",
  "total_results": 47,
  "took_ms": 234,
  "results": [
    {
      "id": "doc-001",
      "title": "Employee Onboarding Checklist 2024",
      "content": "This comprehensive guide covers all aspects of onboarding new employees including: Day 1 orientation schedule, IT equipment setup procedures, HR paperwork requirements, benefits enrollment deadlines, manager introduction protocols, team lunch scheduling, building access card procedures, parking permit applications, corporate credit card requests, expense reporting training, time tracking system setup, Slack workspace invitations, email signature configuration, calendar sharing permissions, project management tool access, code repository permissions, VPN configuration, security training requirements, compliance acknowledgments, emergency contact forms, direct deposit setup, tax withholding elections, 401k enrollment options, health insurance selection, dental and vision plans, life insurance beneficiary forms, HSA/FSA elections, commuter benefits, professional development budget allocation, conference attendance policies, remote work agreements, equipment home office stipend...",
      "score": 0.94,
      "metadata": {
        "author": "HR Team",
        "last_updated": "2024-01-15",
        "department": "Human Resources",
        "document_type": "policy",
        "word_count": 3847,
        "version": "2.3.1"
      },
      "highlights": [
        "...new <em>employee onboarding</em> process should begin...",
        "...<em>onboarding</em> checklist must be completed within..."
      ]
    },
    {
      "id": "doc-002",
      "title": "Remote Onboarding Guidelines",
      "content": "For employees joining remotely, additional considerations apply. Equipment shipping typically takes 3-5 business days. Virtual orientation sessions are conducted via Zoom every Monday at 9 AM PST. Remote employees should set up their home office according to ergonomic guidelines provided in Section 4.2. Internet reimbursement of up to $50/month is available after completing the Remote Work Agreement form HR-107...",
      "score": 0.89,
      "metadata": {
        "author": "Remote Work Committee",
        "last_updated": "2024-02-20",
        "department": "Human Resources",
        "document_type": "guidelines",
        "word_count": 2156,
        "version": "1.4.0"
      },
      "highlights": [
        "...remote <em>onboarding</em> requires additional setup...",
        "...<em>employee</em> equipment shipping procedures..."
      ]
    },
    {
      "id": "doc-003",
      "title": "IT Systems Access Request Procedures",
      "content": "All new employees require access to core systems within their first week. Submit access requests through ServiceNow ticket category 'New Employee Setup'. Required approvals vary by system sensitivity level. Level 1 systems (email, Slack, calendar) are auto-provisioned. Level 2 systems (project tools, code repos) require manager approval. Level 3 systems (production databases, financial systems) require VP approval and security review...",
      "score": 0.85,
      "metadata": {
        "author": "IT Security",
        "last_updated": "2024-03-01",
        "department": "Information Technology",
        "document_type": "procedure",
        "word_count": 4521,
        "version": "3.1.0"
      },
      "highlights": []
    }
  ]
}
Tokens: ~742

Full document content, metadata, and all 47 results would be sent to the model. Most of this is never used.

The SDK can split results: full data for your app’s UI, summarized data for the model. Your user sees the complete search results while the agent only consumes tokens for what it needs to reason about.

3. File Handling

MCP doesn’t specify how to handle file downloads, binary data, or content that needs encoding. A tool that returns a PDF gets you a URL. But the model can’t read PDFs from URLs.

File Handling: What MCP returns vs. what you need

MCP gives you URLs. SDKs give you usable data.

✗Raw MCP Response
{
  "content_uri": "https://storage.example.com/files/abc123",
  "mime_type": "application/pdf",
  "size_bytes": 2516582
}

⚠️Model can't read PDFs. Returns a URL the agent can't use.

✓SDK Transformed
The SDK handles: URL fetching, format detection, content extraction, encoding conversion, size optimization, and error handling. MCP just says "here's where the file is."

SDKs handle the complexity: fetching URLs, detecting formats, extracting text from PDFs, encoding images for vision models, parsing spreadsheets into structured data. Without this, you’re writing format-specific handlers for every file type your tools might return.

4. Execution Hooks

Think Express middleware or DOM event handlers. Before any tool executes, your code runs first. You can log, check permissions, detect prompt injection, sanitize inputs, or block execution entirely.

Execution Hooks: Middleware for Agent Tool Calls

Like Express middleware or DOM event handlers. Return false to block, modify input, or let it continue.

Execution Flow
→Tool Call
bamboohr_update_employee
{ "employeeId": "12345", "salary": "150000"
📝Logging & Audit Hook

Track every tool call for compliance and debugging

Hook Implementation
hooks.beforeToolCall(async (tool, input) => {
  await auditLog.write({
    tool: tool.name,
    input: JSON.stringify(input),
    user: session.userId,
    timestamp: Date.now(),
  });
  return { continue: true }; // Allow execution
});
The pattern: Hooks intercept every tool call before execution. Return { continue: true } to proceed,{ block: true } to stop, or { continue: true, input: modified } to transform. MCP has no equivalent—this is SDK-level control.

This is critical for security. The agent might call file_write with a path from user input that contains ../../../etc/passwd. Or search_docs with a query that says “ignore previous instructions.” Pattern matching catches obvious attacks. Semantic similarity (embeddings compared against known attack vectors) catches the subtle ones. Without hooks, you’re trusting third-party tools completely. With hooks, you control every call.

MCP has no equivalent. It’s a protocol for tool discovery, not execution control. Hooks are SDK-level middleware that frameworks provide but the protocol doesn’t specify.

Which Should You Choose?

Question 1 of 6

Are you building tools for others to consume?

Where This Is Going

MCP isn’t going away. Linux Foundation governance means it’ll evolve slowly but stay stable. The spec will eventually address multi-tenancy, better auth, and the other gaps.

My prediction: two or three agent frameworks will consolidate to cover 70% of the market with solid MCP support. The winners will be Claude’s Agent SDK and Pydantic AI, not OpenAI’s Agents SDK. Anthropic has the model quality lead and is building the tooling to match. Pydantic AI has the Pythonic simplicity that LangChain never achieved. Vercel AI SDK will own the TypeScript/Next.js niche. OpenAI’s SDK feels like the safe choice that loses to teams with stronger opinions about developer experience.

But SDK toolsets like StackOne will continue to provide capabilities that harnesses don’t prioritize. Things like tool filtering with glob patterns, conditional approval workflows, output transformations that reduce token costs. These are features specific to multi-tenant SaaS that general-purpose agent frameworks won’t optimize for.

Multi-tenant isolation is the blind spot. Every framework in the comparison table assumes single-user contexts. Account-scoped tool visibility, per-tenant rate limits, audit logs per customer: you’re building that yourself.

Pure MCP servers will be for ecosystem contribution. Pure SDKs will be for internal tools. Hybrid approaches will power production SaaS features where you need both dynamic discovery and the utilities that make tools safe for real users.

There’s a fourth approach emerging that I haven’t covered here: Code Mode (or “code execution” in some frameworks). Instead of pre-defined tools, the agent writes and executes code to accomplish tasks. Cloudflare’s workers-ai, OpenAI’s code interpreter, and several frameworks are experimenting with this pattern. It deserves its own post.


This is part of a series on AI infrastructure. See also: MCP: Where It’s Been, Where It’s Going.