Edit

Share via


MCP tool trigger for Azure Functions

Use the MCP tool trigger to define tool endpoints in a Model Content Protocol (MCP) server that are accessed by client language models and agents to do specific tasks, such as storing or accessing code snippets. MCP clients can also subscribe to your function app to receive notifications about changes to the exposed tools.

Important

The Azure Functions MCP extension is currently in preview. You can expect changes to the trigger and binding APIs until the extension becomes generally available.
You should avoid using preview extensions in production apps.

For information on setup and configuration details, see the overview.

Example

Note

The Azure Functions MCP extension supports only the isolated worker model.

This code creates an endpoint to expose a tool named GetSnippet that tries to retrieve a code snippet by name from blob storage.

private const string BlobPath = "snippets/{mcptoolargs." + SnippetNamePropertyName + "}.json";

[Function(nameof(GetSnippet))]
public object GetSnippet(
    [McpToolTrigger(GetSnippetToolName, GetSnippetToolDescription)]
        ToolInvocationContext context,
    [BlobInput(BlobPath)] string snippetContent
)
{
    return snippetContent;
}

This code creates an endpoint to expose a tool named SaveSnippet that tries to persist a named code snippet to blob storage.

private const string BlobPath = "snippets/{mcptoolargs." + SnippetNamePropertyName + "}.json";
[Function(nameof(SaveSnippet))]
[BlobOutput(BlobPath)]
public string SaveSnippet(
    [McpToolTrigger(SaveSnippetToolName, SaveSnippetToolDescription)]
        ToolInvocationContext context,
    [McpToolProperty(SnippetNamePropertyName, PropertyType, SnippetNamePropertyDescription)]
        string name,
    [McpToolProperty(SnippetPropertyName, PropertyType, SnippetPropertyDescription)]
        string snippet
)
{
    return snippet;
}

For the complete code example, see SnippetTool.cs.

This code creates an endpoint to expose a tool named GetSnippets that tries to retrieve a code snippet by name from blob storage.

@FunctionName("GetSnippets")
@StorageAccount("AzureWebJobsStorage")
public void getSnippet(
        @McpToolTrigger(
                toolName = "getSnippets",
                description = "Gets a text snippet from your snippets collection.",
                toolProperties = GET_SNIPPET_ARGUMENTS
        )
        String toolArguments,
        @BlobInput(name = "inputBlob", path = BLOB_PATH)
        String inputBlob,
        final ExecutionContext context
) {
    // Log the entire incoming JSON for debugging
    context.getLogger().info(toolArguments);

    // Parse the JSON and get the snippetName field
    String snippetName = JsonParser.parseString(toolArguments)
            .getAsJsonObject()
            .getAsJsonObject("arguments")
            .get(SNIPPET_NAME_PROPERTY_NAME)
            .getAsString();

    // Log the snippet name and the fetched snippet content from the blob
    context.getLogger().info("Retrieving snippet with name: " + snippetName);
    context.getLogger().info("Snippet content:");
    context.getLogger().info(inputBlob);
}

This code creates an endpoint to expose a tool named SaveSnippets that tries to persist a named code snippet to blob storage.

@FunctionName("SaveSnippets")
@StorageAccount("AzureWebJobsStorage")
public void saveSnippet(
        @McpToolTrigger(
                toolName = "saveSnippets",
                description = "Saves a text snippet to your snippets collection.",
                toolProperties = SAVE_SNIPPET_ARGUMENTS
        )
        String toolArguments,
        @BlobOutput(name = "outputBlob", path = BLOB_PATH)
        OutputBinding<String> outputBlob,
        final ExecutionContext context
) {
    // Log the entire incoming JSON for debugging
    context.getLogger().info(toolArguments);

    // Parse the JSON and extract the snippetName/snippet fields
    JsonObject arguments = JsonParser.parseString(toolArguments)
            .getAsJsonObject()
            .getAsJsonObject("arguments");
    String snippetName = arguments.get(SNIPPET_NAME_PROPERTY_NAME).getAsString();
    String snippet = arguments.get(SNIPPET_PROPERTY_NAME).getAsString();

    // Log the snippet name and content
    context.getLogger().info("Saving snippet with name: " + snippetName);
    context.getLogger().info("Snippet content:\n" + snippet);

    // Write the snippet content to the output blob
    outputBlob.setValue(snippet);
}

