Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion samples/FunctionsMcpTool/local.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "java"
"FUNCTIONS_WORKER_RUNTIME": "java",
"FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI": "https://cdn-staging.functions.azure.com/public"
Comment on lines +5 to +6
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI is set to the staging CDN. Committing this in the sample can cause local runs to fetch potentially unstable bundles and can break for users if the staging endpoint changes. Prefer omitting this setting or pointing to the production CDN, and if staging is required for a specific feature, document that requirement explicitly in the sample docs.

Suggested change
"FUNCTIONS_WORKER_RUNTIME": "java",
"FUNCTIONS_EXTENSIONBUNDLE_SOURCE_URI": "https://cdn-staging.functions.azure.com/public"
"FUNCTIONS_WORKER_RUNTIME": "java"

Copilot uses AI. Check for mistakes.
}
}
14 changes: 12 additions & 2 deletions samples/FunctionsMcpTool/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<azure.functions.maven.plugin.version>1.40.0</azure.functions.maven.plugin.version>
<azure.functions.java.library.version>3.2.2</azure.functions.java.library.version>
<azure.functions.maven.plugin.version>1.42.0</azure.functions.maven.plugin.version>
<azure.functions.java.library.version>3.3.0</azure.functions.java.library.version>
<functionAppName>HelloWorld-MCP</functionAppName>
</properties>

Expand All @@ -23,6 +23,16 @@
<artifactId>azure-functions-java-library</artifactId>
<version>${azure.functions.java.library.version}</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-mcp</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-json-jackson2</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.McpPromptArgument;
import com.microsoft.azure.functions.annotation.McpPromptTrigger;

