MCP Server with Azure Functions: Part 2


In Part 1 of this series, we created a simple hello_mcp
Azure Function and walked through how to test it locally and deploy it to the Azure cloud. That was a great starting point for understanding how Model Context Protocol (MCP) tools can be implemented using Azure Functions.
In this second part, weโll take the next step by implementing an MCP tool that accepts arguments โ specifically, two integers that are added together. This will demonstrate how to structure your Azure Function to handle structured input from the MCP system and return meaningful output or error messages when things go wrong. You can refer to the full code from function_app.py.
๐ง What is an MCP Tool ?
An MCP (Model Context Protocol) tool allows you to expose custom logic to LLM-powered applications like GitHub Copilot or Visual Studio Code. By creating these tools, developers can integrate their own backend logic into AI-assisted workflows.
In this case, our tool will be called add_integers
, and it will accept two integer inputs and return their sum.
๐ ๏ธ The Structure of Our Azure Function
We're going to create an Azure Function that uses the mcpToolTrigger
binding, which allows the function to be invoked as an MCP tool. The function will:
Accept two integers (
num_a
andnum_b
)Add them together
Return the result in JSON format
๐ Constants and Property Definitions
To maintain consistency and clarity, we define constants for the property names:
_PROPERTY_A_NAME = "num_a"
_PROPERTY_B_NAME = "num_b"
Then, we use a helper class ToolProperty
to describe each parameter expected by the tool:
class ToolProperty:
def __init__(self, property_name: str, property_type: str, description: str):
self.propertyName = property_name
self.propertyType = property_type
self.description = description
def to_dict(self):
return {
"propertyName": self.propertyName,
"propertyType": self.propertyType,
"description": self.description,
}
This helps us generate a valid schema for the tool properties in the required JSON format.
๐ฆ Defining the Tool Properties
We then define the list of expected properties:
tool_properties_add_integers_object = [
ToolProperty(_PROPERTY_A_NAME, "integer", "The first integer to add."),
ToolProperty(_PROPERTY_B_NAME, "integer", "The second integer to add."),
]
tool_properties_add_integers_json = json.dumps(
[prop.to_dict() for prop in tool_properties_add_integers_object]
)
This JSON will be passed to the mcpToolTrigger
so that the MCP system knows what inputs to expect.
๐ Azure Function Implementation
Now comes the main function decorated with the @app.generic_trigger
decorator:
@app.generic_trigger(
arg_name="context",
type="mcpToolTrigger",
toolName="add_integers",
description="Adds two integers and returns the sum.",
toolProperties=tool_properties_add_integers_json,
)
def add_integers_tool(context: str) -> str:
...
The function expects a JSON string in the context
argument containing the actual input values under the "arguments"
key.
โ Input Validation
Inside the function, we perform several checks:
Ensure the context is valid JSON.
Check if the
"arguments"
key exists.Make sure both
num_a
andnum_b
are present.Convert the values to integers, handling any conversion errors.
If any of these steps fail, we return an appropriate error message in JSON format.
โ Performing the Addition
Once the inputs are validated and parsed:
result = num_a + num_b
return json.dumps({"sum": result})
We log the operation and return the result wrapped in a JSON object.
โ ๏ธ Error Handling
We wrap everything in a try-except
block to catch unexpected issues and return descriptive error messages:
except json.JSONDecodeError:
logging.error(f"Failed to decode JSON from context: {context}")
return json.dumps({"error": "Invalid JSON format in input context."})
except Exception as e:
logging.error(f"An unexpected error occurred: {str(e)}")
return json.dumps({"error": f"An unexpected error occurred: {str(e)}"})
๐งช Testing Locally
Follow Part 1 if you want to learn about local deployment of azure function.
To test this function locally from the project directory:
Start the Azure Functions server:
source .venv/bin/activate func start
Use MCP Inspector to verify that your MCP tool function has been deployed. For a guide on MCP Inspector Usage follow Install MCP Inspector and Check with MCP Inspector from Part 1 .
You should see logs indicating the function was triggered and receive a response like:
โ๏ธ Deploying to Azure
Once tested locally, deploy the function using the instruction from part 1 .
After deployment, the function will be accessible via its public URL. You can now register this tool with the MCP system.
๐ฏ Summary
In this blog post, weโve built on the foundation from Part 1 and created an MCP tool using Azure Functions that:
Accepts two integer inputs
Validates the inputs and handles errors gracefully
Returns a structured JSON response
Can be tested locally and deployed to Azure
This pattern can be extended to implement more complex logic, such as calling external APIs, processing files, or integrating with databases โ all while being exposed as a tool for Copilot experiences.
๐ Next Steps
In the next part of this series, we'll explore how to implement MCP tools for Postgre SQL server, allowing your LLM to access necessary features of your sql server.
Stay tuned!
Subscribe to my newsletter
Read articles from Mustahid Ahmed directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
