Skip to main content

MCP vs Agent Skills: What Each One Adds to an Agent, Measured on Bedrock with Strands

Generative AIPalaniappan P10 min read

Quick summary: On 23 October 2026 we ran one refund-triage job 120 times on Bedrock with Strands 1.62. MCP alone passed 0 of 30 and approved an out-of-window $129 refund 10 times. A Skill alone passed 0 of 30. Both together passed 30 of 30.

Key Takeaways

  • On 23 October 2026 we ran one refund-triage job 120 times on Bedrock with Strands 1.62
  • MCP alone passed 0 of 30 and approved an out-of-window $129 refund 10 times
  • A Skill alone passed 0 of 30
  • Both together passed 30 of 30
  • On 23 October 2026 we gave one Strands agent one job: decide a refund
Navy paper cube holding an open notebook, with mustard-yellow cables running from it to a panel of sockets
Table of Contents

On 23 October 2026 we gave one Strands agent one job: decide a refund. We ran it on Amazon Bedrock (claude-haiku-4-5, us-east-1, Strands Agents 1.62.0, MCP Python SDK 2.1.1) in four setups, 10 runs per task, 120 runs in all. With the order data over MCP and the refund policy in a Skill, it got 30 of 30 right. With MCP alone it got 0 of 30, and it approved a $129 refund outside the return window in all 10 tries. With the Skill alone it also got 0 of 30, but it never guessed: every time, it asked for the order fields it needed.

That is the whole argument in numbers. MCP gives agents reach. Skills give them know-how. The rest of this post explains what each one is, how each one enters the model’s context, what each costs in tokens, and how to build your own on Bedrock with Strands. The benchmark code and raw results are public.

What MCP is

The Model Context Protocol is the connection layer. An MCP server is a separate process that exposes tools (and optionally resources and prompts). The agent’s MCP client lists those tools at startup and passes their names, descriptions, and JSON input schemas to the model. When the model decides to call one, the client forwards the call, the server talks to the real system, and the result comes back into the conversation.

What this buys you is one interface for many systems. A database query, a SaaS API, an AWS account, and an internal order service all look the same to the agent: a named tool with a schema. You write the integration once, as a server, and any MCP-capable agent can use it, whether that is Strands, Claude Code, Kiro, or AgentCore Gateway.

What it costs: every listed tool’s schema rides along on every model request. In our run, three small tools added 835 input tokens to a request that otherwise costs 34.

What an Agent Skill is

A Skill is a reusable playbook. It is a folder with a SKILL.md file: YAML frontmatter with a name and a description, then a Markdown body with the procedure, rules, and conventions. It can also carry scripts/, references/, and assets/. A Skill adds no service and no network hop. It runs inside the agent’s existing environment.

Skills use progressive disclosure. The agent sees only each Skill’s name and description up front. When a task matches the description, the model calls a tool to load the full body, and from then on it follows that procedure. In Strands that tool is called skills, and it is registered by the AgentSkills plugin, which follows the agentskills.io layout.

In our run, the full refund-triage body (about 170 words of rules) cost nothing until the model asked for it. The plugin’s fixed overhead did not: 719 input tokens per request, mostly the skills tool schema plus the metadata block. One Skill is not much cheaper to carry than three MCP tools. The saving shows up when you have 20 Skills and the agent needs one.

Why both exist

They answer different questions.

  • MCP answers “can the agent see and touch the system?” Without it, our agent did not know the headphones cost $249 or were delivered on 8 October. A prompt cannot fix that unless a person pastes the data in.
  • A Skill answers “does the agent know how we do this here?” Without it, our agent read the right order and then applied a generic idea of a return policy. Your 15-day window for opened electronics, your 15% restocking fee, and your $200 approval threshold live nowhere in the model’s training data.

Teams usually reach for whichever one they already know. Platform engineers build an MCP server and wonder why the agent makes bad calls with good data. Prompt-minded teams write a long policy file and wonder why the agent hallucinates order dates. The benchmark below shows both failures side by side.

How each works at runtime

Diagram: a Skill's name and description enter the system prompt on every request and its body loads on demand; an MCP server's tool schemas enter every request and tool results return when the model calls a tool

