Skip to content

Commit 2b0ed9e

Browse files
Merge pull request #307140 from mattchenderson/mcp-java
Updating MCP extension for language stacks
2 parents 224c05d + da8bc15 commit 2b0ed9e

2 files changed

Lines changed: 100 additions & 58 deletions

File tree

articles/azure-functions/functions-bindings-mcp-trigger.md

Lines changed: 74 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -90,33 +90,41 @@ This code creates an endpoint to expose a tool named `SaveSnippets` that tries t
9090
```java
9191
@FunctionName("SaveSnippets")
9292
@StorageAccount("AzureWebJobsStorage")
93-
public void saveSnippet(
93+
public String saveSnippet(
9494
@McpToolTrigger(
95-
toolName = "saveSnippets",
96-
description = "Saves a text snippet to your snippets collection.",
97-
toolProperties = SAVE_SNIPPET_ARGUMENTS
95+
name = "saveSnippets",
96+
description = "Saves a text snippet to your snippets collection."
9897
)
99-
String toolArguments,
100-
@BlobOutput(name = "outputBlob", path = BLOB_PATH)
98+
String mcpToolInvocationContext,
99+
@McpToolProperty(
100+
name = "snippetName",
101+
propertyType = "string",
102+
description = "The name of the snippet.",
103+
required = true
104+
)
105+
String snippetName,
106+
@McpToolProperty(
107+
name = "snippet",
108+
propertyType = "string",
109+
description = "The content of the snippet.",
110+
required = true
111+
)
112+
String snippet,
113+
@BlobOutput(name = "outputBlob", path = "snippets/{mcptoolargs.snippetName}.json")
101114
OutputBinding<String> outputBlob,
102115
final ExecutionContext context
103116
) {
104117
// Log the entire incoming JSON for debugging
105-
context.getLogger().info(toolArguments);
106-
107-
// Parse the JSON and extract the snippetName/snippet fields
108-
JsonObject arguments = JsonParser.parseString(toolArguments)
109-
.getAsJsonObject()
110-
.getAsJsonObject("arguments");
111-
String snippetName = arguments.get(SNIPPET_NAME_PROPERTY_NAME).getAsString();
112-
String snippet = arguments.get(SNIPPET_PROPERTY_NAME).getAsString();
118+
context.getLogger().info(mcpToolInvocationContext);
113119

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

118124
// Write the snippet content to the output blob
119125
outputBlob.setValue(snippet);
126+
127+
return "Successfully saved snippet '" + snippetName + "' with " + snippet.length() + " characters.";
120128
}
121129
```
122130

@@ -125,31 +133,37 @@ This code creates an endpoint to expose a tool named `GetSnippets` that tries to
125133
```java
126134
@FunctionName("GetSnippets")
127135
@StorageAccount("AzureWebJobsStorage")
128-
public void getSnippet(
136+
public String getSnippet(
129137
@McpToolTrigger(
130-
toolName = "getSnippets",
131-
description = "Gets a text snippet from your snippets collection.",
132-
toolProperties = GET_SNIPPET_ARGUMENTS
138+
name = "getSnippets",
139+
description = "Gets a text snippet from your snippets collection."
140+
)
141+
String mcpToolInvocationContext,
142+
@McpToolProperty(
143+
name = "snippetName",
144+
propertyType = "string",
145+
description = "The name of the snippet.",
146+
required = true
133147
)
134-
String toolArguments,
135-
@BlobInput(name = "inputBlob", path = BLOB_PATH)
148+
String snippetName,
149+
@BlobInput(name = "inputBlob", path = "snippets/{mcptoolargs.snippetName}.json")
136150
String inputBlob,
137151
final ExecutionContext context
138152
) {
139153
// Log the entire incoming JSON for debugging
140-
context.getLogger().info(toolArguments);
141-
142-
// Parse the JSON and get the snippetName field
143-
String snippetName = JsonParser.parseString(toolArguments)
144-
.getAsJsonObject()
145-
.getAsJsonObject("arguments")
146-
.get(SNIPPET_NAME_PROPERTY_NAME)
147-
.getAsString();
154+
context.getLogger().info(mcpToolInvocationContext);
148155

149156
// Log the snippet name and the fetched snippet content from the blob
150157
context.getLogger().info("Retrieving snippet with name: " + snippetName);
151158
context.getLogger().info("Snippet content:");
152159
context.getLogger().info(inputBlob);
160+
161+
// Return the snippet content or a not found message
162+
if (inputBlob != null && !inputBlob.trim().isEmpty()) {
163+
return inputBlob;
164+
} else {
165+
return "Snippet '" + snippetName + "' not found.";
166+
}
153167
}
154168
```
155169

