mcpField
P
PnP PowerShell

PnP PowerShell

本地服务
github.com云与基础设施102 周前更新

关于 PnP PowerShell

PnP PowerShell 是用于通过自然语言管理 Microsoft 365、编写 PnP PowerShell 脚本的 MCP 服务。它在持久 PowerShell 会话中运行命令,并可查找和改编社区脚本示例。

主要功能

  1. 01通过自然语言运行 PnP PowerShell 命令
  2. 02搜索命令文档和示例
  3. 03查找、改编并保存脚本示例
  4. 04在多次命令间复用租户连接
  5. 05检查连接就绪状态和会话

适用场景

  1. 01创建 SharePoint 列表并更新列表项
  2. 02创建 Microsoft Teams 团队及欢迎帖
  3. 03改编社区示例以导出列表项
  4. 04检查租户状态并停用 Power Automate 流

MCP 相关

向 MCP 客户端提供搜索 PnP 命令和脚本示例、运行命令、查看结果及管理会话的工具。服务通过本地 stdio 运行,并复用 Connect-PnPOnline 建立的 PnP PowerShell 连接。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
nugetPnP.PowerShell.MCPServer0.1.7-beta

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

PnP PowerShell MCP 服务

💡 描述

此 MCP 服务支持使用自然语言运行 PnP PowerShell 命令和编写复杂的 PnP PowerShell 脚本。它可以处理复杂的提示词,并将其作为一系列 PnP PowerShell cmdlet 执行,以尝试满足用户的请求;还可以在社区的 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 连接上下文。

  • 类型:Local(stdio)
  • 安装:在 VS Code 中安装 PnP PowerShell MCP 在 VS Code Insiders 中安装 PnP PowerShell MCP 在 Visual Studio 中安装 PnP PowerShell MCP 在 Cursor 中安装 PnP PowerShell MCP 在 Claude Code 中安装 PnP PowerShell MCP

上方的一键安装按钮会以 pnp-powershell 为名称注册服务,并将其指向 pnp-powershell-mcp-server 命令,因此请先安装工具(见下文),否则客户端注册的服务将无法启动。

安装为 .NET 全局工具
dotnet tool install --global PnP.PowerShell.MCPServer --prerelease