Per request, the model sees:

  1. Your system prompt.
  2. Skills: an <available_skills> block with each Skill’s name, description, and location, appended by the plugin before every invocation. Plus the skills tool schema.
  3. MCP: the name, description, and input schema of every tool the client listed.
  4. The conversation so far, including any Skill body already loaded and any tool results.

So a Skill is cheap to have and costs real tokens only when used. An MCP tool costs its schema on every turn whether it is used or not. That asymmetry matters once you list 40 tools from five servers. It matters much less with three.

MCP vs Skills, side by side

MCP serverAgent Skill
AddsAccess to a system: read, write, actProcedure: rules, steps, output format
Lives inA separate process (stdio or streamable HTTP)A folder of files the agent can read
Fixed context cost (our run)835 tokens for 3 tools, every request719 tokens for 1 Skill + plugin, every request
On-demand costEach tool resultThe SKILL.md body, once per conversation
CredentialsHeld by the serverNone; it reuses the agent’s tools
VersioningDeploy the serverEdit and review a Markdown file
Failure when missing (our run)Agent asks for data, or invents a placeholderAgent applies a generic policy to real data
Security surfaceTool permissions, auth, network (MCP security)Prompt-injection risk in the file; scripts run with the agent’s permissions

Same prompt, four setups

Every run got the same user message, a one-line request plus a required JSON format:

Order FM-1063: the customer wants a refund for the blender.

Reply with a JSON block: {"order_id": str, "decision": "approve" | "deny",
"refund_amount_usd": number, "needs_human_approval": bool}

The system prompt was one line: a support assistant for an online store, today is 2026-10-20. The blender was delivered on 12 September, 38 days earlier. The Skill’s 30-day window says deny.

SetupWhat the model hadWhat it answered (10 of 10 runs identical)Correct?
No MCP, no SkillThe prompt"decision": "deny", "needs_human_approval": true, after saying it had no order dataNo: approval flag wrong, decision was a guess
MCP onlyOrder data via get_order"decision": "approve", "refund_amount_usd": 129.0. Its reasoning: “not marked as final sale, so a refund is eligible”No: a $129 refund the policy forbids
Skill onlyRefund policy via skillsNo decision. Asked for final-sale flag, delivery date, price, category, and opened statusNo by the grader, and the safe failure
MCP + SkillBoth"decision": "deny", 0, "needs_human_approval": false, citing the 30-day ruleYes

The “without” alternative is the prompt you would have to write by hand: paste the order record, then paste the whole policy, on every request. That works for one ticket. It does not survive a policy change across 40 prompt templates, and it puts the person, not a tool, in charge of fetching the right order.

You write in the promptThe agent fetches or loads
Without MCP or a SkillOrder id, item, price, delivery date, opened flag, final-sale flag, every policy ruleNothing
MCP onlyEvery policy ruleOrder record
Skill onlyOrder id, item, price, delivery date, opened flag, final-sale flagPolicy
MCP + SkillOrder FM-1063: the customer wants a refund for the blender.Order record and policy

Benchmark: what we measured

First-party benchmark — Run on 23 October 2026, 08:23 UTC. Strands Agents 1.62.0, mcp 2.1.1, Python 3.14, us.anthropic.claude-haiku-4-5-20251001-v1:0 in us-east-1, temperature 0. Three tasks against a synthetic order fixture (not a real store), four setups, N=10 per cell. A run passes only if decision, amount (±$0.01), and approval flag all match the expected answer and the agent did not call issue_refund. Raw rows: results.json. Summary: summary.md.

TaskExpectedNo MCP, no SkillMCP onlySkill onlyMCP + Skill
Opened headphones, $249, day 12Approve $211.65, needs approval0/10 (“pending”)0/10 (approved $249.00)0/10 (asked for data)10/10
Clearance jacket, final saleDeny, no approval0/10 (approval flag)0/10 (approval flag)0/10 (asked for data)10/10
Blender, day 38Deny, no approval0/10 (approval flag)0/10 (approved $129.00)0/10 (asked for data)10/10
Median input tokens882,0212,0442,908
Median seconds2.84.23.64.5
Fixed overhead (“reply OK”)348697531,091

Three things stand out.

Correctness came only from the pair. The jump from 0 to 30 out of 30 cost 887 extra input tokens per decision over MCP alone, about 44% more, and 0.4 seconds of median latency.

