func-Office-Word-MCP-Server

PlumyCat/func-Office-Word-MCP-Server

3.2

If you are the rightful owner of func-Office-Word-MCP-Server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

This document provides a comprehensive overview of setting up a Remote MCP Server using Azure Functions with Python, detailing its features, tools, resources, and usage across different platforms.

Tools
3
Resources
0
Prompts
0

Getting Started with Remote MCP Servers using Azure Functions (Python)

This is a quickstart template to easily build and deploy a custom remote MCP server to the cloud using Azure Functions with Python. You can clone/restore/run on your local machine with debugging, and azd up to have it in the cloud in a couple minutes. The MCP server is secured by design using keys and HTTPS, and allows more options for OAuth using built-in auth and/or API Management as well as network isolation using VNET.

If you're looking for this sample in more languages check out the .NET/C# and Node.js/TypeScript versions.

Open in GitHub Codespaces

Below is the architecture diagram for the Remote MCP Server using Azure Functions:

Architecture Diagram

Available MCP Tools

The server exposes the following tools:

  • hello_mcp
  • word_create_document
  • word_add_paragraph
  • word_get_text
  • word_add_heading
  • word_copy_document
  • word_search_and_replace
  • word_list_documents
  • word_list_templates
  • word_get_document_info
  • word_get_document_outline
  • word_add_table
  • word_add_picture
  • word_add_page_break
  • word_get_paragraph_text
  • word_find_text
  • word_format_text
  • word_delete_paragraph
  • word_create_custom_style
  • word_format_table
  • word_set_table_cell_shading
  • word_apply_table_alternating_rows
  • word_highlight_table_header
  • word_merge_table_cells
  • word_merge_table_cells_horizontal
  • word_merge_table_cells_vertical
  • word_set_table_cell_alignment
  • word_set_table_alignment_all
  • word_format_table_cell_text
  • word_set_table_cell_padding
  • word_set_table_column_width
  • word_set_table_width
  • word_auto_fit_table_columns
  • word_get_all_comments
  • word_get_comments_by_author
  • word_get_comments_for_paragraph
  • word_add_comment

See for an up-to-date list.

Microsoft Entra application permissions (Graph)

For the Word → PDF conversion via Microsoft Graph and SharePoint, create an app registration in Microsoft Entra ID and grant the following Application permissions (admin consent required). This approach does not require the docx2pdf library:

  • Files.ReadWrite.All
  • Sites.ReadWrite.All

After granting admin consent, configure the following settings in your Function App (local.settings.json or App Settings in Azure): TENANT_ID, CLIENT_ID, CLIENT_SECRET, SP_DRIVE_ID (or SP_SITE_ID).

The following screenshot illustrates the permissions setup:

Microsoft Entra API permissions

Prerequisites

Prepare your local environment

An Azure Storage Emulator is needed for this sample because the Word tools use Azure Blob Storage to store documents.

  1. Start Azurite

    docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
        mcr.microsoft.com/azure-storage/azurite
    

Note if you use Azurite coming from VS Code extension you need to run Azurite: Start now or you will see errors.

Run your MCP Server locally from the terminal

  1. Change to the src folder in a new terminal window:

    cd src
    
  2. Install Python dependencies:

    pip install -r requirements.txt
    

Note it is a best practice to create a Virtual Environment before doing the pip install to avoid dependency issues/collisions, or if you are running in CodeSpaces. See Python Environments in VS Code for more information.

  1. Start the Functions host locally:

    func start
    

Note by default this will use the webhooks route: /runtime/webhooks/mcp/sse. Later we will use this in Azure to set the key on client/host calls: /runtime/webhooks/mcp/sse?code=<system_key>

Connect to the local MCP server from a client/host

VS Code - Copilot agent mode

  1. Add MCP Server from command palette and add URL to your running Function app's SSE endpoint:

    http://0.0.0.0:7071/runtime/webhooks/mcp/sse
    
  2. List MCP Servers from command palette, choose your server, and select Start

  3. In Copilot chat agent mode enter a prompt to trigger a tool, for example:

    Say Hello
    
  4. When prompted to run the tool, consent by clicking Continue

  5. When you're done, press Ctrl+C in the terminal window to stop the Functions host process.

