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:
49
plugin/make-plugin.ps1
Normal file
49
plugin/make-plugin.ps1
Normal 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."
|
||||
Reference in New Issue
Block a user