MCP alone failed in the expensive direction. It overpaid the headphones by $37.35 (no restocking fee) and approved the out-of-window blender in every run. A person reviewing a queue of these would see confident, well-formatted JSON built on real data. That is harder to catch than an agent that admits it does not know.

The Skill alone failed in the safe direction. The SKILL.md says “If you cannot see the order data, say which fields you need. Do not guess dates or prices.” The model followed that line in 30 of 30 runs. Our grader counts it as a fail because there is no decision. In a live support queue it is the behavior you want.

What broke — Building the artifact on 23 October 2026, the first MCP run died with MCPClientInitializationError: the client initialization failed. The server subprocess had crashed on import: mcp 2.x renamed FastMCP to MCPServer, so from mcp.server.fastmcp import FastMCP raises ModuleNotFoundError. Strands only reports the closed connection, not the server’s traceback. We found it by running the server file directly, switched to from mcp.server.mcpserver import MCPServer, and pinned mcp==2.1.1. Second failure, same day: the default model id we planned to use returned AccessDeniedException ... is not available for this account, so the published run uses Haiku 4.5. A bigger model may close some of the MCP-only gap. It will not know your restocking fee.

One more observation, without a failure attached: the MCP-only agent said the blender was delivered “39 days ago” in all 10 runs. It was 38. The policy outcome is the same here. Date math you care about belongs in a script the Skill calls, not in the model’s head.

Build your own on Bedrock with Strands

The full project is in examples/architecture-blog-2026/mcp-vs-agent-skills/. The three pieces:

1. An MCP server. Python 3.12+, mcp==2.1.1, stdio transport. Tool docstrings become the descriptions the model reads, so write them for the model.

from mcp.server.mcpserver import MCPServer

mcp = MCPServer("order-tools")

@mcp.tool()
def get_order(order_id: str) -> dict:
    """Look up one order by id (for example FM-1042). Returns item, category, price, delivery date, opened and final_sale flags."""
    return next((o for o in ORDERS if o["order_id"] == order_id), {"error": f"order {order_id} not found"})

if __name__ == "__main__":
    mcp.run()

2. A Skill. Plain Markdown in skills/refund-triage/SKILL.md. The folder name must match name, or Strands logs a warning (and raises in strict=True mode). The description is the trigger, so name the situations it covers.

---
name: refund-triage
description: Decide whether a return or refund request is eligible and how much to refund. Use for any refund, return, or exchange question about an order.
---

# Refund triage

1. **Final sale.** If the order is `final_sale: true`, deny. Refund 0.
2. **Return window.** More than 30 days since `delivered_on`: deny.
3. **Opened electronics.** 15-day window; inside it, refund price × 0.85.
4. **Everything else inside the window:** approve the full price.

Any approved refund above $200.00 sets `needs_human_approval: true`.
Never call a refund or payment tool. You propose; a person executes.
If you cannot see the order data, say which fields you need. Do not guess.

3. The agent. Strands Agents 1.62.0 on Bedrock. MCPClient starts the server as a subprocess and lists its tools. AgentSkills injects the metadata and registers the skills tool.

from mcp import StdioServerParameters, stdio_client
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from strands.vended_plugins.skills import AgentSkills

server = StdioServerParameters(command="python", args=["mcp_server/order_tools.py"])
orders = MCPClient(lambda: stdio_client(server))

with orders:
    agent = Agent(
        model=BedrockModel(model_id="us.anthropic.claude-haiku-4-5-20251001-v1:0", region_name="us-east-1", temperature=0),
        system_prompt="You are a support assistant for an online store. Today is 2026-10-20.",
        tools=orders.list_tools_sync(),
        plugins=[AgentSkills(skills=["./skills/refund-triage"])],
    )
    print(agent("Order FM-1042: the customer wants a refund for the headphones."))

result.metrics.accumulated_usage gives you input and output tokens per call, and result.metrics.tool_metrics gives tool call counts. That is all bench.py reads.

Reproduce this — Download examples/architecture-blog-2026/mcp-vs-agent-skills/. uv sync, then AWS_PROFILE=your-profile uv run bench.py --n 10. It makes 124 agent runs and writes results/summary.md with the pass counts and token medians above. Use MODEL_ID=... to rerun on a different model.

Advantages, and the trade-off

