When a team "adds a tool" to an Agent, they often stack three different things under one word: the steps in SKILL.md, callable capabilities on an MCP server, and the JSON Schema on Function Calling / HTTP APIs. All three can contain JSON. They do not solve the same problem. This article is dated 2026-09-17: first split the three layers, then give a decision tree and a Tool Schema you can accept in the Workbench. For how Skills load on demand, see Why agents need Skills; for how the Responses API and MCP share one tools array, see DevDay 2026 Agent; for why the contract layer is JSON, see Why AI likes JSON.
By 2026, Agent products already speak three vocabularies at once. Cursor, Claude Code, and Codex scan SKILL.md. The same products also connect MCP. OpenAI Responses API, Claude tool_use, and Gemini function declarations still consume Function Calling. The "vs" in the title invites picking a side. Production more often stacks them: a Skill sets the order, MCP or an API executes, and a Schema validates. What you pick wrong is not a brand. It is a layer.
Why "choosing a tool" picks the wrong layer
"Adding a tool to an Agent" sounds like procurement. Failures usually look like these three:
- Treat a handbook as a tool. An 8-step release, incident severity, or diagram-type list becomes an MCP server. Each call returns a paragraph of instructions. The protocol idles. Context still grows.
- Turn a single function into a bus. Only your own backend calls
create_invoice, but you stand up MCP, auth, and Host config for it. Reuse is zero. The failure surface grows by one. - Write field types in prose. The Skill body says "price is a number." The API uses a string. The MCP
inputSchemacopies a third version. The three layers diverge. Validation drifts on all of them.
So ask three questions before you pick an implementation: Is this a step, or an action? How many Hosts will share this action? Can a Schema pin the inputs and outputs? Steps go in a Skill. Actions that need cross-Host reuse or isolated credentials go to MCP. Actions that only serve your own loop go to API / Function Calling. Write the contract as JSON Schema first.
One line. A Skill answers how. MCP answers access. An API answers "the contract for this hop." JSON Tool Schema is the hard interface of the last two layers โ and the part a Skill must not replace with prose.
Draw the three layers first: handbook, bus, interface
Strip the runtime and the three layers look like this:
The arrows are dependencies, not a requirement to run all three. An internal invoicing Agent can be Function Calling plus a short system prompt. A team that wants editors, CLIs, and a custom loop to share "look up an order" should put the action on MCP and the acceptance steps in a Skill.
SKILL.md: process knowledge, not a callable tool
An Agent Skill is a folder: SKILL.md at the root, YAML frontmatter with name and description, steps in the body. Long tables go in references/. Executable snippets go in scripts/. At startup the runtime only registers an index. It expands after a task match or a slash command. That is progressive loading, not RPC.
A Skill does not provide live data and does not execute side effects for you. It tells the Agent: read brand tokens before drawing; run these 8 steps before a release; on a failed DB lookup, check the error code before retrying or stopping. The tool itself still has to be wired separately. In the community, i-have-adhd constrains output shape and diagram-design loads a diagram-type handbook on demand โ both are process, not an action like "create a GitHub Release." Details in the previous article Why coding agents need Skills.
description is the most important line at this layer. "Handle incidents" will not route. Spell out trigger words and the applicability boundary, and it loads on the right task. That is the same engineering instinct as a tool description, one level up: pick the wrong Skill and you pick the wrong handbook.
Write the boundary in stone. Wrapping a single get_order in a Skill is usually waste. A Skill pays for itself when there are multiple steps, judgment, and stop conditions. A one-shot call belongs in the tool description.
MCP Server: a standardized tool runtime
MCP (Model Context Protocol) is a client-server protocol on JSON-RPC. A server exposes tools, resources, and prompts. A Host (Cursor, Claude Code, a custom Agent, or some vendors' remote MCP) discovers and calls them. You write the server once. Compatible Hosts can list the same tools. Transport can be local stdio or remote HTTP.
MCP buys these three things โ not "smarter than Function Calling":
- Reuse. The same lookup, issue-create, or browser-run capability does not need a new adapter for every Agent product.
- Isolation. Credentials and side effects stay in the server process. The model sees only tool names and Schema.
- Discovery. The Host lists tools by protocol. Description and
inputSchemadecide when the model reaches.
The tool contract is still JSON Schema. MCP's inputSchema (and the increasingly common outputSchema) is the same class of object as Function Calling's parameters. Only the wrapper fields differ. OpenAI's Responses API can already put remote MCP and your own functions in the same tools array โ the protocol landing on a platform does not mean you can skip the Schema. See Agent contracts after DevDay.
Do not stand up MCP for a function that only your own loop will call and that does not need isolation. Protocol, process, and Host config all cost. When reuse is zero, a direct API is shorter.
API / Function Calling: a direct business contract
API here means two things that get mixed together:
- Model-side Function Calling / tool calling. You declare
name,description, andparameters(JSON Schema) on the request. The model returns a structured call. Your code executes it and feeds the result back. OpenAI, Claude, and Gemini wrap it differently. The core is still that Schema. - Business HTTP / RPC. Your own invoicing, inventory, or search endpoints. The Agent eventually changes state in these systems. Function Calling can hit them directly, or an MCP server can wrap them.
Function Calling's advantage is short: no second process, no Host inventory, credentials stay in your backend. The downside is clear: switch Agent products and you re-declare. As tools grow, you have to lazy-load or retrieve them yourself, or descriptions fill the context.
Vendors also stuff built-in capabilities into the tools array (web, code execution, remote MCP). That is platform-hosted execution, not a reason to skip Schema. Your own actions still need validatable inputs and outputs. Definition: What is Structured Output; from a sample: How to generate a Schema.
JSON Tool Schema: the shared contract layer
The one thing that should be "written once, then distributed" across the three layers is the shape of the tool object. Maintain a core Schema, then wrap it:
- OpenAI function:
type: "function"+parameters. In strict mode the object often needsadditionalProperties: false. - Claude tool:
input_schema. - Gemini:
parameters/ function declarations, with a narrower usable subset. - MCP tool:
inputSchema, optionaloutputSchema.
A Skill does not replace this contract. A Skill can say "call get_order first; stop if order_id is missing." It cannot use a paragraph of prose to declare that total is a number. Field types, required fields, enums, and whether extra fields are allowed belong only in Schema. Otherwise the same tool silently forks between MCP and API.
When a coding agent edits mcp.json / settings.json, the same instinct applies: the file is a text patch; whether the object is right still depends on parse and Schema. See How agents edit JSON config.
Decision tree: when to use which layer
Ask in this order. You will stand up fewer useless servers and write fewer resident long prompts.
- Mostly steps, judgment, and stop conditions โ not a side effect? Write a Skill. Put trigger words in
description. Keep the body short. Long lists go inreferences/. - One action (or a few), and only your backend loop will call it? Function Calling or your own HTTP API. Put the Schema on the request. Execute in your process.
- The same action will be used by two or more Hosts, or credentials must leave the model process? Make an MCP server. The Host sees only the tool list and Schema.
- Both multi-step judgment and a real action? Skill + (MCP or API). The Skill owns order and acceptance. The tool owns execution. Do not collapse either layer into prose.
- You still don't have a parseable sample object? Don't pick a bus yet. Sample first, then Schema, then decide which layer it hangs on.
A rule of thumb: MCP's minimum reasonable size is "a second Host will connect" or "credentials cannot enter the prompt." A Skill's minimum reasonable size is "without it, the model skips steps or reaches on unrelated tasks."
Comparison table
| Skill | MCP | API / Function Calling | |
|---|---|---|---|
| Question it answers | When, and in what steps | Where tools come from, how to discover them | Inputs and outputs of this hop |
| Form | SKILL.md folder |
JSON-RPC server | In-request tool declaration or HTTP |
| Contract | frontmatter + Markdown | inputSchema / resource URI |
JSON Schema parameters |
| Loading | On demand after description match | Host lists; model decides to call | Declared with the request, or lazy retrieval |
| Side effects | None (unless scripts run) | In the server process | In your backend |
| Cross-product | Strong (open directory convention) | Strong (protocol layer) | Weak (each vendor wraps differently) |
| Fits | Handbooks, acceptance, output shape | Shared capabilities, isolated credentials | Single-app loops, short path |
The three are often used together: a Rule or short Skill pins "never commit secrets"; a Skill specifies "these 8 steps before release"; MCP provides "create a Release"; if the Release is only cut inside your own CI Agent, Function Calling is also fine. Maintain one Schema.
Common signals you picked the wrong layer
- MCP wrapping a paragraph of explanation. The call result is just a Markdown handbook. That is a Skill. It should not occupy a server.
- MCP for a single function. No second Host, no isolation need. Switch back to Function Calling.
- An 80-line lookup living in the system prompt. Unrelated tasks get the same context dump. Move it to a Skill. Leave one trigger line in the tool description.
- Three definitions of the same field. Skill prose, API Schema, and MCP Schema each write their own. Merge into one core object first.
- Using a Skill as auth. "Don't delete the production database" in a handbook will not stop a model that actually got
delete_*. Deny rules and least privilege live at the tool layer, not in Markdown. - Handing the entire MCP config to an Agent to rewrite. Arrays get overwritten. Comments disappear. Read first, then apply a minimal patch. See How to edit JSON config.
A Tool Schema you can accept locally
Below is the core object for an invoicing action. It is not yet an OpenAI / MCP wrapper โ only the contract. All three vendor wrappers and MCP inputSchema grow from this.
{
"tool": "create_invoice",
"description": "Create a draft invoice for an existing order. Use when the user asks to bill, issue, or generate an invoice. Do not call if order_id is missing.",
"arguments": {
"order_id": "ord_1042",
"currency": "USD",
"line_items": [
{
"sku": "seat-pro",
"quantity": 12,
"unit_cents": 4900
}
],
"require_approval": true
},
"result": {
"invoice_id": "inv_7781",
"status": "draft",
"total_cents": 58800
}
}
The matching core Schema should pin three things first: order_id / currency / line_items required; unit_cents is integer, not string; turn additionalProperties off on the object so the model cannot stuff in note. require_approval is a product decision. Do not leave it only in the Skill body โ if the tool layer cannot see it, it cannot stop a bad call.
On the Skill side, keep only the steps: stop if order_id is missing; get_order then create_invoice; do not send email if status is not draft. Those sentences do not go in the Schema.
How to accept it in JSON Toolbox
- Paste the
arguments/resultabove into JSON Format and confirm they parse. - Use JSON โ Schema or Structured Output to generate the core contract. Add required and
additionalProperties. - Run the same fields through Function Calling and MCP Tool separately. Do not copy two type systems.
- Validate a second set of real returns with Schema validation. When they don't match the sample, use JSON Diff.
All data is processed in the browser and never uploaded to a server. Have a validatable object first. Then decide whether it hangs behind a Skill, MCP, or an API.
FAQ
Are Agent Skills and MCP the same thing?
No. A Skill is a handbook: SKILL.md answers when, and in what steps. MCP is a bus: the server answers where tools come from, and how to discover and call them. A Skill does not connect a database. MCP does not write a release order.
If I already have Function Calling / API, why do I still need MCP?
Function Calling serves this one request. MCP lets multiple Hosts discover the same capability and keeps credentials in the server. One loop and no isolation need: skip MCP.
When should I write only an API and skip MCP?
The tool is only called by your own backend, credentials must not leave that process, and there is no second Host. MCP buys reuse and isolation, not a faster single call.
Which layer should JSON Tool Schema live on?
On the tool contract layer: Function Calling's parameters, or MCP's inputSchema. A Skill only writes steps and stop conditions. Maintain one core Schema, then wrap it per vendor.
How do I know I picked the wrong layer?
Standing up MCP for one function; a lookup living in the prompt; types specified in prose; API and MCP each copy a field set and they drift. Fold the object into a Schema first, then pick a bus.
Summary
Choosing tools for an AI Agent is not picking a winner among Skill, MCP, and API. A Skill collects repeatable professional process into an on-demand handbook. MCP collects actions that need cross-Host reuse or isolated credentials into a server. API / Function Calling collects actions that only serve your own loop into the shortest path. Under all three is the same JSON Tool Schema: types, required fields, and extra fields are pinned here. Wrappers can change. For developers, the next step is not standing up a server first, and not writing a longer prompt. It is producing a parseable sample object โ short index, hard contract, handbook on demand, bus that charges for reuse.