CertSafari
    CLAUDE-CERTIFIED-DEVELOPER-FOUNDATIONS-CCDV-F · Lessons

    Domain 8 · Lesson 25/25

    Built-in Tools, Custom Tools or MCP: Choosing How Claude Acts

    Agentic Customization

    9 min read
    3.53% of exam
    5 sources
    Published 29 Sep 2026
    Docs as of 26 Sep 2026

    What you will be able to do

    • Decide whether a task needs anything beyond an agent's built-in tools
    • Recognise when a custom tool is worth building, and how the Agent SDK registers one
    • Choose an MCP server when the capability lives in an external system

    Key concept

    Name the gap, then add the smallest fix — Each way of extending an agent fills a different gap. Built-in tools are actions the agent already has. A custom tool adds a function you write. MCP connects an outside system. A Skill adds knowledge or a workflow, not a new action. To choose well, first name what is actually missing.

    1.Start from the tools the agent already has

    Every agentic customization decision starts with the same step: work out what the agent can't do yet, then add the smallest thing that fixes it. There are four options. Built-in tools are actions the agent already has. A custom tool is a function you write. An MCP server connects an outside system. A Skill adds knowledge or a workflow instead of a new action. This page covers the first three. The cheapest option is always the one you don't have to build.

    Claude Code and the Agent SDK come with a working set of tools. Before you design anything, check whether that set already covers the job.

    A selection of built-in tools and whether each needs permission
    ToolWhat it doesPermission required
    ReadReads the contents of filesNo
    EditMakes targeted edits to specific filesYes
    WriteCreates or overwrites filesYes
    BashExecutes shell commands in your environmentYes
    GrepSearches for patterns in file contentsNo
    WebFetchFetches content from a specified URLYes
    SkillExecutes a skill within the main conversationYes
    ListMcpResourcesToolLists resources exposed by connected MCP serversNo

    Reading files, editing them, running shell commands and searching code are all built in. A refactor that stays inside the local repository needs no customization. Start with the built-ins and a clear prompt. Every layer you add is something else to maintain.

    A fintech startup is building an internal support agent with the Claude Agent SDK. The agent must look up account balances from a proprietary ledger service reachable only through an internal REST gateway with no existing MCP server or public SDK. Which approach best fits this requirement?

    On the Messages API the same tradeoff appears in a different form: who writes the tool's schema, and who runs its code?

    Messages API tool categories by schema author and executor
    Tool categoryWho writes the schemaWhere the call executes
    User-defined toolsYouYour application
    Anthropic-defined schemas, such as bash and text_editorAnthropic, which trains Claude on itYour application, which returns the tool_result
    Server tools, such as web_search, web_fetch, code_execution, tool_searchAnthropicAnthropic's infrastructure

    The middle row is the one people get wrong. Anthropic-defined tools such as bash and text_editor come with a schema Claude was trained on, so you don't have to design one. The call still goes to your application to run. Server tools are the only kind you neither define nor run.

    Sources12

    2.Write a custom tool when the logic is yours

    Build a custom tool when only you can supply the logic. Examples are a call to an internal API, a domain-specific calculation, or a lookup against data the agent can't reach with Bash or Read. The cost is that you now own the whole contract: you write the schema, and your application runs every call.

    In the Agent SDK a tool has four parts: a name Claude calls it by, a description, an input schema and an async handler. The description matters most, because it is the text Claude reads when deciding whether the tool fits a request.

    Defining a tool in TypeScript: name, description and a Zod input schematypescript
    // Define a tool: name, description, input schema, handler
    const getTemperature = tool(
      "get_temperature",
      "Get the current temperature at a location",
      {
        latitude: z.number().describe("Latitude coordinate"), // .describe() adds a field description Claude sees
        longitude: z.number().describe("Longitude coordinate")
      },

    You can't pass the SDK a bare tool. You register it by wrapping it in an in-process MCP server and passing that server to query(). The tool then gets a name prefixed with the server's name, and that prefixed name is also what you pre-approve:

    Wrapping the tool in an in-process MCP servertypescript
    // Wrap the tool in an in-process MCP server
    const weatherServer = createSdkMcpServer({
      name: "weather",
      version: "1.0.0",
      tools: [getTemperature]
    });
    Passing the server to query() and pre-approving the tooltypescript
    for await (const message of query({
      prompt: "What's the temperature in San Francisco?",
      options: {
        mcpServers: { weather: weatherServer },
        allowedTools: ["mcp__weather__get_temperature"]
      }
    })) {

    Claude reads whatever the handler returns. The result must contain a content array, and each block's type must be text, image, audio, resource or resource_link. It can also include structuredContent for machine-readable data. Setting isError: true lets you write the failure message Claude sees, rather than passing along the raw exception.

    Two more settings control how your tool sits alongside the built-ins. Setting readOnlyHint: true on a tool with no side effects lets Claude call it in parallel. Passing a tools array that lists only the built-ins you want removes the others from Claude's context.

    A platform team keeps pasting the same multi-step production deployment checklist into chat every time someone ships a release, and the steps sometimes get skipped when typed manually. What is the most appropriate way to address this in Claude Code?

    Sources32

    3.Connect an MCP server when the system lives elsewhere

    When the capability lives in someone else's system, the answer is usually MCP, the protocol Claude Code uses to connect to external services. The features guide gives Slack, database queries and browser control as examples. Its rule of thumb is concrete: if you keep copying data out of a browser tab Claude can't see, connect that system as an MCP server.

    If a service already publishes an MCP server, connecting it in Claude Code takes one command:

    Adding a remote HTTP MCP server in Claude Codebash
    # Real example: Connect to Notion
    claude mcp add --transport http notion https://mcp.notion.com/mcp

    Claude then has the service's tools and you have written no handlers. Typical uses are building features from issue trackers, analysing monitoring data and querying databases. A server can even act as a channel that pushes messages into your session, so Claude responds to outside events. On the Messages API, the MCP connector reaches remote MCP servers without you building a separate MCP client. If the same server name is configured at more than one scope, only one applies: local beats project, and project beats user.

    The three action-adding options side by side
    OptionPick it whenWhat you take on
    Built-in toolsThe job is files, shell, search or web on the agent's own machineNothing to build. Narrow the set with a tools array if needed
    Custom toolThe logic is yours: internal APIs, domain calculationsName, description, schema and handler, wrapped with createSdkMcpServer
    MCP serverThe capability lives in an external serviceConnect it (for example with claude mcp add). Configure scope and auth

    Sources452

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Tools with Anthropic-defined schemas, such as bash and text_editor, run on Anthropic's servers the way web_search does.Why is that wrong?

      They are client tools. Anthropic supplies the schema, but your application still runs every call and returns the result.

      Covered in Start from the tools the agent already has

    2. 2.An Agent SDK custom tool is a separate mechanism from MCP, so building one means you are not using MCP.Why is that wrong?

      The SDK registers custom tools by wrapping them in an in-process MCP server that you pass to query().

      Covered in Write a custom tool when the logic is yours

    3. 3.Claude decides when to call a custom tool from its input schema.Why is that wrong?

      The schema defines the arguments. Claude reads the description to decide when to call the tool.

      Covered in Write a custom tool when the logic is yours

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
    2. 2.
      “Tools differ primarily by where the code executes.”
      ↩︎ Start from the tools the agent already has
      “Client tools (including user-defined tools and tools with Anthropic-defined schemas, such as bash and text_editor) run in your application.”
      ↩︎ Start from the tools the agent already has
      “For tools you define, you write the schema and your application executes each call.”
      ↩︎ Write a custom tool when the logic is yours
      “Connect to remote MCP servers from the Messages API without a separate MCP client.”
      ↩︎ Connect an MCP server when the system lives elsewhere
      “Anthropic publishes the schema and trains Claude on it. Your application still executes each call and returns the tool_result.”
      ↩︎ Exam trap 1
    3. 3.
      “Use @tool (Python) or tool() (TypeScript) with a name, description, schema, and handler.”
      ↩︎ Write a custom tool when the logic is yours
      “Return isError: true to compose the message instead of surfacing the raw exception.”
      ↩︎ Write a custom tool when the logic is yours
      “Set readOnlyHint: true on tools with no side effects.”
      ↩︎ Write a custom tool when the logic is yours
      “Pass a tools array listing only the built-ins you want.”
      ↩︎ Write a custom tool when the logic is yours
      “Wrap in create_sdk_mcp_server / createSdkMcpServer and pass to mcpServers in query().”
      ↩︎ Exam trap 2
      “Description: what the tool does. Claude reads this to decide when to call it.”
      ↩︎ Exam trap 3
    4. 4.
      “Protocol for connecting to external services”
      ↩︎ Connect an MCP server when the system lives elsewhere
      “Connect that system as an MCP server”
      ↩︎ Connect an MCP server when the system lives elsewhere
      “MCP servers override by name: local > project > user.”
      ↩︎ Connect an MCP server when the system lives elsewhere
      “MCP connects Claude to external services and tools”
      ↩︎ Key concept
    5. 5.
      “an MCP server can also act as a channel that pushes messages into your session”
      ↩︎ Connect an MCP server when the system lives elsewhere

    Continue to page 2 of 2

    Agent Skills vs MCP, Hooks and CLAUDE.md: When to Use a Skill