For the complete code example, see Snippets.java.

Example code for JavaScript isn't currently available. See the TypeScript examples for general guidance using Node.js.

This code creates an endpoint to expose a tool named getsnippet that tries to retrieve a code snippet by name from blob storage.

  }

  // Save the snippet to blob storage using the output binding
  context.extraOutputs.set(blobOutputBinding, snippet);

  console.info(`Saved snippet: ${snippetName}`);
  return snippet;
}

// Register the GetSnippet tool
app.mcpTool("getSnippet", {
  toolName: GET_SNIPPET_TOOL_NAME,
  description: GET_SNIPPET_TOOL_DESCRIPTION,

This is the code that handles the getsnippet trigger:


// GetSnippet function - retrieves a snippet by name
export async function getSnippet(
  _toolArguments: unknown,
  context: InvocationContext
): Promise<string> {
  console.info("Getting snippet");

  // Get snippet name from the tool arguments
  const mcptoolargs = context.triggerMetadata.mcptoolargs as {
    snippetname?: string;
  };
  const snippetName = mcptoolargs?.snippetname;

  console.info(`Snippet name: ${snippetName}`);

  if (!snippetName) {
    return "No snippet name provided";
  }

  // Get the content from blob binding - properly retrieving from extraInputs
  const snippetContent = context.extraInputs.get(blobInputBinding);

This code creates an endpoint to expose a tool named savesnippet that tries to persist a named code snippet to blob storage.

      propertyName: SNIPPET_NAME_PROPERTY_NAME,
      propertyType: PROPERTY_TYPE,
      description: SNIPPET_NAME_PROPERTY_DESCRIPTION,
    },
  ],
  extraInputs: [blobInputBinding],
  handler: getSnippet,
});