MCP’s advantages: one integration serves every MCP-capable agent; credentials stay in the server, not the prompt; the same server can run locally over stdio or remotely behind AgentCore Gateway or the managed AWS MCP Server.

Skills’ advantages: a reviewer can read the whole procedure in a pull request; changing a rule is a text edit, not a deploy; dozens can be installed while only the matching one enters context; and they travel between agents that follow the same layout, which is why AWS shipped 43 of them in the Agent Toolkit for AWS in May 2026.

Our recommendation: when an agent gives wrong answers, check which half is missing before you build anything. If it says “I don’t have access to,” add an MCP tool. If it has the data and still decides wrong, write a Skill. Start with read-only tools and one Skill per decision type. The trade-off is context: in our run, the pair cost 2,908 input tokens per decision against 2,021 for MCP alone, and every extra MCP server adds its schemas to every turn. Past roughly a dozen tools, filter the tool list per agent instead of loading every server.

Neither layer solves the next problem. A refund agent also needs the right customer history, the right policy version, and retrieval over documents too large for a Skill. That is a data and context question: S3 Vectors behind AgentCore is where we would go next.

If You Only Do One Thing

Take the agent you already have and run its last 10 wrong answers through one question: did it lack access or procedure? Fix that half first. Then take write tools such as issue_refund off the agent’s tool list until a named person approves the action. A Skill line saying “never call it” held in all 120 runs here, and it is still only an instruction.

What This Post Doesn’t Cover

  • MCP security. Auth, tool poisoning, and network exposure are in MCP security for enterprise AI.
  • Remote MCP and AgentCore. We ran stdio on one machine. We have not measured Gateway-hosted tools or Harness Skills with this workload.
  • Bigger models. The run used Haiku 4.5 because it was the model this account could call. We have not rerun on Sonnet or Opus.
  • Many Skills. With one Skill, progressive disclosure saves little. We did not measure 20 Skills competing for one trigger.
  • Real data. The orders are a four-row synthetic fixture. Real tickets are messier, and the pass rate will be lower.

Frequently asked questions

What is the difference between MCP and Agent Skills?
MCP is a protocol for connecting an agent to outside systems. An MCP server exposes tools, and the model discovers and calls them. An Agent Skill is a folder with a SKILL.md file, plus optional scripts and references, that tells the agent how to do a task. MCP adds access. A Skill adds procedure. In our 120-run benchmark, neither one alone produced a correct refund decision; both together passed 30 of 30.
Do Agent Skills cost fewer tokens than MCP?
Less than people expect. In Strands 1.62 on Bedrock, one Skill added 719 input tokens of fixed overhead per request, because the AgentSkills plugin also registers a skills tool with its own schema. Three MCP tools added 835. The metadata-only claim is true for the SKILL.md body, which loads only when the task matches, but the plugin itself is not free.
When should I not write a Skill?
When the procedure changes faster than you can review a file, or when it depends on live data the agent cannot see. A Skill that says 'check the return window' is useless without a tool that returns the delivery date. In our run the Skill-only setup asked for the order fields 30 times out of 30 and never produced a decision.
When should I not add an MCP server?
When the agent already has the data and the problem is judgment. Access without policy is the riskier failure. Our MCP-only setup read the correct order every time and still approved a $129 refund outside the 30-day window in 10 of 10 runs, and overpaid the opened-headphones refund by $37.35 in 10 of 10.
Is a Skill rule like 'never call the refund tool' a security control?
No. It is an instruction to the model. In 120 runs the agent never called issue_refund, but that is a behavior we observed, not a guarantee. Remove write tools from the agent's tool list, or put them behind an approval step, if a person has to sign off. Prompt text is not an authorization boundary.
Can I use MCP and Skills with Amazon Bedrock AgentCore instead of a local Strands agent?
Yes. AgentCore Gateway can host MCP tools server-side, and AgentCore Harness supports Skills. This benchmark ran a local Strands agent against Bedrock to keep the moving parts small. We have not rerun it on AgentCore.
Palaniappan P
Palaniappan P

AWS Cloud Architect & AI Expert

AWS-certified cloud architect and AI expert with deep expertise in cloud migrations, cost optimization, and generative AI on AWS.

AWS ArchitectureCloud MigrationGenAI on AWSCost OptimizationDevOps

Recommended Reading

Explore All Articles »