/**
* Demonstrates MCP Prompt functions that expose prompt templates to MCP clients.
* Clients discover prompts via prompts/list and invoke them via prompts/get.
*
* Return a plain string (auto-wrapped into a single user message by the host)
* or a JSON-serialized GetPromptResult for multi-message / rich content responses.
*/
public class PromptExamples {

/**
* A code review prompt with multiple arguments (1 required, 1 optional).
* Uses McpPromptArgument annotations to define arguments in a strongly-typed way.
*/
@FunctionName("CodeReviewPrompt")
public String codeReviewPrompt(
@McpPromptTrigger(
name = "code_review",
description = "Generates a code review prompt for the given code snippet",
title = "Code Review")
String context,
@McpPromptArgument(
name = "code",
description = "The code to review",
isRequired = true)
String code,
@McpPromptArgument(
name = "language",
description = "The programming language")
String language,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Generating code review prompt");

String lang = (language != null && !language.isEmpty()) ? language : "unknown";
String snippet = (code != null && !code.isEmpty()) ? code : "// no code provided";

return "Please review the following " + lang + " code and suggest improvements:\n\n```"
+ lang + "\n" + snippet + "\n```";
}

/**
* A summarize prompt with a single required argument and plain string return.
* The host auto-wraps the returned string into a PromptMessage with role "user".
*/
@FunctionName("SummarizePrompt")
public String summarizePrompt(
@McpPromptTrigger(
name = "summarize",
description = "Summarizes the provided text",
title = "Summarize Text")
String context,
@McpPromptArgument(
name = "text",
description = "The text to summarize",
isRequired = true)
String text,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Generating summarize prompt");

String input = (text != null && !text.isEmpty()) ? text : "No text provided";
return "Please provide a concise summary of the following text:\n\n" + input;
}

/**
* A prompt with no arguments. Tests the edge case of a prompt
* that takes no user input.
*/
@FunctionName("NoArgsPrompt")
public String noArgsPrompt(
@McpPromptTrigger(
name = "no_args_prompt",
description = "A prompt that requires no arguments",
title = "No Arguments Prompt")
String context,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Generating no-args prompt");
return "This prompt requires no arguments. Please provide general guidance.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.McpToolProperty;
import com.microsoft.azure.functions.annotation.McpToolTrigger;
import com.microsoft.azure.functions.mcp.McpContent;
import com.microsoft.azure.functions.mcp.McpToolResult;
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

McpToolResult is imported but never used in this file; please remove the unused import to avoid compilation warnings (and potential checkstyle failures if enabled).

Suggested change
import com.microsoft.azure.functions.mcp.McpToolResult;

Copilot uses AI. Check for mistakes.
import io.modelcontextprotocol.spec.McpSchema.Content;
import io.modelcontextprotocol.spec.McpSchema.ImageContent;
import io.modelcontextprotocol.spec.McpSchema.TextContent;

import java.util.Arrays;
import java.util.List;

/**
* Demonstrates structured content support in Azure Functions MCP tools.
*
* <p>These examples show three approaches for returning rich content from MCP tools:</p>
* <ol>
* <li>{@link #getSnippetStructured} — {@code @McpContent}-annotated POJO (automatic text + structured content)</li>
* <li>{@link #renderImage} — Single content block (ImageContentBlock)</li>
* <li>{@link #getMultiContent} — Multiple content blocks (List of ContentBlock)</li>
Comment on lines +22 to +23
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class-level Javadoc refers to "ImageContentBlock" and "ContentBlock", but the actual return types used here are ImageContent and List<Content>. Updating the wording to match the concrete types will prevent confusion for readers trying to follow the examples.

Suggested change
* <li>{@link #renderImage} — Single content block (ImageContentBlock)</li>
* <li>{@link #getMultiContent} — Multiple content blocks (List of ContentBlock)</li>
* <li>{@link #renderImage} — Single content block ({@code ImageContent})</li>
* <li>{@link #getMultiContent} — Multiple content blocks ({@code List<Content>})</li>

Copilot uses AI. Check for mistakes.
* </ol>
*
* <p>Note: These functions require the {@code azure-functions-java-mcp} dependency which provides
* the middleware that wraps return values into the MCP result envelope.</p>
*/
public class StructuredContentExamples {

// ========================================================================
// Example 1: @McpContent-annotated POJO
// The middleware automatically creates both text content (for backwards
// compatibility) and structured content (for clients that support it).
// ========================================================================

/**
* A snippet POJO decorated with @McpContent. When returned from an MCP tool function,
* this will be serialized as both text content (JSON text) and structured content
* (JSON object), enabling MCP clients to parse the result programmatically.
*/
@McpContent
public static class SnippetResult {
private String name;
private String content;
private String language;

public SnippetResult() {
}

public SnippetResult(String name, String content, String language) {
this.name = name;
this.content = content;
this.language = language;
}

public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getLanguage() { return language; }
public void setLanguage(String language) { this.language = language; }
}

/**
* Returns a code snippet as structured content. The {@code @McpContent} annotation
* on {@code SnippetResult} tells the middleware to serialize the return value as both
* text content and structured content.
*
* <p>MCP clients that support structured content can parse the JSON object directly.
* Older clients will see the JSON as a text string.</p>
*/
@FunctionName("GetSnippetStructured")
public SnippetResult getSnippetStructured(
@McpToolTrigger(
name = "getSnippetStructured",
description = "Gets a code snippet with structured content support.")
String context,
@McpToolProperty(
name = "snippetName",
propertyType = "string",
description = "The name of the snippet to retrieve.",
isRequired = true)
String snippetName,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Getting structured snippet: " + snippetName);

return new SnippetResult(
snippetName,
"public class HelloWorld { public static void main(String[] args) { System.out.println(\"Hello!\"); } }",
"java"
);
}

// ========================================================================
// Example 2: Single content block (ImageContentBlock)
// For returning rich content types like images.
// ========================================================================

/**
* Returns an image as a single content block. The middleware wraps this
* in an MCP result envelope automatically.
*/
@FunctionName("RenderImage")
public ImageContent renderImage(
@McpToolTrigger(
name = "renderImage",
description = "Returns a base64-encoded image.")
String context,
@McpToolProperty(
name = "data",
propertyType = "string",
description = "Base64-encoded image data.",
isRequired = true)
String data,
@McpToolProperty(
name = "mimeType",
propertyType = "string",
description = "MIME type of the image (e.g., image/png).")
String mimeType,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Rendering image with MIME type: " + mimeType);

return new ImageContent(null, data, mimeType != null ? mimeType : "image/png");
}

// ========================================================================
// Example 3: Multiple content blocks
// For returning a list of mixed content types in a single response.
// ========================================================================

/**
* Returns multiple content blocks — a text description followed by an image.
* The middleware wraps this as a multi-content result.
*/
@FunctionName("GetMultiContent")
public List<Content> getMultiContent(
@McpToolTrigger(
name = "getMultiContent",
description = "Returns multiple content blocks including text and an image.")
String context,
@McpToolProperty(
name = "imageData",
propertyType = "string",
description = "Base64-encoded image data.",
isRequired = true)
String imageData,
final ExecutionContext executionContext) {

executionContext.getLogger().info("Generating multi-content response");

return Arrays.asList(
new TextContent("Here is the requested image:"),
new ImageContent(null, imageData, "image/png")
);
}
}
2 changes: 1 addition & 1 deletion samples/McpWeatherApp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<azure.functions.maven.plugin.version>1.41.0</azure.functions.maven.plugin.version>
<azure.functions.java.library.version>3.2.4</azure.functions.java.library.version>
<azure.functions.java.library.version>3.3.0</azure.functions.java.library.version>
<functionAppName>McpWeatherApp</functionAppName>
</properties>

Expand Down