Add plugin builder for one-file client install

plugin/make-plugin.{sh,ps1} stamp a user's own Freshservice API key and the
shared server token into a template and emit a personalized freshservice.plugin
(direct HTTP MCP connection — no Node/mcp-remote/config editing on clients).
Built plugins embed credentials, so *.plugin is git-ignored; the committed
template holds only placeholders. Validated with 'claude plugin validate'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 08:39:27 -06:00
parent 4f9a862c25
commit 549a1b6879
7 changed files with 195 additions and 0 deletions

49
plugin/make-plugin.ps1 Normal file
View File

@@ -0,0 +1,49 @@
# Build a personalized freshservice.plugin for Claude Desktop / Cowork (Windows).
#
# Each person runs this ONCE with their own Freshservice API key. The output
# .plugin file contains your key — do not share it.
#
# Usage: powershell -ExecutionPolicy Bypass -File .\make-plugin.ps1
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$Template = Join-Path $ScriptDir "template"
$ServerUrl = if ($env:SERVER_URL) { $env:SERVER_URL } else { "http://192.168.101.12:3839/mcp" }
$FsDomain = if ($env:FS_DOMAIN) { $env:FS_DOMAIN } else { "pesco.freshservice.com" }
$FsKey = if ($env:FS_KEY) { $env:FS_KEY } else {
Read-Host "Your Freshservice API key (Freshservice -> profile picture -> Profile settings -> API key)"
}
$McpToken = if ($env:MCP_TOKEN) { $env:MCP_TOKEN } else {
Read-Host "Shared MCP server token (ask IT / Spencer)"
}
if (-not $FsKey) { throw "API key is required." }
if (-not $McpToken) { throw "MCP token is required." }
$Build = Join-Path ([System.IO.Path]::GetTempPath()) ("fsplugin-" + [guid]::NewGuid())
Copy-Item -Recurse -Force $Template $Build
$McpJson = Join-Path $Build ".mcp.json"
$content = Get-Content -Raw $McpJson
$content = $content.Replace("__SERVER_URL__", $ServerUrl)
$content = $content.Replace("__FS_DOMAIN__", $FsDomain)
$content = $content.Replace("__FS_KEY__", $FsKey)
$content = $content.Replace("__MCP_TOKEN__", $McpToken)
Set-Content -NoNewline -Path $McpJson -Value $content
# Sanity check: no placeholders left anywhere.
$leftover = Get-ChildItem -Recurse -File $Build | Select-String -Pattern "__[A-Z_]*__" -SimpleMatch:$false
if ($leftover) { throw "Unfilled placeholders remain; aborting." }
$Out = Join-Path $ScriptDir "freshservice.plugin"
if (Test-Path $Out) { Remove-Item $Out }
Add-Type -AssemblyName System.IO.Compression.FileSystem
# CreateFromDirectory includes dot-directories (.claude-plugin), unlike
# Compress-Archive with a wildcard path.
[System.IO.Compression.ZipFile]::CreateFromDirectory($Build, $Out)
Remove-Item -Recurse -Force $Build
Write-Host "Built: $Out"
Write-Host "Install it in Claude Desktop (Cowork -> Customize -> add plugin), then start a new chat."
Write-Host "REMINDER: this file contains your personal API key -- don't share it."