PnP PowerShell について
PnP PowerShell は、自然言語で Microsoft 365 を管理し、PnP PowerShell スクリプトを作成する MCP サーバーです。永続的な PowerShell セッションでコマンドを実行し、コミュニティのサンプルを検索・改変できます。
主な機能
- 01自然言語による PnP PowerShell コマンド実行
- 02コマンドのドキュメントと例の検索
- 03スクリプトサンプルの検索・改変・保存
- 04コマンド間でのテナント接続の再利用
- 05接続準備状況とセッション状態の確認
活用シーン
- 01SharePoint リストの作成と項目の更新
- 02Microsoft Teams チームと歓迎投稿の作成
- 03コミュニティサンプルを使ったリスト項目の書き出し
- 04テナント状態の確認と Power Automate フローの無効化
MCP 対応
PnP コマンドやスクリプトサンプルの検索、コマンド実行、結果確認、セッション管理のツールを MCP クライアントに提供します。ローカル stdio で動作し、Connect-PnPOnline で確立した PnP PowerShell 接続を再利用します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
PnP PowerShell MCP サーバー
💡 概要
この MCP サーバーを使うと、自然言語で PnP PowerShell コマンドを実行したり、複雑な PnP PowerShell スクリプトを作成したりできます。ユーザーのリクエストを満たすために PnP PowerShell コマンドレットを連続して実行する複雑なプロンプトを処理できるほか、コミュニティの PnP Script Samples ライブラリを検索して、すぐにカスタマイズできるスクリプトを見つけられます。これにより、MCP クライアントから直接、Microsoft 365 のさまざまな領域(SharePoint Online、Microsoft Teams、Entra ID、OneDrive、Planner、Power Platform、Microsoft 365 Groups、分類、検索、テナント管理)を管理し、独自の自動化スクリプトを作成するための出発点として活用できます。
📦 前提条件
-
.NET 10 SDK(ソースからビルドまたは実行する場合にのみ必要です。公開済みのツールリリースは自己完結型です)
-
PowerShell 7.4 以降(
pwsh)がインストールされ、PATHから利用できること -
PnP.PowerShellモジュールがインストールされていること:Install-Module -Name PnP.PowerShell -Scope CurrentUser -Force -AllowClobber
🚀 インストールと使い方
この MCP サーバーは、ローカルにインストールされた PnP PowerShell モジュールを呼び出します。認証は行わないため、まず Connect-PnPOnline を使って認証してください(推奨される認証方法についてはベストプラクティスを参照してください)。その後、MCP サーバーは同じ PnP PowerShell 接続コンテキストを再利用します。
上のワンクリックボタンを使うと、サーバーは
pnp-powershellという名前で登録され、pnp-powershell-mcp-serverコマンドが指定されます。そのため、まずツールをインストールしてください(下記参照)。インストールしない場合、クライアントは起動できないサーバーを登録してしまいます。
.NET グローバルツールとしてインストール
dotnet tool install --global PnP.PowerShell.MCPServer --prerelease
これにより、PATH 上に pnp-powershell-mcp-server という名前の、自己完結型のネイティブ AOT 実行可能ファイルがインストールされます。対応プラットフォーム:Windows(x64、arm64)、macOS(arm64、x64)、Linux(x64、arm64、musl x64)。
既存のインストールを更新するには:
dotnet tool update --global PnP.PowerShell.MCPServer --prerelease
Version <x> of package PnP.PowerShell.MCPServer.<rid> is not found in NuGet feedsと表示されますか? このツールは、小さなラッパーパッケージとプラットフォームごとのパッケージで構成されています。このエラーは、お使いのマシン向けのプラットフォームパッケージが、そのバージョンでは公開されていないことを意味します。0.1.1-beta以前のバージョンが該当します。0.1.3-beta以降をインストールするか、ソースからビルドして実行してください。メンテナーの方はRELEASING.mdを参照してください。
VS Code に追加する
-
コマンドパレット(Ctrl+Shift+P、macOS では Cmd+Shift+P)を開き、
MCP: Add Serverと入力します。 -
サーバーの種類として
Command (stdio)を選択します。 -
MCP サーバーを実行するコマンドを入力します。
pnp-powershell-mcp-server -
サーバーに名前を付けます(例:
PnP PowerShell MCP Server)。
その結果、.vscode/mcp.json ファイルに次の設定が追加されます。
{
"servers": {
"PnP PowerShell MCP Server": {
"type": "stdio",
"command": "pnp-powershell-mcp-server"
}
}
}
これで、VS Code で GitHub Copilot チャットを開くと、利用可能な MCP サーバーの一覧から PnP PowerShell MCP Server を選択して、自然言語で Microsoft 365 の管理に使用できます。プロンプトで「Using PnP PowerShell, I want you to...」と指定すると、GitHub Copilot Agent が MCP サーバーを使用してリクエストを実行します。
GitHub Copilot CLI に追加する
GitHub Copilot CLI を使用している場合は、次の手順で PnP PowerShell MCP サーバーを Copilot に追加できます。
-
Copilot CLI を起動します。
copilot -
copilot mcp コマンドを使用して MCP サーバーを追加します。
/mcp add -
MCP フォームに入力します。
- サーバー名:任意の名前(スペースなし)。例:
pnp-powershell-mcp-server - サーバーの種類:
Local - コマンド:
pnp-powershell-mcp-server - 引数:空欄のままにします
- サーバー名:任意の名前(スペースなし)。例:
その後、Ctrl+S を押して保存し、q を押して MCP フォームを終了します。これで、GitHub Copilot CLI で PnP PowerShell MCP サーバーを使用できます。例:「Using PnP PowerShell, I want you to...」。
Claude Code に追加する
claude mcp add pnp-powershell --scope user -- pnp-powershell-mcp-server
--scope user を指定すると、サーバーがすべてのプロジェクトで利用できるようになります。現在のプロジェクトだけに登録する場合は、この指定を省略してください。claude mcp list で登録されていることを確認できます。
Claude Desktop に追加する
-
Claude Desktop で、左上のハンバーガーアイコンをクリックして設定を開きます。
-
File > Settings を選択します(または
Ctrl + ,を押します)。 -
Developer タブで、Edit Config をクリックします。 注:Developer タブが表示されない場合は、Help > Enable Developer Mode から先に有効にしてください。
-
エクスプローラーが開きます。使い慣れたテキストエディターで
claude_desktop_config.jsonを編集し、次を追加します。{ "mcpServers": { "PnP-PowerShell": { "command": "pnp-powershell-mcp-server" } } } -
変更を反映するため、Claude Desktop を再起動します。
注:Windows では、ウィンドウを閉じても Claude は終了せず、バックグラウンドで実行され続けます。システムトレイで Claude を見つけ、右クリックして Quit を選択すると、完全に終了できます。
Cursor に追加する
-
チャットのオプションから
Agent settingsを選択します。 -
Tools & MCPタブに移動し、New MCP serverをクリックします。 -
次のように
mcp.jsonの設定を変更します。{ "mcpServers": { "PnP PowerShell MCP Server": { "type": "stdio", "command": "pnp-powershell-mcp-server" } } } -
Tools & MCPタブでPnP PowerShell MCP Serverを保存して有効にし、ツールが読み込まれるまで待ちます。
📷 使用例
以下は、この MCP サーバーの使用例の一部です。さまざまなタスクに対応できるため、自由に試しながら自然言語で Microsoft 365 を管理してください。
SharePoint Online を管理する
プロンプト:
Add a new list to this site with title 'awesome ducks'. Then add new columns to that list including them in the default view. The first should be a text description column and the second one should be a user column. Then add 3 items to this list with some funny jokes about ducks added in the description column and my user in the user column.
Microsoft Teams を管理する
プロンプト:
Create a new Team on Teams with name 'Awesome Ducks' and in the General channel add a welcome post.
コミュニティのサンプルからスクリプトを作成する
プロンプト:
I need a PnP PowerShell script that exports all SharePoint list items to a CSV file — find a community sample and adapt it for the 'Documents' list on my site.
独自のスクリプトを再利用する
プロンプト:
Do I have a script in my samples that reports inactive sites? If so, run it for the last 90 days.
新しいスクリプトが動作したら、次のようにします。
Save that script to my samples as inactive-sites-report.
初回のセットアップについては、独自のスクリプトサンプルを参照してください。
テナントの状態をレポートする
プロンプト:
Can you check if I have a Power Automate flow called 'HoursReportingReminder' and if so disable it?
🛠️ ツール
| ツール | 説明 |
|---|---|
| pnp_search_commands | 作業に適したコマンドレットを見つけます。すべてのコマンドレットの名前、動詞、名詞、概要、説明、パラメーター、使用例を含む組み込みインデックスを、フィールドごとに重み付けした BM25 でスコアリングします。そのため、「リストに列を追加する」のような平易な質問から Add-PnPField を見つけられます。プロセス内だけで完結するため、pwsh、セッション、ネットワークは不要で、まだセットアップされていないマシンでも動作します。テキストに加えて構造化コンテンツを返し、インデックス作成元のモジュールバージョンも示します。 |
| pnp_get_command_docs | 指定した名前のコマンドレットのリファレンスドキュメント(構文、パラメーター、パラメーターセット、使用例)を取得します。ドキュメントページの Markdown ソースとレンダリング済み HTML ページの両方へのリンクが先頭に付いています。Markdown は同じ内容をわずかなトークン数で提供します。 |
| pnp_run_command | 接続済みのテナントに対して PnP PowerShell を実行し、結果を返します。永続セッションで実行されるため、Connect-PnPOnline の接続は呼び出し間で再利用されます。破壊的なコマンドを実行するには、事前の確認が必要です。出力上限を超える結果セットは切り捨てずに要約し、ページ分割して返します。 |
| pnp_get_result_page | pnp_run_command が要約した結果セットの次のページを返します。すでに取得済みの行を対象とするため、テナントへの追加コストはなく、元のコマンドが取得した行をそのまま返します。 |
| pnp_get_connection_status | セッションにサインインしているか、どのサイトに接続しているか、どのアカウントを使用しているかを確認します。 |
| pnp_diagnose_connection | コマンドの実行に必要な条件をすべて確認します。PATH 上の pwsh、PnP.PowerShell モジュール、セッションが保持している接続、接続がない場合は、このマシンで実際にサインインできるアプリの登録、保存済みのログイン、または証明書を確認します。失敗した各チェックでは、原因と次に実行する正確なコマンドが示されます。事実を当てはめられるプレースホルダーは残りません。特定のサイト向けのコマンドを取得するには、targetUrl を渡してください。pwsh、モジュール、認証情報のチェックにはテナントもネットワークも不要なため、まだセットアップされていないマシンでも動作します。接続が確立されている場合はその接続も検査します。この処理では PnP に Graph トークンを要求するため、Entra ID にアクセスします。 |
| pnp_reset_session | セッションとその PnP 接続を終了します。サインアウト、アカウントの切り替え、応答しなくなったセッションの復旧に使用します。 |
| pnp_get_best_practices | この MCP サーバー経由で PnP PowerShell を使用する際のベストプラクティスを返します。任意の section(workflow、docs、sessions、config、readonly、output、destructive、auth、execution、patterns)を指定すると、ガイド全体ではなく特定のトピックを取得でき、応答を小さくできます。 |
| pnp_search_script_samples | キーワードに一致する、コミュニティの PnP Script Samples と PNP_SCRIPT_SAMPLES_PATH にある独自のサンプルを一覧表示します。タイトル、説明、リンクが対象で、コードは含まれません。コミュニティのインデックスはサーバーに組み込まれているためネットワークは不要です。PNP_SCRIPT_SAMPLES_PATH に Git URL が指定されている場合は、初回使用時に取得されます。 |
| pnp_get_script_sample | 指定した名前のスクリプトサンプルについて、PnP PowerShell スクリプトのコード全体を取得します。インデックス項目はローカルにあります。コミュニティのスクリプト本体は GitHub から取得し、独自のスクリプトはディスクから読み込みます。 |
| pnp_suggest_script | タスクに最も関連するスクリプトサンプルを探します。独自のサンプルを優先し、スクリプトコード全体とカスタマイズのガイダンスを一度の呼び出しで返します。 |
| pnp_save_script_sample | 動作したスクリプトを、PNP_SCRIPT_SAMPLES_PATH の最初の通常フォルダーに .ps1 として保存します。1 行の要約は .SYNOPSIS として保存されるため、検索や提案ですぐに見つけられます。既存のファイルを上書きすることはありません。 |
| pnp_ping | サーバーのバージョン、稼働時間、読み取り専用モードの状態、アクティブなセッション数を返します。また、includeReadiness が false でない限り、pwsh と PnP.PowerShell モジュールが存在するかどうかも返します。サーバーが応答していることと、マシンの準備が整っていることを確認する簡易ヘルスチェックとして使用します。 |
| pnp_list_sessions | すべてのアクティブな PowerShell セッションを、状態と最終アクティビティ時刻とともに一覧表示します。接続、リセット、再利用するセッションを決める前に、どのセッションがあるか確認するために使用します。 |
| pnp_setup_environment | 現在のユーザー向けに PnP.PowerShell モジュールをインストールし、PnP コマンドレットを実行できるようにします。リリース済みビルドまたは最新のプレリリースビルドを選択します。このモジュールだけをインストールし、サインイン、テナントへのアクセス、アプリの登録は行いません。また、PNP_MCP_ALLOW_SETUP=true の場合に限ってインストールします。それ以外の場合は、手動で実行するための正確な Install-Module コマンドを返します。 |
すべてのツールは readOnlyHint、idempotentHint、openWorldHint のアノテーションを宣言しており、読み取り専用ではないツールは destructiveHint も宣言しています。Microsoft 365 を変更できる 2 つのツール(pnp_run_command、pnp_reset_session)では true、現在のユーザーにモジュールをインストールするツール(pnp_setup_environment)では false を指定しているため、クライアントは推測に頼らず、自動承認するツールを判断できます。 |
ツールの説明は、実際に適切なツールが選択されるかどうかに基づいて評価されます。e2eTestPrompts.md にあるすべてのプロンプトを公開済みの説明に照らして採点する ToolSelectionEvaluatorTests は、適切なツールが上位 3 位に入らない場合、ビルドを失敗させます。ツールの選択を参照してください。
📚 リソース
同じガイダンスとコマンドレットのドキュメントは MCP リソースとしても公開されているため、対応するクライアントはツール呼び出しを使わずにコンテンツを参照してキャッシュできます。
| URI | 内容 |
|---|---|
pnp://best-practices | ガイダンス文書全体。 |
pnp://best-practices/{section} | 1 つのセクション:workflow、docs、sessions、config、readonly、output、destructive、auth、execution、patterns。 |
pnp://cmdlet/{name} | 1 つのコマンドレットのヘルプテキスト。先頭に公開済みのドキュメント URL が付きます。例:pnp://cmdlet/Get-PnPWeb。 |
セッションと sessionId
コマンドは永続的な pwsh セッションで実行されるため、Connect-PnPOnline で確立した接続はツール呼び出しの間も維持されます。コマンドごとに接続し直す必要はなく、一度接続すれば十分です。
通常、sessionId を設定する必要はありません。 省略すると、すべての処理で default という名前のセッションが共有されます。sessionId が必要なのは、2 つのテナント(またはアカウント)を同時に扱う場合だけです。1 つの PnP セッションで保持できる接続は 1 つだけだからです。
sessionId なし | sessionId あり | |
|---|---|---|
| 使用するセッション | default | 指定した名前 |
| 接続 | 1 つを共有 | セッション名ごとに 1 つ |
変数($sites など) | 共有 | セッションごとに分離 |
sessionId を受け付けるツールは 3 つです:pnp_run_command、pnp_get_connection_status、pnp_reset_session。pnp_search_commands はセッションをまったく使用せず、コンパイル時に組み込まれたインデックスから応答します。また、コマンドレットのヘルプは接続先のテナントに依存しないため、pnp_get_command_docs は常に default を使用します。
使用する場合
エージェントには自然言語で依頼するため、設定を編集するのではなく、伝えることで指定します。1 つの会話で 2 つのテナントを扱う場合:
Connect to contoso in a session called "contoso" and to fabrikam in a session called "fabrikam",
then list the site count in each and tell me which is larger.
その後、エージェントは以下に相当する呼び出しを行います:
// tool: pnp_run_command
{ "sessionId": "contoso", "command": "Connect-PnPOnline -Url https://contoso.sharepoint.com -Interactive" }
{ "sessionId": "fabrikam", "command": "Connect-PnPOnline -Url https://fabrikam.sharepoint.com -Interactive" }
{ "sessionId": "contoso", "command": "(Get-PnPTenantSite).Count" }
{ "sessionId": "fabrikam", "command": "(Get-PnPTenantSite).Count" }
それ以外の場合は、単一のテナントに対する複数ステップの作業も含めて、省略してください:
Connect to contoso, find all site collections with no owner, and export them to a CSV.
知っておくとよいこと
pnp_reset_sessionでサインアウトまたはアカウントを切り替えます。セッションを終了し、接続と変数を破棄します。次の呼び出しでは新しいセッションが開始されます。- アイドル状態のセッションは 30 分後に終了します。 コマンドの実行中のセッションは、実行にどれだけ時間がかかっても終了されません。セッションが期限切れになった場合は、再接続してください。
- 1 セッションにつき、同時に実行できるコマンドは 1 つです。 使用中のセッションに対する 2 つ目の呼び出しは待機し、その後、セッションが使用中であることを報告します。2 つの処理を同時に実行するには、異なる
sessionId値を 2 つ使用してください。 - 接続を再利用してください。 コマンドのたびに
Connect-PnPOnlineを再実行しないでください。まずpnp_get_connection_statusを確認してください。確認したセッションが報告されます。
独自のスクリプトサンプル
標準では、サンプルツールはコミュニティの約320件の PnP Script Samples を把握しています。
PNP_SCRIPT_SAMPLES_PATH に独自のスクリプトを指定すると、同じ方法で検索、提案、取得され、ほぼ同程度に一致するコミュニティサンプルより優先されます。
{
"servers": {
"PnP PowerShell MCP Server": {
"type": "stdio",
"command": "pnp-powershell-mcp-server",
"env": {
"PNP_SCRIPT_SAMPLES_PATH": "C:\\scripts\\pnp;https://github.com/contoso/pnp-scripts.git"
}
}
}
}
項目は ; で区切り、それぞれ次の形式です。
| 項目 | 読み取る内容 |
|---|---|
C:\scripts\pnp などの完全なフォルダーパス | 配下とそのサブフォルダーにあるすべての .ps1。上限は5,000件です。OneDrive フォルダーも使用できます。隠しファイルとシステム項目、1 MB を超えるファイル、ファイルまたはフォルダーを指すシンボリックリンクとジャンクションはスキップされます。 |
https:// または ssh:// の Git URL | ローカルのアプリデータの下に浅いクローンを作成し、サーバーの起動ごとに最初のサンプル呼び出し時に一度更新します。既存の Git 認証情報を使用し、認証情報の入力は求めません。そのため、まず自分で一度リポジトリをクローンしてください。更新できないコピーは新しいクローンに置き換えられ、それも失敗した場合は最後のコピーが使用されます。 |
| pnp/script-samples のクローン | 同名の組み込みコピーの代わりに、そのサンプルを使用します。 |
相対パスや git@host:repo(代わりに ssh://git@host/repo と記述してください)など、それ以外の形式は無視されます。
スクリプトはコメントベースのヘルプブロック(<# … #>)から検出されるため、.SYNOPSIS を記述することをお勧めします。記述がない場合、ファイル名がタイトルになります。
<#
.SYNOPSIS
Report sites with no activity in the last 180 days
.DESCRIPTION
Lists every site collection whose content has not changed recently, oldest first, as a CSV.
#>
param([int]$Days = 180)
Get-PnPTenantSite | Where-Object LastContentModifiedDate -lt (Get-Date).AddDays(-$Days) |
Sort-Object LastContentModifiedDate | Select-Object Url, Title, LastContentModifiedDate |
Export-Csv inactive-sites.csv -NoTypeInformation
名前はフォルダー内のパスをもとにし、ASCII の英字、数字、_、. 以外の文字はすべて - に置き換えられます。そのため、C:\scripts\pnp\sites\Inactive Sites.ps1 は sites-Inactive-Sites になります。スクリプト名が重複した場合は、最初に見つかったものが優先され、名前が空のスクリプトはスキップされます。
これを使用するプロンプト:
What scripts do I have for site permissions?
Find one of my samples that exports list items, and adapt it for the Documents list.
Show me the full code of sites-Inactive-Sites.
Save the script we just ran to my samples as monthly-storage-report.
pnp_save_script_sample は、一覧の最初にある通常のフォルダー(Git コピーまたはクローンは対象外)に小文字のファイル名で保存し、指定した概要を .SYNOPSIS として追加します。また、既存ファイルへの上書きや、サンプル名の再利用は拒否されます。保存したスクリプトはすぐに見つかります。手動で追加または編集したスクリプトは、次回の保存時またはサーバー再起動後に表示されます。Git リポジトリにプッシュした変更は、再起動後に反映されます。保存されるスクリプトはモデルが作成したものなので、そのフォルダーをスクリプトの実行者と共有する前に内容を確認してください。
設定
| 環境変数 | デフォルト | 説明 |
|---|---|---|
PNP_MCP_COMMAND_TIMEOUT_SECONDS | 600 | 1 回の pnp_run_command 呼び出しに対する実時間の制限です。タイムアウトするとセッションが終了し、接続が失われます。 |
PNP_MCP_CONFIRM_DESTRUCTIVE | true | false に設定すると、破壊的なコマンド(Remove-*、Clear-*、...)を確認なしで実行します。この制限を回避する方法はこれだけです。モデルが自らの破壊的なコマンドを承認できるツールパラメーターはないため、確認プロンプトを表示できないクライアントでは、破壊的なコマンドはブロックされます。 |
PNP_MCP_READONLY | false | true に設定すると、Microsoft 365 に変更を加えるコマンドをすべて拒否します。許可される動詞:Get-、Export-、Test-、Convert-/ConvertTo-/ConvertFrom-、Read-、Measure-、Connect-/Disconnect-、Find-、Format-、Resolve-、Write-、Search-、Show-、Compare-、およびパイプラインの整形(Select-、Where-、Sort-、Group-、ForEach-、Out-、Join-、Split-)。拒否される動詞:Set-、Remove-、Add-、New-、Clear-、Invoke-、Update-、Move-、Enable-/Disable-、Grant-/Revoke-、Copy-、Import-、Restore-、Reset-、Rename-、Start-/Stop-、Register-/Unregister-、およびその他すべての変更系動詞です。間接的に呼び出されるコマンド、ネイティブ実行ファイル、ExecuteQuery など状態を変更するメソッド呼び出しも拒否されます。全表はベストプラクティスをご覧ください。ローカルファイルへの出力(Out-File、Export-*)は引き続き許可されます。 |
PNP_MCP_ALLOW_SETUP | false | true に設定すると、pnp_setup_environment によって現在のユーザー用に PnP.PowerShell モジュールをインストールできます。未設定の場合、このツールは何も変更せず、手動で実行する Install-Module コマンドを返します。それ以外のものをインストールしたり、サインインしたり、テナントにアクセスしたりすることはありません。 |
PNP_MCP_MAX_OUTPUT_CHARS | 50000 | 返されるツール応答の最大文字数です。JSON の結果セットが上限を超える場合は、実際の行数、フィールド名、収まる限りの行全体、および pnp_get_result_page 用のカーソルを含む要約が返されるため、応答は完全な状態で解析可能です。それ以外の内容は、どれだけ省略されたかを示す注記とともに、最初の行全体までで切り詰められます。注記を入れると出力の余地がなくなるため、2000 未満の値は無視されます。 |
PNP_MCP_REPLAY_DIR | (未設定) | テスト専用。 コマンドを実行する代わりに、このディレクトリに記録されたフィクスチャからすべてのコマンドに応答するため、サーバーが Microsoft 365 にアクセスすることはありません。設定すると stderr にその旨が表示されます。記録再生テストをご覧ください。 |
PNP_MCP_RECORD_DIR | (未設定) | テスト専用。 サーバーが実行するすべてのコマンドについて、サニタイズしたフィクスチャをこのディレクトリに書き込みます。 |
PNP_SCRIPT_SAMPLES_PATH | (未設定) | コミュニティのインデックスと併せて検索され、コミュニティのサンプルと同程度に一致する場合はそちらより優先される、独自のスクリプトサンプルです。.ps1 ファイルの完全なフォルダーパス、pnp/script-samples のクローン、および https:// または ssh:// の Git URL を ; 区切りで指定します。pnp_save_script_sample は、最初に指定された通常のフォルダーに書き込みます。独自のスクリプトサンプルをご覧ください。 |
クライアントはサーバープロセスの起動時に環境変数を渡します。そのため、設定場所によって適用される対象が決まり、変更を反映するにはサーバーの再起動が必要です。
MCP Registry または NuGet.org の MCP タブからインストールすると、PNP_MCP_READONLY と PNP_MCP_ALLOW_SETUP のみが求められ、どちらもデフォルトは false です。他の変数を追加するには、クライアントが作成する env ブロックに指定してください。
設定場所
MCP クライアントの設定 — 通常はこちらを選びます。クライアントの起動方法にかかわらずサーバーに適用される唯一の場所であり、再起動後も設定が保持されます。
VS Code — .vscode/mcp.json(またはユーザーレベルの mcp.json)
{
"servers": {
"PnP PowerShell MCP Server": {
"type": "stdio",
"command": "pnp-powershell-mcp-server",
"env": {
"PNP_MCP_READONLY": "true",
"PNP_MCP_COMMAND_TIMEOUT_SECONDS": "1800"
}
}
}
}
Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"PnP-PowerShell": {
"command": "pnp-powershell-mcp-server",
"env": {
"PNP_MCP_READONLY": "true"
}
}
}
}
Cursor — mcp.json
{
"mcpServers": {
"PnP PowerShell MCP Server": {
"type": "stdio",
"command": "pnp-powershell-mcp-server",
"env": {
"PNP_MCP_READONLY": "true"
}
}
}
}
Claude Code — claude mcp add
claude mcp add pnp-powershell --scope user \
--env PNP_MCP_READONLY=true \
--env PNP_MCP_COMMAND_TIMEOUT_SECONDS=1800 \
-- pnp-powershell-mcp-server
シェルでの設定 — 設定ファイルを編集せずに読み取り専用モードを試す場合など、一度だけ実行するときに使います。値を引き継ぐには、クライアントをそのシェルから起動する必要があります。
# macOS / Linux
PNP_MCP_READONLY=true code .
# Windows PowerShell
$env:PNP_MCP_READONLY = 'true'; code .
マシン全体への設定 — マシン上のすべてのツールで同じ動作にする場合に使います。他のプロセスにも影響するため、それが目的でない場合はクライアントの設定を優先してください。
# Windows, persists across reboots
[Environment]::SetEnvironmentVariable('PNP_MCP_READONLY', 'true', 'User')
設定例
| 目的 | 設定 |
|---|---|
| エージェントが本番環境のテナントを変更せずに調査できるようにする | PNP_MCP_READONLY=true |
| 10 分を超えるテナント全体のレポートを実行する | PNP_MCP_COMMAND_TIMEOUT_SECONDS=3600 |
| コマンドがすでにレビュー済みの、無人実行の自動化 | PNP_MCP_CONFIRM_DESTRUCTIVE=false |
| 独自のスクリプトとチームのリポジトリを検索して保存する | PNP_SCRIPT_SAMPLES_PATH=C:\scripts;https://github.com/contoso/pnp-scripts.git |
| ベンダー提供のインデックスより新しいスクリプトサンプルのクローンを使用する | PNP_SCRIPT_SAMPLES_PATH=C:\src\script-samples |
これらの設定を変更した後は、MCP サーバーを再起動してください(ほとんどのクライアントでは、ウィンドウを再読み込みするか、サーバーをいったんオフにしてからオンにします)。クライアントはプロセスの起動時に環境変数を渡すため、すでに実行中のサーバーには古い値が適用されたままです。
注意点が 2 つあります。PNP_MCP_CONFIRM_DESTRUCTIVE=false にすると、エージェントが Remove-PnPTenantSite を実行するのを防ぐ唯一の仕組みがなくなるため、コマンドを別の方法でレビューする場合に限って設定してください。また、どちらのブール値も完全一致で判定されます。PNP_MCP_READONLY が有効になるのは文字列 true(大文字と小文字は区別しません)の場合のみで、PNP_MCP_CONFIRM_DESTRUCTIVE が無効になるのは false の場合のみです。1 や yes を含め、それ以外の値では既定の設定が維持されます。
MCP の Tasks 拡張機能に対応しているクライアントでは、長時間かかるテナント操作の間、リクエストを開いたままにする代わりに、pnp_run_command をタスクとして実行し、結果をポーリングできます。
🏗️ ローカルでのビルドと実行方法
まず、プロジェクトを復元してビルドします。
dotnet build
ローカルビルドから VS Code で MCP を実行する
ソースから MCP サーバーを起動すると、GitHub Copilot Agent で使用できます。VS Code の GitHub Copilot Agent モードで、ツールアイコンをクリックし、Add more tools → Add MCP server → Command (stdio) を選択して、次を入力します。
dotnet run --project FULL_PATH_TO_YOUR_PROJECT/PnPPowerShell.MCPServer.csproj
名前は自由に設定できます。テストでは、workspace スコープに追加することをおすすめします。このリポジトリの .mcp.json には同等の設定が含まれているため、必要に応じて調整して使用できます。
同梱データ
3 つのインデックスは埋め込みリソースとしてアセンブリにコンパイルされるため、これらを使うツールはネットワーク、VS Code 拡張機能、テナントなしで動作します。
| ファイル | 内容 | 使用ツール |
|---|---|---|
| data/script-samples.json | PnP スクリプトサンプルのカタログ — 名前、タイトル、説明、タグ、作成者 | pnp_search_script_samples、pnp_get_script_sample、pnp_suggest_script |
| data/pnp-commands.json | すべての PnP.PowerShell コマンドレット名と、Markdown および HTML ドキュメント用の URL テンプレート | pnp_get_command_docs |
| data/pnp-index.json | 検索コーパス — 各コマンドレットの概要、説明、パラメーター、パラメーターセット、使用例、および旧エイリアスの対応表 | pnp_search_commands |
内容が古くなる可能性がある 2 つのインデックスは、回答のたびに出所を示すため、インデックスが古くなっても見過ごされません。pnp_search_script_samples はサンプルカタログのコミットを示し、pnp_search_commands はインデックス作成元のモジュールバージョンを示します。pnp-commands.json が提供するのはドキュメントの URL テンプレートのみです。pnp_get_command_docs はインストール済みのモジュールからヘルプを読み取るため、警告すべき古い内容はありません。リリース前に 3 つすべてを更新してください。
# Sample and cmdlet-name indexes, from pnp/vscode-pnp-powershell.
pwsh ./build/Update-VendoredData.ps1
# Search corpus, read from the PnP.PowerShell module installed on this machine, whose version it
# records. Requires PnP.PowerShell; takes a few seconds.
pwsh ./build/Update-CommandIndex.ps1
コーパスは呼び出し元のモジュールではなく、インストール済みのモジュールから作成されるため、pnp_search_commands で説明されるのはサーバーのビルド時に存在していたコマンドレットです。各回答でそのバージョンが示されます。また、pnp_get_command_docs は実際に使用しているモジュールから読み取るため、実行前に構文を確認するにはこちらを使用してください。
どちらかのアップストリームファイルが URL テンプレートと一致しなくなった場合、スクリプトは推測で処理せずに失敗します。
PnP PowerShell VS Code 拡張機能がインストールされている場合は、その拡張機能独自の samples.json がコンパイル済みカタログに置き換わります。その後、PNP_SCRIPT_SAMPLES_PATH のサンプルが追加され、同じ名前のサンプルは置き換えられます。そのため、そこに指定した pnp/script-samples のクローンは、新しいカタログを使うコントリビューターにも役立ちます。
ツールの選択
e2eTestPrompts.md には、各ツールの自然言語プロンプトが記載されています。ToolSelectionEvaluatorTests は公開されている説明文を使って BM25 で各プロンプトに対するすべてのツールを順位付けし、期待されるツールが上位 3 位に入らなければ失敗します。検証するのは順位だけです。信頼度スコアも一時期ここにありましたが、リグレッションを一度も検出できず、削除されました。ツールを追加する場合は、そのツールのプロンプトも追加してください。プロンプトが 1 つもないツールがあるとテストは失敗します。また、プロンプトでリグレッションが発生した場合、修正すべきなのは通常プロンプトではなく、ツールの [Description] です。
Bm25_agrees_with_the_model_that_read_the_same_descriptions は、評価器を検証するテストです。BM25 の第一候補と、公開された説明文だけを基に言語モデルが同じプロンプトを分類した modelSelections.md の結果を比較します。両者の一致率は 93 % です。この数値が下がる場合、語彙ベースのスコアラーが選択を予測できなくなっているため、置き換える必要があるのは説明文ではなくスコアラーです。
経験から学んだ、直感に反するルールが 1 つあります。ツール間の選択はゼロサムです。そのため、あるプロンプトで選ばれるように説明を広げると、ほかのすべてのツールが不利になります。効果があるのは、より特徴的な表現だけです。
プロトコルテスト
StdioProtocolTests は、ビルド済みサーバーを実際のプロセスとして起動し、SDK ではなく手書きのクライアントで、改行区切りの JSON-RPC(initialize、tools/list、tools/call)を送信します。これにより SDK 同士のやり取りではなく、ワイヤ形式そのものをテストします。ツールの一覧、公開されるアノテーション、そしてプロンプトを表示できないクライアントを破壊的コマンドのゲートがブロックすることを検証します。最後の確認以外はすべて外部依存なしで実行できます。テストはサーバー自身のビルド出力を起動するため、先に dotnet build を実行してください。
記録済み再生テスト
テナントに依存する動作は、開発用テナントに対して一度記録し、その後はオフラインで何度でも再生できるため、CI に pwsh もテナントも必要ありません。各フィクスチャは、生成されたスクリプトのハッシュではなく、記録対象の操作ごとに格納されます。つまり、run とコマンド、command-docs とコマンドレットの組み合わせです。そのため、スクリプトの文言を変えても、すべてのフィクスチャが気づかないうちに孤立することはありません。ファイル名にもそのことが示されています。
run-get-pnplist-select-object-title-itemcount-ca7f2242b91c2383.transcript は、その操作をスラッグ化したものにキーを付けたファイル名です。フィクスチャを特定するのはキーだけです。検索時にはキーでの照合にフォールバックするため、再生を壊すことなく、読みやすい部分を手作業で修正できます。フィクスチャは
tests/PnPPowerShell.MCPServer.Tests/fixtures に格納され、取り込み時に TranscriptScrubber によってスクラブされます。対象はテナントのホスト名、UPN、GUID、トークン、シークレット、拇印、証明書ブロックで、コマンドをラップする Base64 ペイロード内も含まれます。
再記録するには、開発用テナントに接続したマシンで次を実行します。
$env:PNP_MCP_RECORD_FIXTURES = '1'
$env:PNP_MCP_RECORD_TENANT_URL = 'https://<tenant>.sharepoint.com/sites/<site>'
$env:PNP_MCP_RECORD_CLIENT_ID = '<app id>'
dotnet test --filter RecordedPlaybackTests
コミットする前に、すべてのフィクスチャを確認してください。 スクラバーは自由記述内の表示名を検出できません。記録済みフィクスチャは、コミットすればテナントデータの漏えいにつながる可能性があります。
インスペクターを使用したローカルビルドからの MCP の実行(デバッグ)
MCP サーバーをテストする方法の 1 つは、MCP Inspector を使用することです。
npx @modelcontextprotocol/inspector dotnet run --project ./PnPPowerShell.MCPServer.csproj
インスペクターが起動するまで待ち、ブラウザーで開いてください。MCP サーバーが実行中であることを確認でき、ローカルでツールを照会して実行できます。
Native AOT ビルドの発行
dotnet publish -c Release -r win-x64 --self-contained
win-x64 を対象の RuntimeIdentifier(linux-x64、osx-arm64 など)に置き換えてください。出力されるのは、.NET ランタイムへの依存がない単一のネイティブ実行可能ファイルです。
Native AOT にはプラットフォームのツールチェーンが必要です。Windows では「Desktop development with C++」ワークロード、macOS では Xcode コマンドラインツール、Linux では clang と zlib1g-dev を使用します。
NuGet へのリリース
リリースは8 個のパッケージで構成されます。小さなラッパー 1 個と、プラットフォームごとのパッケージです。通常の dotnet pack ではラッパーしかビルドされません。手動で公開しないでください。RELEASING.md を参照し、Release ワークフローを使用してください。同じワークフローで、.mcp/server.json からOfficial MCP Registryにもリリースが登録されます。
PnP PowerShell MCP Server への貢献
協力していただける方は、貢献の始め方のガイドラインに従ってください。共有することは大切です!
サポートと SLA
このライブラリはオープンソースで、コミュニティによって提供されており、活発なコミュニティがサポートを行っています。これは Microsoft が提供するモジュールではないため、このオープンソースコンポーネントについて、Microsoft による SLA や直接のサポートはありません。PnP イニシアチブの詳細については、公式サイトをご覧ください:Microsoft 365 & Power Platform Community。
🔗 リソース
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。