Build More Tools

In the previous chapter, our MCP server currently has only one tool:

Calculator MCP Server

add()

That’s a good start, but a calculator should be able to do more than addition.

Let’s add three more tools:

Calculator MCP Server

add

subtract

multiply

divide

By the end of this chapter, our MCP server will support the four basic arithmetic operations.


βž– 7.1 Add the Subtract Tool

Let’s start with subtraction.

Add this function to server.py:

@mcp.tool()
def subtract(a: int, b: int) -> int:
"""Subtract the second number from the first number."""
return a - b

The tool takes two numbers:

a
b

and returns:

a - b

For example:

subtract(20, 5)

returns:

15

Notice that the structure is very similar to our add() tool.

@mcp.tool()
def subtract(a: int, b: int) -> int:
"""Subtract the second number from the first number."""
return a - b

The @mcp.tool() decorator exposes the function as an MCP tool.


βœ–οΈ 7.2 Add the Multiply Tool

Next, let’s add multiplication.

@mcp.tool()
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b

For example:

multiply(10, 5)

returns:

50

Our server now has:

Calculator MCP Server

add

subtract

multiply


βž— 7.3 Add the Divide Tool

Finally, let’s add division.

@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide the first number by the second number."""
return a / b

We are using float here because division doesn’t always produce a whole number.

For example:

divide(10, 2)

returns:

5.0

And:

divide(10, 4)

returns:

2.5

But there’s a problem.

What happens if someone tries:

divide(10, 0)

We need to handle that.


🚫 7.4 Handle Invalid Input

Division by zero isn’t a valid mathematical operation.

Instead of allowing our function to fail unexpectedly, we should handle it explicitly.

Update the function:

@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide the first number by the second number."""
if b == 0:
raise ValueError("Cannot divide by zero.")
return a / b

Now our tool checks the input before performing the calculation.

If b is zero:

divide(10, 0)

the tool raises an error:

Cannot divide by zero.

This is an important principle when building MCP tools:

Tools should handle invalid inputs explicitly rather than allowing unexpected failures.


🧾 7.5 Our Complete Calculator Server

Our server.py now looks like this:

from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Calculator Server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@mcp.tool()
def subtract(a: int, b: int) -> int:
"""Subtract the second number from the first number."""
return a - b
@mcp.tool()
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide the first number by the second number."""
if b == 0:
raise ValueError("Cannot divide by zero.")
return a / b
if __name__ == "__main__":
mcp.run()

We now have four MCP tools.

Calculator MCP Server

add(a, b)

subtract(a, b)

multiply(a, b)

divide(a, b)


πŸ“ 7.6 Tool Descriptions Matter

Notice that every tool has a description:

"""Add two numbers together."""
"""Subtract the second number from the first number."""
"""Multiply two numbers together."""
"""Divide the first number by the second number."""

These descriptions are not just comments for developers.

They become part of the information that an MCP client can discover about the tools.

The AI can use this information to understand what each tool does.

For example:

add
Description:
Add two numbers together.

and:

divide
Description:
Divide the first number by the second number.

Clear descriptions become increasingly important as the number of tools grows.


πŸ”„ 7.7 Restart the MCP Server

Whenever we change our Python code, restart the server so that the new tools are loaded.

Stop the running server and start it again:

Terminal window
python server.py

Our MCP client can now discover all four tools.

add
subtract
multiply
divide

πŸ§ͺ 7.8 Try the New Tools

Let’s test them through our MCP client.

Ask:

What is 25 + 15?

The client can use:

add(25, 15)

Result:

40

Try subtraction:

What is 50 - 18?

The tool call is:

subtract(50, 18)

Result:

32

Try multiplication:

What is 12 Γ— 5?

The tool call is:

multiply(12, 5)

Result:

60

And division:

What is 20 divided by 4?

The tool call is:

divide(20, 4)

Result:

5

⚠️ 7.9 What Happens With an Error?

Now try:

What is 10 divided by 0?

The client may attempt:

divide(10, 0)

Our server checks:

if b == 0:
raise ValueError("Cannot divide by zero.")

Instead of returning an incorrect result, the tool reports an error.

The client can then use that result to explain what went wrong.

This demonstrates why error handling matters for MCP tools.

Tools are ultimately code running on a server, so they need the same defensive programming practices as any other application.


βœ… 7.10 What We Have Built

We started with one tiny function:

add(10, 20)

Now we have a complete calculator:

MCP Server

Calculator Server

add

subtract

multiply

divide

Our tools have:

  • Names
  • Descriptions
  • Parameters
  • Parameter types
  • Return types
  • Input validation
  • Error handling

More importantly, we now understand the basic lifecycle:

Discover tools

Call selected tool

MCP Client

MCP Server

add

subtract

multiply

divide

Tool executes

Result / Error

This small calculator may seem simple, but the exact same pattern can be used to build much more powerful MCP servers.

For example, a real-world MCP server could expose tools for:

search_documents()
query_database()
create_ticket()
get_customer()
send_email()
search_products()

The difference is that those tools perform useful real-world operations instead of arithmetic.

And that’s the real power of MCP: we can expose capabilities from our own applications to AI clients through a standard interface.