// Register the SaveSnippet tool
app.mcpTool("saveSnippet", {
  toolName: SAVE_SNIPPET_TOOL_NAME,
  description: SAVE_SNIPPET_TOOL_DESCRIPTION,
  toolProperties: [
    {
      propertyName: SNIPPET_NAME_PROPERTY_NAME,
      propertyType: PROPERTY_TYPE,
      description: SNIPPET_NAME_PROPERTY_DESCRIPTION,

This is the code that handles the savesnippet trigger:

  }

  console.info(`Retrieved snippet: ${snippetName}`);
  return snippetContent as string;
}

// SaveSnippet function - saves a snippet with a name
export async function saveSnippet(
  _toolArguments: unknown,
  context: InvocationContext
): Promise<string> {
  console.info("Saving snippet");

  // Get snippet name and content from the tool arguments
  const mcptoolargs = context.triggerMetadata.mcptoolargs as {
    snippetname?: string;
    snippet?: string;
  };

  const snippetName = mcptoolargs?.snippetname;
  const snippet = mcptoolargs?.snippet;

  if (!snippetName) {
    return "No snippet name provided";
  }

For the complete code example, see snippetsMcpTool.ts.

This code uses the generic_trigger decorator to create an endpoint to expose a tool named get_snippet that tries to retrieve a code snippet by name from blob storage.

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="get_snippet",
    description="Retrieve a snippet by name.",
    toolProperties=tool_properties_get_snippets_json,
)
@app.generic_input_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
def get_snippet(file: func.InputStream, context) -> str:
    """
    Retrieves a snippet by name from Azure Blob Storage.

    Args:
        file (func.InputStream): The input binding to read the snippet from Azure Blob Storage.
        context: The trigger context containing the input arguments.

    Returns:
        str: The content of the snippet or an error message.
    """
    snippet_content = file.read().decode("utf-8")
    logging.info(f"Retrieved snippet: {snippet_content}")
    return snippet_content

This code uses the generic_trigger decorator to create an endpoint to expose a tool named save_snippet that tries to persist a named code snippet to blob storage.

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="save_snippet",
    description="Save a snippet with a name.",
    toolProperties=tool_properties_save_snippets_json,
)
@app.generic_output_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
def save_snippet(file: func.Out[str], context) -> str:
    content = json.loads(context)
    snippet_name_from_args = content["arguments"][_SNIPPET_NAME_PROPERTY_NAME]
    snippet_content_from_args = content["arguments"][_SNIPPET_PROPERTY_NAME]

    if not snippet_name_from_args:
        return "No snippet name provided"

    if not snippet_content_from_args:
        return "No snippet content provided"

    file.set(snippet_content_from_args)
    logging.info(f"Saved snippet: {snippet_content_from_args}")
    return f"Snippet '{snippet_content_from_args}' saved successfully"

For the complete code example, see function_app.py.

Important

The MCP extension doesn't currently support PowerShell apps.

Attributes

C# libraries use McpToolTriggerAttribute to define the function trigger.

The attribute's constructor takes the following parameters:

Parameter Description
ToolName (Required) name of the tool that's being exposed by the MCP trigger endpoint.
Description (Optional) friendly description of the tool endpoint for clients.

See Usage to learn how to define properties of the endpoint as input parameters.

Annotations

The McpTrigger annotation creates a function that exposes a tool endpoint in your remote MCP server.

The annotation supports the following configuration options:

Parameter Description
toolName (Required) name of the tool that's being exposed by the MCP trigger endpoint.
description (Optional) friendly description of the tool endpoint for clients.
toolProperties The JSON string representation of one or more property objects that expose properties of the tool to clients.

Decorators

Applies only to the Python v2 programming model.

Note

At this time, you must use a generic decorator to define an MCP trigger.

The following MCP trigger properties are supported on generic_trigger:

Property Description
type (Required) Must be set to mcpToolTrigger in the generic_trigger decorator.
arg_name The variable name (usually context) used in function code to access the execution context.
toolName (Required) The name of the MCP server tool exposed by the function endpoint.
description A description of the MCP server tool exposed by the function endpoint.
toolProperties The JSON string representation of one or more property objects that expose properties of the tool to clients.

Configuration

The trigger supports these binding options, which are defined in your code:

Options Description
type Must be set to mcpToolTrigger. Only used with generic definitions.
toolName (Required) The name of the MCP server tool exposed by the function endpoint.
description A description of the MCP server tool exposed by the function endpoint.
toolProperties An array of toolProperty objects that expose properties of the tool to clients.
extraOutputs When defined, sends function output to another binding.
handler The method that contains the actual function code.

See the Example section for complete examples.

Usage

The MCP protocol enables an MCP server to make known to clients other properties of a tool endpoint. In C#, you can define properties of your tools as either input parameters using the McpToolProperty attribute to your trigger function code or by using the FunctionsApplicationBuilder when the app starts.

You can define one or more tool properties by applying the McpToolProperty attribute to input binding-style parameters in your function.

The McpToolPropertyAttribute type supports these properties:

Property Description
PropertyName Name of the tool property that gets exposed to clients.
PropertyType The data type of the tool property, such as string.
Description (Optional) Description of what the tool property does.

You can see these attributes used in the SaveSnippet tool in the Examples.

Properties of a tool exposed by your remote MCP server are defined using tool properties. These properties are returned by the toolProperties field, which is a string representation of an array of ToolProperty objects.

A ToolProperty object has this structure:

{
    "propertyName": "Name of the property",
    "propertyType": "Type of the property",
    "description": "Optional property description",
}

Properties of a tool exposed by your remote MCP server are defined using tool properties. These properties are returned by the toolProperties field, which is a string representation of an array of ToolProperty objects.

A ToolProperty object has this structure:

{
    "propertyName": "Name of the property",
    "propertyValue": "Type of the property",
    "description": "Optional property description",
}

For more information, see Examples.

host.json settings

The host.json file contains settings that control MCP trigger behaviors. See the host.json settings section for details regarding available settings.

Azure OpenAI extension for Azure Functions