Azure Functions (NodeJS) でリモートMCP

Azure Functions でリモートMCPを簡単につくれるようになりました。

https://techcommunity.microsoft.com/blog/appsonazureblog/build-ai-agent-tools-using-remote-mcp-with-azure-functions/4401059

NodeJSの場合は以下がクイックスタートになるのですが、Storageをつかった機能サンプルが含まれていたり、Azureへのデプロイはazd upしたりと、さっくりとやるにはちょっと重いので、さくっとHelloWorld的なものを新規作成したいなということでそのステップの紹介です。

https://github.com/Azure-Samples/remote-mcp-functions-typescript

記事にあるようにAzure Functions Core Toolsのバージョンとかそのあたりは適宜上げてください。

# まずはAzure Functionsのガワをつくる

ここはいつものinitコマンドです。

```cmd
func init NantokaMCP
```
さっくりとnodejs/javascriptで作ります。

# 設定を変える

host.jsonを編集してMCPを使えるようにします。(ここはいずれExperimentalとかはいらなくなるでしょうけど)

```json:host.json
{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental", <-ここだけ変える
    "version": "[4.*, 5.0.0)"
  }
}
```
package.jsonを変えてbetaを読み込むようにする

betaのライブラリを読み込むようにします。（ここもいずれは以下略

```json:package.json
{
  "name": "jsmcptool",
  "version": "1.0.0",
  "description": "",
  "main": "src/functions/*.js",
  "scripts": {
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "@azure/functions": "4.0.11-beta.0" <--ここだけ変える
  },
  "devDependencies": {
    "azure-functions-core-tools": "^4.x"
  }
}
```

@azure/functionsを変えたので、npm installも再実行

```cmd
npm install
```


あとは実装ですね

# MCPサーバの実装

src/functions にNantokaMCP.jsをつくって以下を実装します。
これでourmissionというツールで、マイクロソフトのミッションを返してくれるMCPの実装が完成です。

```javascript:NantokaMCP.js
const { app, InvocationContext, output } = require("@azure/functions");

// Hello function - responds with hello message
function mcpToolMission(_toolArguments, context) {
    return "Empower every person and every organization on the planet to achieve more.";
}

// Register the hello tool
app.mcpTool('mission', {
    toolName: 'our-mission',
    description: 'MCP Tool that responses with our mission message.',
    handler: mcpToolMission
});

module.exports = { mcpToolMission };
```

# 実行してみる（ローカル)

まずはローカル環境で動かしてみます。ローカルで動かすにあたってStorageのエミュレータが必要です。Azuriteか何かは事前に起動しておいてください。

https://learn.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite?tabs=visual-studio%2Cblob-storage


```cmd
func start
```

以下が出てきたらmcp起動に成功です。

```cmd
[2025-XX-XXTXX:XX:XX.XXXZ] MCP server SSE endpoint: http://localhost:7071/runtime/webhooks/mcp/sse
[2025-YY-YYTYY:YY:YY.YYYZ] Worker process started and initialized.

Functions:

        mission: mcpToolTrigger
```

もしVS Codeを利用していれば、.vscode/mcp.jsonに以下をいれればすぐにGitHub Copilotで使えます。

```json:mcp.json
{
    "servers": {
        "my-mcp-server": {
            "type": "sse",
            "url": "http://localhost:7071/runtime/webhooks/mcp/sse",
        }
    }
}
```

# Azure上にデプロイする

既にFunctionsが用意されていれば、以下で簡単にデプロイできます。
（きちんとやるならGitHubとかAzure DevOpsとかにコードをあげてCI/CDですが。）

```cmd
func azure functionapp publish <FunctionAppName>
```
さて、デプロイが成功したらテストですね。 .vscode/mcp.jsonを以下のように変えます。

```json:mcp.json
{
    "servers": {
        "my-mcp-server": {
            "type": "sse",
            "url": "https://<FunctionAppName>/runtime/webhooks/mcp/sse",
            "headers": {
                "x-functions-key": "<API Key>"
            }
        }
    }
}
```
ちなみにAPI KeyはFunctionsのポータルのApp Keysのmcp_extensionのやつを使います。（下図)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/250591d6-224d-4161-8659-9cb33978c63f.png)

これでシンプルなリモートMCPの完成です。

# 現在の課題と今後について

現時点(4/10)ではExperimentalとかbetaとかを使わないとなりませんが、簡単にリモートMCPができます。あとは機能を色々実装していけばいいのですが、現状sseをつかっています。

AzureのApp Service（Azure Loadbalancer)には240秒(Linux)/230秒(Windows)の制限があるため、MCPサーバとしてSSE接続していると上記の時間を経過するとエラーが発生してしまいます。お試しであれば再度MCPクライアントを起動すればいいだけではありますが、ちょっとよろしくない状況です。

将来的にはStreamable HTTPに対応して、またExperimentalとかbetaとかも早く外れたらいいなぁということでシンプルな動作検証でした。