这会在你的 PATH 上安装一个名为 pnp-powershell-mcp-server 的独立 Native 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
  1. 打开命令面板(Ctrl+Shift+P;在 macOS 上按 Cmd+Shift+P),然后输入 MCP: Add Server。

  2. 选择 Command (stdio) 作为服务类型。

  3. 输入运行 MCP 服务的命令:

    pnp-powershell-mcp-server
    
  4. 为服务命名(例如,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。在提示词中指定“使用 PnP PowerShell,我希望你……”,GitHub Copilot Agent 就会使用 MCP 服务执行你的请求。

添加到 GitHub Copilot CLI

如果你正在使用 GitHub Copilot CLI,可以按以下步骤将 PnP PowerShell MCP 服务添加到 Copilot:

  1. 启动 Copilot CLI:

    copilot
    
  2. 使用 copilot mcp 命令添加 MCP 服务:

    /mcp add
    
  3. 填写 MCP 表单:

    • 服务名称:任意名称,不含空格,例如 pnp-powershell-mcp-server
    • 服务类型:Local
    • 命令:pnp-powershell-mcp-server
    • 参数:留空

之后按 Ctrl+S 保存,再按 q 退出 MCP 表单。现在,你可以在 GitHub Copilot CLI 中使用 PnP PowerShell MCP 服务,例如:“使用 PnP PowerShell,我希望你……”。

添加到 Claude Code
claude mcp add pnp-powershell --scope user -- pnp-powershell-mcp-server

--scope user 会使该服务在每个项目中都可用;移除此参数,则只会为当前项目注册该服务。使用 claude mcp list 检查是否已成功添加。

添加到 Claude Desktop
  1. 在 Claude Desktop 中,点击左上角的汉堡菜单图标打开设置。

  2. 选择 File > Settings(或按 Ctrl + ,)。

  3. 在 Developer 标签页中,点击 Edit Config。 注意:如果看不到 Developer 标签页,请先通过 Help > Enable Developer Mode 启用该标签页。

  4. 这会打开文件资源管理器;使用你喜欢的文本编辑器编辑 claude_desktop_config.json 并添加:

    {
      "mcpServers": {
        "PnP-PowerShell": {
          "command": "pnp-powershell-mcp-server"
        }
      }
    }
    
  5. 重启 Claude Desktop,使更改生效。

注意:在 Windows 上,关闭窗口后 Claude 不会退出,而是继续在后台运行。请在系统托盘中找到它,右键点击并选择 Quit,以完全退出。

添加到 Cursor
  1. 在聊天选项中选择 Agent settings。

  2. 前往 Tools & MCP 标签页,然后点击 New MCP server。

  3. 按如下方式修改 mcp.json 配置:

    {
      "mcpServers": {
        "PnP PowerShell MCP Server": {
          "type": "stdio",
          "command": "pnp-powershell-mcp-server"
        }
      }
    }
    
  4. 保存并在 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查找可完成某项任务的 cmdlet。使用字段加权 BM25 对内置索引中的所有 cmdlet 进行评分,索引包含名称、动词、名词、概要、描述、参数和示例,因此像“向列表添加列”这样的自然语言问题也能找到 Add-PnPField。完全在进程内作答:无需 pwsh、会话或网络,因此在尚未配置的计算机上也能使用。除文本外,还会返回结构化内容,并注明建立索引时使用的模块版本。
pnp_get_command_docs获取指定 cmdlet 的参考文档——语法、参数、参数集和示例,并在文档前附上文档页面的原始 markdown 源文件和渲染后的 HTML 页面链接。markdown 内容相同,但所需 token 仅为一小部分。
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 token,因此会连接到 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将可用脚本以 .ps1 文件形式保存到 PNP_SCRIPT_SAMPLES_PATH 中第一个普通文件夹,并将一行摘要保存为 .SYNOPSIS,以便搜索和建议立即找到它。绝不覆盖现有文件。
pnp_ping返回服务版本、运行时间、只读模式状态和活动会话数;除非 includeReadiness 为 false,还会说明是否已安装 pwsh 和 PnP.PowerShell 模块。可将其用作轻量级健康检查,确认服务正常响应且计算机已准备就绪。
pnp_list_sessions列出所有活动 PowerShell 会话及其状态和上次活动时间。可在决定连接、重置或复用哪些会话前,用它查看现有会话。
pnp_setup_environment为当前用户安装 PnP.PowerShell 模块,以便运行 PnP cmdlet,并选择已发布版本或最新预发布版本。只安装该模块——绝不会登录、访问租户或创建应用注册——且仅当 PNP_MCP_ALLOW_SETUP=true 时执行;否则会返回可手动运行的确切 Install-Module 命令。
每个工具都会声明其 readOnlyHint、idempotentHint 和 openWorldHint 注解;非只读工具还会声明 destructiveHint——对于可能更改 Microsoft 365 的两个工具(pnp_run_command、pnp_reset_session),该值为 true;对于当前用户的模块安装工具(pnp_setup_environment),该值为 false。这样,客户端无需猜测即可决定要自动批准哪些操作。

工具描述是否合格取决于它们能否实际选中工具:[ToolSelectionEvaluatorTests] 会根据已发布的描述为 e2eTestPrompts.md 中的每条提示评分;如果正确的工具未排在前三名,构建就会失败。请参阅工具选择。

📚 资源

同一份指南和 cmdlet 文档也会作为 MCP 资源公开,因此支持资源的客户端可以浏览并缓存内容,无需为此消耗一次工具调用。

URI内容
pnp://best-practices完整的指南文档。
pnp://best-practices/{section}单个章节:workflow、docs、sessions、config、readonly、output、destructive、auth、execution、patterns。
pnp://cmdlet/{name}某个 cmdlet 的帮助文本,前面附有其已发布的文档 URL——例如 pnp://cmdlet/Get-PnPWeb。
会话与 sessionId

命令会在持久的 pwsh 会话中运行,因此通过 Connect-PnPOnline 建立的连接会在工具调用之间保持有效——连接一次即可,无需每条命令都重新连接。

通常无需设置 sessionId。 省略它即可,所有操作都会共用名为 default 的会话。只有一种情况需要设置:同时操作两个租户(或两个账户),因为单个 PnP 会话只能保留一个连接。

不使用 sessionId使用 sessionId
使用的会话default你指定的名称
连接一个,共用每个会话名称各一个
变量($sites 等)共用各会话隔离

三个工具接受该参数:pnp_run_command、pnp_get_connection_status 和 pnp_reset_session。pnp_search_commands 完全不使用会话——它直接从内置索引返回结果;pnp_get_command_docs 始终使用 default,因为 cmdlet 的帮助信息与连接到哪个租户无关。

何时使用

你是用自然语言向 Agent 提出请求,因此只需通过描述来设置该参数,无需编辑配置。在一次对话中操作两个租户:

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.

随后,Agent 会发起与以下内容等效的调用:

// 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 分钟后结束。 但正在运行命令的会话不会被回收,无论命令运行多久都一样——若会话过期,只需重新连接。
  • 每个会话一次只能运行一条命令。 如果向正忙的会话发起第二次调用,该调用会等待,随后报告会话正忙。若要真正同时运行两项任务,请使用两个不同的 sessionId 值。
  • 复用连接。 不要在每条命令前都重新运行 Connect-PnPOnline;请先检查 pnp_get_connection_status。它会报告所检查的会话。
你自己的脚本示例

开箱即用时,示例工具已知晓约 320 个社区 PnP 脚本示例。 将 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_SECONDS600单次 pnp_run_command 调用的实际运行时间上限。超时后会终止会话并断开连接。
PNP_MCP_CONFIRM_DESTRUCTIVEtrue设置为 false,即可在不请求确认的情况下运行破坏性命令(Remove-*、Clear-* 等)。这是绕过此限制的唯一方法:没有工具参数可让模型批准自己的破坏性命令,因此在无法显示确认提示的客户端上,破坏性命令会被直接阻止。
PNP_MCP_READONLYfalse设置为 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_SETUPfalse设置为 true,即可让 pnp_setup_environment 为当前用户安装 PnP.PowerShell 模块。若不设置,该工具不会进行任何更改,而是返回供你手动运行的 Install-Module 命令。它绝不会安装其他内容、登录或访问租户。
PNP_MCP_MAX_OUTPUT_CHARS50000工具响应返回的最大字符数。超过上限的 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

在 Shell 中,适用于临时运行的场景,例如无需修改配置即可试用只读模式。客户端必须从该 Shell 启动,才能继承此值:

# 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')
示例
目标设置
允许 Agent 探索生产租户,但无法对其进行更改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 服务(在大多数客户端中,重新加载窗口或关闭再打开服务即可)——客户端会在启动进程时传入环境变量,因此已在运行的服务仍会使用旧值。

请注意以下两点:PNP_MCP_CONFIRM_DESTRUCTIVE=false 会移除 Agent 与 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 已包含等效配置,你可以据此调整。

随附数据

三个索引会作为嵌入资源编译进程序集,因此使用它们的工具无需网络、VS Code 扩展或租户即可运行:

文件内容使用方
data/script-samples.jsonPnP 脚本示例目录——名称、标题、描述、标签、作者pnp_search_script_samples、pnp_get_script_sample、pnp_suggest_script
data/pnp-commands.json所有 PnP.PowerShell cmdlet 名称,以及其 Markdown 和 HTML 文档的 URL 模板pnp_get_command_docs
data/pnp-index.json搜索语料——每个 cmdlet 的概要、描述、参数、参数集和示例,以及已被取代的别名映射pnp_search_commands

其中两个索引的内容可能过时,因此每次回答都会显示其来源,让过时的索引一目了然,而非悄无声息:pnp_search_script_samples 会标明示例目录的提交版本,pnp_search_commands 会标明为其建立索引的模块版本。pnp-commands.json 只提供文档 URL 模板——pnp_get_command_docs 会从你已安装的模块中读取帮助内容——因此无需担心内容过时。发布前请刷新这三个文件:

# 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 描述的是构建服务时存在的 cmdlet。它会在每次回答中注明该版本,而 pnp_get_command_docs 会读取你实际安装的模块——运行任何命令前,请用它确认语法。

如果上游文件不再符合 URL 模板,该脚本会直接失败,而不会猜测。

如果安装了 PnP PowerShell VS Code 扩展,该扩展自带的 samples.json 会替换编译时内置的目录。随后,PNP_SCRIPT_SAMPLES_PATH 中的示例会被添加进来,并替换任何同名示例。因此,在此处列出的 pnp/script-samples 克隆也能为使用较新目录的贡献者提供支持。

工具选择

e2eTestPrompts.md 按工具列出了自然语言提示词。ToolSelectionEvaluatorTests 使用 BM25 对每条提示词和每个工具进行排名,依据的是已发布的描述——不需要模型、网络或租户——并在预期工具未进入前三名时失败。断言的只有排名:此处曾短暂加入置信度评分,但它从未发现过回归,因此已被移除。添加工具时,必须为其添加提示词;没有任何提示词的工具会导致测试失败。如果提示词未能通过测试,通常应修改工具的 [Description],而不是提示词。

Bm25_agrees_with_the_model_that_read_the_same_descriptions 用于检查检查器本身:它会将 BM25 排名第一的工具与 modelSelections.md 进行比较;后者由语言模型仅根据已发布的描述为相同提示词标注。两者有 93 % 的一致率。如果这一比例下降,说明词法评分器已无法预测工具选择,此时需要替换的是评分器,而不是文案。

有一条反直觉的规则,是经过惨痛教训才总结出来的:工具选择是零和竞争,因此扩大描述范围以匹配某条提示词,会让所有其他工具付出代价。只有更有辨识度的措辞才有帮助。

协议测试

StdioProtocolTests 会将构建好的服务作为真实进程启动,并通过手写客户端与其交换以换行符分隔的 JSON-RPC 消息——initialize、tools/list、tools/call——而非使用 SDK,这样测试的是线上的协议格式,而不是 SDK 与自身的交互。测试会断言工具接口、已发布的注释,以及破坏性命令门控会阻止无法接收提示词的客户端。除最后一项检查外,其他测试都不依赖外部环境;请先运行 dotnet build,因为测试会启动服务自身构建输出目录中的程序。

录制回放测试

依赖租户的行为会针对开发租户录制一次,之后始终离线回放,因此 CI 既不需要 pwsh,也不需要租户。每个夹具都按所录制的操作归档——run 加上命令、command-docs 加上 cmdlet——而不是按生成脚本的哈希值归档,因此重新措辞脚本不会悄悄导致所有夹具失去关联。文件名也会体现这一点: run-get-pnplist-select-object-title-itemcount-ca7f2242b91c2383.transcript 表示该操作,后面跟着 slug 和 key。只有 key 用于标识夹具——查找时会回退到按 key 匹配——因此可以手动修正易读部分而不影响回放。夹具存放在 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

提交前请检查每个夹具。 清理器无法检测自由文本中的显示名称,而已录制的夹具可能会泄露租户数据。

使用 Inspector 从本地构建运行 MCP(调试)

测试 MCP 服务的一种方法是使用 MCP Inspector:

npx @modelcontextprotocol/inspector dotnet run --project ./PnPPowerShell.MCPServer.csproj

等待 Inspector 启动,然后在浏览器中打开。你应该能看到 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

一次发布包含 八个 包——一个小型封装包,以及每个平台各一个包——而普通的 dotnet pack 只会构建封装包。请勿手动发布;请参阅 RELEASING.md,并使用 Release 工作流。随后,同一工作流会根据 .mcp/server.json 将发布版本列入 官方 MCP 注册表。

为 PnP PowerShell MCP Server 做贡献

请遵循贡献入门指南来提供帮助。分享就是关爱!

支持与 SLA

此库是由社区提供并维护的开源库,活跃社区会为其提供支持。该模块并非由 Microsoft 提供,因此 Microsoft 不会为此开源组件提供 SLA 或直接支持。有关 PnP 计划的更多信息,请访问官方网站:Microsoft 365 & Power Platform Community。

🔗 资源

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。