Publish curated ITWorx_MCP_Hub source from e1fd00a3172eaaec29bf8f1e6e47f96d175c31ff
This commit is contained in:
1 parent
cb5be898ea
commit
5ff5c807d3
5 files changed
+140
-140
No files matched your search
@@ -1,97 +1,97 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-z0-9][a-z0-9-]*$')]
|
||||
[string]$Project,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-z0-9][a-z0-9-]*$')]
|
||||
[string]$Environment,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[0-9a-fA-F-]{36}$')]
|
||||
[string]$HubClientId,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-zA-Z0-9_.@-]+$')]
|
||||
[string]$OAuthUsername,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SecretFile,
|
||||
|
||||
[string]$PublicBaseUrl = 'https://mcp.example.com',
|
||||
[string]$TokenEndpoint = 'https://auth.example-host.com/application/o/token/',
|
||||
[string]$OAuthClientId = 'itworx-mcp-hub',
|
||||
[string]$PythonExecutable = '',
|
||||
[string]$CodexExecutable = '',
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$bridge = Join-Path $PSScriptRoot 'mcp_stdio_bridge.py'
|
||||
$resolvedSecret = (Resolve-Path -LiteralPath $SecretFile).Path
|
||||
if (-not (Test-Path -LiteralPath $bridge -PathType Leaf)) {
|
||||
throw 'MCP bridge script is missing.'
|
||||
}
|
||||
$secretInfo = Get-Item -LiteralPath $resolvedSecret
|
||||
if (-not $secretInfo.PSIsContainer -and $secretInfo.Length -gt 0 -and $secretInfo.Length -le 8192) {
|
||||
# Continue; content is deliberately never read or printed by this installer.
|
||||
} else {
|
||||
throw 'Secret file must be a non-empty regular file no larger than 8192 bytes.'
|
||||
}
|
||||
if (-not $PublicBaseUrl.StartsWith('https://') -or -not $TokenEndpoint.StartsWith('https://')) {
|
||||
throw 'Public MCP and OAuth endpoints must use HTTPS.'
|
||||
}
|
||||
|
||||
if (-not $PythonExecutable) {
|
||||
$PythonExecutable = (Get-Command python -ErrorAction Stop).Source
|
||||
}
|
||||
if (-not $CodexExecutable) {
|
||||
$CodexExecutable = (Get-Command codex -ErrorAction Stop).Source
|
||||
}
|
||||
|
||||
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||
$currentAcl = Get-Acl -LiteralPath $resolvedSecret
|
||||
if ($currentAcl.Owner -ne $identity) {
|
||||
throw 'Secret file must already be owned by the current Windows identity.'
|
||||
}
|
||||
$verifiedAcl = $currentAcl
|
||||
$verifiedRules = @($verifiedAcl.Access)
|
||||
if (
|
||||
-not $verifiedAcl.AreAccessRulesProtected -or
|
||||
$verifiedRules.Count -ne 1 -or
|
||||
$verifiedRules[0].IdentityReference.Value -ne $identity -or
|
||||
$verifiedRules[0].AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or
|
||||
($verifiedRules[0].FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl
|
||||
) {
|
||||
throw 'Secret file ACL must grant only the current Windows identity FullControl; use new_codex_credential.ps1.'
|
||||
}
|
||||
|
||||
$name = "itworx-$Project-$Environment"
|
||||
$endpoint = "$($PublicBaseUrl.TrimEnd('/'))/mcp/$Project/$Environment"
|
||||
$existing = & $CodexExecutable mcp get $name 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
if (-not $Force) {
|
||||
throw "Codex MCP server '$name' already exists. Re-run with -Force to replace it."
|
||||
}
|
||||
& $CodexExecutable mcp remove $name | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not remove existing Codex MCP server '$name'." }
|
||||
}
|
||||
|
||||
$arguments = @(
|
||||
'mcp', 'add', $name, '--',
|
||||
$PythonExecutable, $bridge,
|
||||
'--endpoint', $endpoint,
|
||||
'--client-id', $HubClientId,
|
||||
'--token-endpoint', $TokenEndpoint,
|
||||
'--oauth-client-id', $OAuthClientId,
|
||||
'--oauth-username', $OAuthUsername,
|
||||
'--client-secret-file', $resolvedSecret,
|
||||
'--scope', 'openid profile'
|
||||
)
|
||||
& $CodexExecutable @arguments | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not add Codex MCP server '$name'." }
|
||||
& $CodexExecutable mcp get $name
|
||||
if ($LASTEXITCODE -ne 0) { throw "Codex MCP server '$name' was not readable after installation." }
|
||||
Write-Output "Configured $name for $endpoint. Restart Codex before first use."
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-z0-9][a-z0-9-]*$')]
|
||||
[string]$Project,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-z0-9][a-z0-9-]*$')]
|
||||
[string]$Environment,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[0-9a-fA-F-]{36}$')]
|
||||
[string]$HubClientId,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidatePattern('^[a-zA-Z0-9_.@-]+$')]
|
||||
[string]$OAuthUsername,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SecretFile,
|
||||
|
||||
[string]$PublicBaseUrl = 'https://mcp.example.com',
|
||||
[string]$TokenEndpoint = 'https://auth.example-host.com/application/o/token/',
|
||||
[string]$OAuthClientId = 'itworx-mcp-hub',
|
||||
[string]$PythonExecutable = '',
|
||||
[string]$CodexExecutable = '',
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$bridge = Join-Path $PSScriptRoot 'mcp_stdio_bridge.py'
|
||||
$resolvedSecret = (Resolve-Path -LiteralPath $SecretFile).Path
|
||||
if (-not (Test-Path -LiteralPath $bridge -PathType Leaf)) {
|
||||
throw 'MCP bridge script is missing.'
|
||||
}
|
||||
$secretInfo = Get-Item -LiteralPath $resolvedSecret
|
||||
if (-not $secretInfo.PSIsContainer -and $secretInfo.Length -gt 0 -and $secretInfo.Length -le 8192) {
|
||||
# Continue; content is deliberately never read or printed by this installer.
|
||||
} else {
|
||||
throw 'Secret file must be a non-empty regular file no larger than 8192 bytes.'
|
||||
}
|
||||
if (-not $PublicBaseUrl.StartsWith('https://') -or -not $TokenEndpoint.StartsWith('https://')) {
|
||||
throw 'Public MCP and OAuth endpoints must use HTTPS.'
|
||||
}
|
||||
|
||||
if (-not $PythonExecutable) {
|
||||
$PythonExecutable = (Get-Command python -ErrorAction Stop).Source
|
||||
}
|
||||
if (-not $CodexExecutable) {
|
||||
$CodexExecutable = (Get-Command codex -ErrorAction Stop).Source
|
||||
}
|
||||
|
||||
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||
$currentAcl = Get-Acl -LiteralPath $resolvedSecret
|
||||
if ($currentAcl.Owner -ne $identity) {
|
||||
throw 'Secret file must already be owned by the current Windows identity.'
|
||||
}
|
||||
$verifiedAcl = $currentAcl
|
||||
$verifiedRules = @($verifiedAcl.Access)
|
||||
if (
|
||||
-not $verifiedAcl.AreAccessRulesProtected -or
|
||||
$verifiedRules.Count -ne 1 -or
|
||||
$verifiedRules[0].IdentityReference.Value -ne $identity -or
|
||||
$verifiedRules[0].AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or
|
||||
($verifiedRules[0].FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl
|
||||
) {
|
||||
throw 'Secret file ACL must grant only the current Windows identity FullControl; use new_codex_credential.ps1.'
|
||||
}
|
||||
|
||||
$name = "itworx-$Project-$Environment"
|
||||
$endpoint = "$($PublicBaseUrl.TrimEnd('/'))/mcp/$Project/$Environment"
|
||||
$existing = & $CodexExecutable mcp get $name 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
if (-not $Force) {
|
||||
throw "Codex MCP server '$name' already exists. Re-run with -Force to replace it."
|
||||
}
|
||||
& $CodexExecutable mcp remove $name | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not remove existing Codex MCP server '$name'." }
|
||||
}
|
||||
|
||||
$arguments = @(
|
||||
'mcp', 'add', $name, '--',
|
||||
$PythonExecutable, $bridge,
|
||||
'--endpoint', $endpoint,
|
||||
'--client-id', $HubClientId,
|
||||
'--token-endpoint', $TokenEndpoint,
|
||||
'--oauth-client-id', $OAuthClientId,
|
||||
'--oauth-username', $OAuthUsername,
|
||||
'--client-secret-file', $resolvedSecret,
|
||||
'--scope', 'openid profile'
|
||||
)
|
||||
& $CodexExecutable @arguments | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not add Codex MCP server '$name'." }
|
||||
& $CodexExecutable mcp get $name
|
||||
if ($LASTEXITCODE -ne 0) { throw "Codex MCP server '$name' was not readable after installation." }
|
||||
Write-Output "Configured $name for $endpoint. Restart Codex before first use."
|
||||
Reference in new issue
Block a user