@@ -272,17 +286,16 @@ For the complete code example, see [snippetsMcpTool.ts](https://github.com/Azure
272286
::: zone-end
273287
::: zone pivot="programming-language-python"
274288

275-
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.
289+
This code uses the `mcp_tool_trigger` decorator to create an endpoint to expose a tool named `save_snippet` that tries to persist a named code snippet to blob storage.
276290

277291
```python
278-
@app.generic_trigger(
292+
@app.mcp_tool_trigger(
279293
arg_name="context",
280-
type="mcpToolTrigger",
281-
toolName="save_snippet",
294+
tool_name="save_snippet",
282295
description="Save a snippet with a name.",
283-
toolProperties=tool_properties_save_snippets_json,
296+
tool_properties=tool_properties_save_snippets_json,
284297
)
285-
@app.generic_output_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
298+
@app.blob_output(arg_name="file", connection="AzureWebJobsStorage", path=_BLOB_PATH)
286299
def save_snippet(file: func.Out[str], context) -> str:
287300
content = json.loads(context)
288301
snippet_name_from_args = content["arguments"][_SNIPPET_NAME_PROPERTY_NAME]
@@ -299,17 +312,16 @@ def save_snippet(file: func.Out[str], context) -> str:
299312
return f"Snippet '{snippet_content_from_args}' saved successfully"
300313
```
301314

302-
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.
315+
This code uses the `mcp_tool_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.
303316

304317
```python
305-
@app.generic_trigger(
318+
@app.mcp_tool_trigger(
306319
arg_name="context",
307-
type="mcpToolTrigger",
308-
toolName="get_snippet",
320+
tool_name="get_snippet",
309321
description="Retrieve a snippet by name.",
310-
toolProperties=tool_properties_get_snippets_json,
322+
tool_properties=tool_properties_get_snippets_json,
311323
)
312-
@app.generic_input_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
324+
@app.blob_input(arg_name="file", connection="AzureWebJobsStorage", path=_BLOB_PATH)
313325
def get_snippet(file: func.InputStream, context) -> str:
314326
"""
315327
Retrieves a snippet by name from Azure Blob Storage.
@@ -348,34 +360,40 @@ See [Usage](#usage) to learn how to define properties of the endpoint as input p
348360

349361
## Annotations
350362

351-
The `McpTrigger` annotation creates a function that exposes a tool endpoint in your remote MCP server.
363+
The `@McpToolTrigger` annotation creates a function that exposes a tool endpoint in your remote MCP server.
352364

353365
The annotation supports the following configuration options:
354366

355367
|Parameter | Description|
356368
|---------|----------------------|
357-
| **toolName**| (Required) name of the tool that's being exposed by the MCP trigger endpoint. |
369+
| **name**| (Required) name of the tool that's being exposed by the MCP trigger endpoint. |
358370
| **description**| (Optional) friendly description of the tool endpoint for clients. |
359-
| **toolProperties** | The JSON string representation of one or more property objects that expose properties of the tool to clients. |
371+
372+
The `@McpToolProperty` annotation defines individual properties for your tools. Each property parameter in your function should be annotated with this annotation.
373+
374+
The `@McpToolProperty` annotation supports the following configuration options:
375+
376+
|Parameter | Description|
377+
|---------|----------------------|
378+
| **name**| (Required) name of the tool property that gets exposed to clients. |
379+
| **propertyType**| (Required) type of the tool property. Valid types are: `string`, `number`, `integer`, `boolean`, `object`. |
380+
| **description**| (Optional) description of what the tool property does. |
381+
| **required** | (Optional) if set to `true`, the tool property is required as an argument for tool calls. Defaults to `false`. |
360382

361383
::: zone-end
362384
::: zone pivot="programming-language-python"
363385
## Decorators
364386

365387
_Applies only to the Python v2 programming model._
366388

367-
>[!NOTE]
368-
>At this time, you must use a generic decorator to define an MCP trigger.
369-
370-
The following MCP trigger properties are supported on `generic_trigger`:
389+
The `mcp_tool_trigger` decorator requires version 1.24.0 or later of the [`azure-functions` package](https://pypi.org/project/azure-functions/). The following MCP trigger properties are supported on `mcp_tool_trigger`:
371390

372391
| Property | Description |
373392
|-------------|-----------------------------|
374-
| **type** | (Required) Must be set to `mcpToolTrigger` in the `generic_trigger` decorator. |
375393
| **arg_name** | The variable name (usually `context`) used in function code to access the execution context. |
376-
| **toolName** | (Required) The name of the MCP server tool exposed by the function endpoint. |
394+
| **tool_name** | (Required) The name of the MCP server tool exposed by the function endpoint. |
377395
| **description** | A description of the MCP server tool exposed by the function endpoint. |
378-
| **toolProperties** | The JSON string representation of one or more property objects that expose properties of the tool to clients. |
396+
| **tool_properties** | The JSON string representation of one or more property objects that expose properties of the tool to clients. |
379397

380398
::: zone-end
381399
::: zone pivot="programming-language-javascript,programming-language-typescript"
@@ -506,7 +524,12 @@ For the complete example, see the [`Program.cs` file](https://github.com/Azure-S
506524
---
507525

508526
::: zone-end
509-
::: zone pivot="programming-language-java,programming-language-python,programming-language-javascript,programming-language-typescript"
527+
::: zone pivot="programming-language-java"
528+
In Java, you define tool properties by using the `@McpToolProperty` annotation on individual function parameters. Each parameter that represents a tool property should be annotated with this annotation, specifying the property name, type, description, and whether it's required.
529+
530+
You can see these annotations used in the [Examples](#example).
531+
::: zone-end
532+
::: zone pivot="programming-language-python,programming-language-javascript,programming-language-typescript"
510533
You can configure tool properties in the trigger definition's `toolProperties` field, which is a string representation of an array of `ToolProperty` objects.
511534

512535
A `ToolProperty` object has this structure:

articles/azure-functions/functions-bindings-mcp.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,33 @@ The Azure Functions MCP extension allows you to use Azure Functions to create re
4040
Add the extension to your project by installing this [NuGet package](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Mcp) in your preferred way:
4141

4242
`Microsoft.Azure.Functions.Worker.Extensions.Mcp`
43-
::: zone-end
44-
::: zone pivot="programming-language-javascript,programming-language-typescript,programming-language-python,programming-language-java"
45-
<!---At GA, replace with:
43+
::: zone-end
44+
::: zone pivot="programming-language-java"
45+
+ Requires version 3.2.1 or later of the [`azure-functions-java-library` dependency](https://central.sonatype.com/artifact/com.microsoft.azure.functions/azure-functions-java-library).
46+
+ Requires version **TBD** or later of the [`azure-functions-maven-plugin` dependency](https://central.sonatype.com/artifact/com.microsoft.azure.functions/azure-functions-maven-plugin).
47+
::: zone-end
48+
::: zone pivot="programming-language-javascript,programming-language-typescript"
49+
+ Requires version 4.8.0 or later of the [`@azure/functions` dependency](https://www.npmjs.com/package/@azure/functions)
50+
::: zone-end
51+
::: zone pivot="programming-language-python"
52+
+ Requires version 1.24.0 or later of the [`azure-functions` package](https://pypi.org/project/azure-functions/).
53+
::: zone-end
54+
::: zone pivot="programming-language-javascript,programming-language-typescript,programming-language-python,programming-language-java"
55+
4656
[!INCLUDE [functions-install-extension-bundle](../../includes/functions-install-extension-bundle.md)]
47-
-->
48-
> [!IMPORTANT]
49-
> A generally available version of the extension is now available. However, it isn’t yet included in the default extension bundle. The instructions show how to use the preview extension bundle, which includes an earlier preview version of the MCP extension, along with other preview dependencies. For now, to use the generally available version of the extension, you must [manually install the extension](./functions-bindings-register.md#explicitly-install-extensions).
50-
[!INCLUDE [functions-extension-bundles-json-preview](../../includes/functions-extension-bundles-json-preview.md)]
57+
58+
The MCP extension specifically requires bundle version 4.28.0 or later. You can ensure you get this version by specifying it as the minimum version in your `host.json` file:
59+
60+
```json
61+
{
62+
"version": "2.0",
63+
"extensionBundle": {
64+
"id": "Microsoft.Azure.Functions.ExtensionBundle",
65+
"version": "[4.28.0, 5.0.0)"
66+
}
67+
}
68+
```
69+
5170
::: zone-end
5271

5372
## host.json settings

0 commit comments

Comments
 (0)