MCP Inspector

  1. In a new terminal window, install and run MCP Inspector

    npx @modelcontextprotocol/inspector
    
  2. CTRL click to load the MCP Inspector web app from the URL displayed by the app (e.g. http://0.0.0.0:5173/#resources)

  3. Set the transport type to SSE

  4. Set the URL to your running Function app's SSE endpoint and Connect:

    http://0.0.0.0:7071/runtime/webhooks/mcp/sse
    

Note this step will not work in CodeSpaces. Please move on to Deploy to Remote MCP.

  1. List Tools. Click on a tool and Run Tool.

Deploy to Azure

Authentication & Subscription (Azure CLI and azd)

Make sure you're logged into the same tenant and same subscription for both Azure CLI and Azure Developer CLI (azd).

  1. Azure CLI — select tenant + subscription

    az login --tenant <TENANT_ID>
    az account set --subscription <SUBSCRIPTION_ID>
    # Verify
    az account show -o table
    
  2. azd — align default subscription

    azd logout
    azd config list
    azd config set defaults.subscription <SUBSCRIPTION_ID>
    azd login               # or: azd login --tenant-id <TENANT_ID> if multiple tenants
    # (Optional) Check status
    azd auth login --check-status
    

Summary: Both Azure CLI and azd must point to the same <TENANT_ID> and same <SUBSCRIPTION_ID> before running azd up, azd provision, etc.

Additionally, can be used for improved security and policies over your MCP Server, and App Service built-in authentication can be used to set up your favorite OAuth provider including Entra.

Connect to your remote MCP server function app from a client

Your client will need a key in order to invoke the new hosted SSE endpoint, which will be of the form https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse. The hosted function requires a system key by default which can be obtained from the portal or the CLI (az functionapp keys list --resource-group <resource_group> --name <function_app_name>). Obtain the system key named mcp_extension.

Connect to remote MCP server in MCP Inspector

For MCP Inspector, you can include the key in the URL:

https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<your-mcp-extension-system-key>

Connect to remote MCP server in VS Code - GitHub Copilot

For GitHub Copilot within VS Code, you should instead set the key as the x-functions-key header in mcp.json, and you would just use https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse for the URL. The following example uses an input and will prompt you to provide the key when you start the server from VS Code. Note has already been included in this repo and will be picked up by VS Code. Click Start on the server to be prompted for values including functionapp-name (in your /.azure/*/.env file) and functions-mcp-extension-system-key which can be obtained from CLI command above or API Keys in the portal for the Function App.

{
    "inputs": [
        {
            "type": "promptString",
            "id": "functions-mcp-extension-system-key",
            "description": "Azure Functions MCP Extension System Key",
            "password": true
        },
        {
            "type": "promptString",
            "id": "functionapp-name",
            "description": "Azure Functions App Name"
        }
    ],
    "servers": {
        "remote-mcp-function": {
            "type": "sse",
            "url": "https://${input:functionapp-name}.azurewebsites.net/runtime/webhooks/mcp/sse",
            "headers": {
                "x-functions-key": "${input:functions-mcp-extension-system-key}"
            }
        },
        "local-mcp-function": {
            "type": "sse",
            "url": "http://0.0.0.0:7071/runtime/webhooks/mcp/sse"
        }
    }
}

For MCP Inspector, you can include the key in the URL: https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<your-mcp-extension-system-key>.

For GitHub Copilot within VS Code, you should instead set the key as the x-functions-key header in mcp.json, and you would just use https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse for the URL. The following example uses an input and will prompt you to provide the key when you start the server from VS Code:

{
    "inputs": [
        {
            "type": "promptString",
            "id": "functions-mcp-extension-system-key",
            "description": "Azure Functions MCP Extension System Key",
            "password": true
        }
    ],
    "servers": {
        "my-mcp-server": {
            "type": "sse",
            "url": "<funcappname>.azurewebsites.net/runtime/webhooks/mcp/sse",
            "headers": {
                "x-functions-key": "${input:functions-mcp-extension-system-key}"
            }
        }
    }
}

Redeploy your code

You can run the azd up command as many times as you need to both provision your Azure resources and deploy code updates to your function app.

[!NOTE] Deployed code files are always overwritten by the latest deployment package.

Clean up resources

When you're done working with your function app and related resources, you can use this command to delete the function app and its related resources from Azure and avoid incurring any further costs:

azd down

Helpful Azure Commands

Once your application is deployed, you can use these commands to manage and monitor your application:

# Get your function app name from the environment file
FUNCTION_APP_NAME=$(cat .azure/$(cat .azure/config.json | jq -r '.defaultEnvironment')/env.json | jq -r '.FUNCTION_APP_NAME')
echo $FUNCTION_APP_NAME

# Get resource group 
RESOURCE_GROUP=$(cat .azure/$(cat .azure/config.json | jq -r '.defaultEnvironment')/env.json | jq -r '.AZURE_RESOURCE_GROUP')
echo $RESOURCE_GROUP

# View function app logs
az webapp log tail --name $FUNCTION_APP_NAME --resource-group $RESOURCE_GROUP

# Redeploy the application without provisioning new resources
azd deploy

Testing the Websearch function

The repository includes an integration test (tests/websearch_test.py) that calls a SearXNG/Azure Function backend via HTTP. You can perform the same call manually with curl.

Local function

curl -X POST http://localhost:7071/api/websearch \
  -H "Content-Type: application/json" \
  -H "x-functions-key: $WEBSEARCH_FUNCTION_KEY" \
  -d '{"query": "Microsoft Azure"}'

Deployed function

curl -X POST https://<funcappname>.azurewebsites.net/api/websearch \
  -H "Content-Type: application/json" \
  -H "x-functions-key: $WEBSEARCH_FUNCTION_KEY" \
  -d '{"query": "Microsoft Azure"}'

Set the WEBSEARCH_FUNCTION_URL and WEBSEARCH_FUNCTION_KEY environment variables before running the automated test:

WEBSEARCH_FUNCTION_URL=https://<funcappname>.azurewebsites.net/api/websearch \
WEBSEARCH_FUNCTION_KEY=<key> \
pytest tests/websearch_test.py

Source Code

The function code for each MCP tool is defined in the Python files in the src directory. Functions are exposed as MCP tools using the @app.generic_trigger decorator.

Here's the hello_mcp tool from function_app.py:

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="hello_mcp",
    description="Hello world.",
    toolProperties="[]",
)
def hello_mcp(context) -> None:
    """A simple function that returns a greeting message."""
    return "Hello I am MCPTool!"

Note that the host.json file also includes a reference to the experimental bundle, which is required for apps using this feature:

"extensionBundle": {
  "id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental",
  "version": "[4.*, 5.0.0)"
}

Next Steps