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
1 change: 1 addition & 0 deletions src/FunctionsMcpPrompts/.funcignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.venv
47 changes: 47 additions & 0 deletions src/FunctionsMcpPrompts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
bin
obj
csx
.vs
edge
Publish

*.user
*.suo
*.cscfg
*.Cache
project.lock.json

/packages
/TestResults

/tools/NuGet.exe
/App_Data
/secrets
/data
.secrets
appsettings.json

node_modules
dist

# Local python packages
.python_packages/

# Python Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Azurite artifacts
__blobstorage__
__queuestorage__
__azurite_db*__.json
91 changes: 91 additions & 0 deletions src/FunctionsMcpPrompts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# FunctionsMcpPrompts — MCP Prompts on Azure Functions (Python)

This project is a Python Azure Function app that exposes MCP (Model Context Protocol) prompts as a remote MCP server. Prompts are reusable prompt templates that MCP clients can discover and invoke, optionally with arguments.

> **Note:** MCP tools are in the [FunctionsMcpTool](../FunctionsMcpTool/) project.

## Prompts included

| Prompt | Arguments | Description |
|--------|-----------|-------------|
| `code_review_checklist` | _(none)_ | Returns a structured code review checklist for evaluating code changes. |
| `summarize_content` | `topic` (required), `audience` (optional) | Generates a summarization prompt tailored to a given topic and audience. |
| `generate_documentation` | `function_name` (optional), `style` (optional) | Generates API documentation for a function. |

## Key concepts

- **Simple prompts** (like `code_review_checklist`) take no arguments and return static prompt text.
- **Parameterized prompts** use `prompt_arguments` to accept arguments from the client.
- Prompts can define arguments as required or optional, and read them from `context.arguments`.

## Prerequisites

- [Python](https://www.python.org/downloads/) version 3.13 or higher
- [Azure Functions Core Tools](https://learn.microsoft.com/azure/azure-functions/functions-run-local?pivots=programming-language-python#install-the-azure-functions-core-tools) >= `4.8.0`
- `azure-functions` version 2.2.0b2 or greater
- .NET SDK (for building the MCP extension)

## Run locally

### 1. Build the MCP extension

From this directory (`src/FunctionsMcpPrompts`), build the MCP extension:

```shell
dotnet restore extensions.csproj
dotnet build extensions.csproj
```

### 2. Install Dependencies

Create and activate a virtual environment, then install dependencies:

```shell
python3 -m venv .venv

# macOS/Linux
source .venv/bin/activate

# Windows
.venv\Scripts\activate

pip install -r requirements.txt
```

### 3. Start the Functions host

```shell
func start
```

The MCP endpoint will be available at `http://localhost:7071/runtime/webhooks/mcp`.

## Deploy to Azure

```shell
azd env set DEPLOY_SERVICE prompts
azd provision
azd deploy --service prompts
```

## Examining the code

Prompts are defined in `function_app.py`. Each prompt is a Python function with the `@app.mcp_prompt_trigger` decorator:

```python
@app.mcp_prompt_trigger(
arg_name="context",
prompt_name="summarize_content",
prompt_arguments=[
func.PromptArgument("topic", "The topic or content to summarize.", required=True),
func.PromptArgument("audience", "Target audience (e.g., 'executive', 'developer', 'beginner').", required=False)
],
description="Generates a summarization prompt tailored to a given topic and audience."
)
def summarize_content(context: func.PromptInvocationContext) -> str:
topic = context.arguments.get("topic", "")
audience = context.arguments.get("audience")
# Returns a formatted prompt string
```

The `prompt_arguments` parameter defines the arguments that MCP clients see when they list available prompts.
17 changes: 17 additions & 0 deletions src/FunctionsMcpPrompts/extensions.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<WarningsAsErrors></WarningsAsErrors>
<DefaultItemExcludes>**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Extensions.Mcp" Version="1.4.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.3.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.3" />
</ItemGroup>
<ItemGroup>
<None Update="app/dist/*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
90 changes: 90 additions & 0 deletions src/FunctionsMcpPrompts/function_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import azure.functions as func
import logging

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

# Simple prompt with no arguments. Returns a static code review checklist.
# Demonstrates the basic mcp_prompt_trigger usage.
@app.mcp_prompt_trigger(
arg_name="context",
prompt_name="code_review_checklist",
description="Returns a structured code review checklist prompt for evaluating code changes."
)
def code_review_checklist(context: func.PromptInvocationContext) -> str:
logging.info("Code review checklist prompt invoked.")

return """You are a senior software engineer performing a code review.
Use the following checklist to evaluate the code:

1. **Correctness** — Does the code do what it's supposed to?
2. **Error Handling** — Are edge cases and failures handled?
3. **Security** — Are there any vulnerabilities (injection, auth, secrets)?
4. **Performance** — Are there obvious inefficiencies?
5. **Readability** — Is the code clear and well-named?
6. **Tests** — Are there adequate tests for the changes?

Provide your feedback in a structured format with a severity level
(critical, warning, suggestion) for each finding."""


# Prompt with arguments.
# Generates a context-aware summarization prompt for a given topic and audience.
@app.mcp_prompt_trigger(
arg_name="context",
prompt_name="summarize_content",
prompt_arguments=[
func.PromptArgument("topic", "The topic or content to summarize.", required=True),
func.PromptArgument("audience", "Target audience (e.g., 'executive', 'developer', 'beginner').", required=False)
],
description="Generates a summarization prompt tailored to a given topic and audience."
)
def summarize_content(context: func.PromptInvocationContext) -> str:
topic = context.arguments.get("topic", "")
audience = context.arguments.get("audience")

logging.info(f"Summarize prompt invoked for topic: {topic}")

audience_instruction = (
f"Tailor the summary for a **{audience}** audience."
if audience is not None
else "Write the summary for a general technical audience."
)

return f"""Summarize the following topic concisely and accurately:

**Topic:** {topic}

{audience_instruction}

Guidelines:
- Start with a one-sentence overview.
- Include 3–5 key points as bullet items.
- End with a brief conclusion or recommendation.
- Keep the total length under 300 words."""


# Prompt with arguments for generating API documentation.
@app.mcp_prompt_trigger(
arg_name="context",
prompt_name="generate_documentation",
prompt_arguments=[
func.PromptArgument("function_name", "The name of the function to document.", required=False),
func.PromptArgument("style", "Documentation style: 'concise', 'detailed', or 'tutorial'.", required=False)
],
description="Generates API documentation for a function. Arguments are configured in Program.cs."
)
def generate_documentation(context: func.PromptInvocationContext) -> str:
function_name = context.arguments.get("function_name", "(unknown)")
style = context.arguments.get("style", "concise")

logging.info(f"Generate docs prompt invoked for function: {function_name}")

return f"""Generate API documentation for the function named **{function_name}**.

Documentation style: **{style}**

Include the following sections:
- **Description** — What the function does.
- **Parameters** — List each parameter with its type and purpose.
- **Return Value** — What the function returns.
- **Example Usage** — A short code example showing how to call it."""
19 changes: 19 additions & 0 deletions src/FunctionsMcpPrompts/host.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "2.0",
"extensions": {
"mcp": {
"system": {
"webhookAuthorizationLevel": "Anonymous"
}
}
},
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
},
"enableLiveMetricsFilters": true
}
}
}
7 changes: 7 additions & 0 deletions src/FunctionsMcpPrompts/local.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "python",
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
}
}
5 changes: 5 additions & 0 deletions src/FunctionsMcpPrompts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Do not include azure-functions-worker in this file
# The Python Worker is managed by the Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues

azure-functions --pre