@egain/egain-mcp-server 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mcp-server.js +1143 -6
- package/bin/mcp-server.js.map +6 -6
- package/esm/src/hooks/auth-hook.d.ts.map +1 -1
- package/esm/src/hooks/auth-hook.js +1147 -0
- package/esm/src/hooks/auth-hook.js.map +1 -1
- package/esm/src/lib/config.d.ts +2 -2
- package/esm/src/lib/config.js +2 -2
- package/esm/src/mcp-server/mcp-server.js +1 -1
- package/esm/src/mcp-server/server.js +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/src/hooks/auth-hook.ts +1153 -0
- package/src/lib/config.ts +2 -2
- package/src/mcp-server/mcp-server.ts +1 -1
- package/src/mcp-server/server.ts +1 -1
package/bin/mcp-server.js
CHANGED
|
@@ -4046,9 +4046,9 @@ var init_config = __esm(() => {
|
|
|
4046
4046
|
SDK_METADATA = {
|
|
4047
4047
|
language: "typescript",
|
|
4048
4048
|
openapiDocVersion: "1.0.0",
|
|
4049
|
-
sdkVersion: "1.0.
|
|
4049
|
+
sdkVersion: "1.0.4",
|
|
4050
4050
|
genVersion: "2.723.8",
|
|
4051
|
-
userAgent: "speakeasy-sdk/mcp-typescript 1.0.
|
|
4051
|
+
userAgent: "speakeasy-sdk/mcp-typescript 1.0.4 2.723.8 1.0.0 @egain/egain-mcp-server"
|
|
4052
4052
|
};
|
|
4053
4053
|
});
|
|
4054
4054
|
|
|
@@ -40910,6 +40910,9 @@ class AuthenticationHook {
|
|
|
40910
40910
|
return {};
|
|
40911
40911
|
}
|
|
40912
40912
|
getSafariWarningPage() {
|
|
40913
|
+
if (SAFARI_WARNING_HTML) {
|
|
40914
|
+
return SAFARI_WARNING_HTML;
|
|
40915
|
+
}
|
|
40913
40916
|
try {
|
|
40914
40917
|
const projectRoot = getProjectRoot();
|
|
40915
40918
|
const htmlPath = path.join(projectRoot, "src", "hooks", "auth-pages", "safari-warning.html");
|
|
@@ -40920,6 +40923,9 @@ class AuthenticationHook {
|
|
|
40920
40923
|
}
|
|
40921
40924
|
}
|
|
40922
40925
|
getConfigPage() {
|
|
40926
|
+
if (CONFIG_PAGE_HTML) {
|
|
40927
|
+
return CONFIG_PAGE_HTML;
|
|
40928
|
+
}
|
|
40923
40929
|
try {
|
|
40924
40930
|
const projectRoot = getProjectRoot();
|
|
40925
40931
|
const htmlPath = path.join(projectRoot, "src", "hooks", "auth-pages", "config-page.html");
|
|
@@ -40930,6 +40936,9 @@ class AuthenticationHook {
|
|
|
40930
40936
|
}
|
|
40931
40937
|
}
|
|
40932
40938
|
getConfigPageJS() {
|
|
40939
|
+
if (CONFIG_PAGE_JS) {
|
|
40940
|
+
return CONFIG_PAGE_JS;
|
|
40941
|
+
}
|
|
40933
40942
|
try {
|
|
40934
40943
|
const projectRoot = getProjectRoot();
|
|
40935
40944
|
const jsPath = path.join(projectRoot, "src", "hooks", "auth-pages", "config-page.js");
|
|
@@ -41867,7 +41876,1135 @@ var __filename2, __dirname2, getProjectRoot = () => {
|
|
|
41867
41876
|
return configDir;
|
|
41868
41877
|
}, getConfigPath = () => {
|
|
41869
41878
|
return path.join(getConfigDir(), "config.json");
|
|
41870
|
-
}, execAsync, CONFIG_SERVER_PORT = 3333, CONFIG_SERVER_HOST = "localhost"
|
|
41879
|
+
}, execAsync, CONFIG_SERVER_PORT = 3333, CONFIG_SERVER_HOST = "localhost", CONFIG_PAGE_HTML = `<!DOCTYPE html>
|
|
41880
|
+
<html lang="en">
|
|
41881
|
+
<head>
|
|
41882
|
+
<meta charset="UTF-8">
|
|
41883
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
41884
|
+
<title>eGain MCP - Sign In</title>
|
|
41885
|
+
<style>
|
|
41886
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
41887
|
+
body {
|
|
41888
|
+
font-family: "Open Sans", "Segoe UI", "SegoeUI", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
|
41889
|
+
background: #fef1fd;
|
|
41890
|
+
min-height: 100vh;
|
|
41891
|
+
display: flex;
|
|
41892
|
+
justify-content: center;
|
|
41893
|
+
align-items: center;
|
|
41894
|
+
padding: 20px;
|
|
41895
|
+
}
|
|
41896
|
+
.container {
|
|
41897
|
+
background: white;
|
|
41898
|
+
border-radius: 16px;
|
|
41899
|
+
box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.12);
|
|
41900
|
+
max-width: 500px;
|
|
41901
|
+
width: 100%;
|
|
41902
|
+
padding: 32px;
|
|
41903
|
+
}
|
|
41904
|
+
h1 { color: #333; margin-bottom: 8px; font-size: 24px; }
|
|
41905
|
+
.subtitle { color: #666; margin-bottom: 20px; font-size: 13px; }
|
|
41906
|
+
.quick-signin {
|
|
41907
|
+
display: none;
|
|
41908
|
+
text-align: center;
|
|
41909
|
+
position: relative;
|
|
41910
|
+
}
|
|
41911
|
+
.quick-signin .icon { font-size: 64px; }
|
|
41912
|
+
.quick-signin h1 { text-align: center; }
|
|
41913
|
+
.saved-config {
|
|
41914
|
+
background: #f8f9fa;
|
|
41915
|
+
border-radius: 8px;
|
|
41916
|
+
padding: 20px;
|
|
41917
|
+
margin: 30px 0;
|
|
41918
|
+
text-align: left;
|
|
41919
|
+
}
|
|
41920
|
+
.saved-config-title {
|
|
41921
|
+
font-size: 12px;
|
|
41922
|
+
font-weight: 600;
|
|
41923
|
+
color: #666;
|
|
41924
|
+
text-transform: uppercase;
|
|
41925
|
+
margin-bottom: 15px;
|
|
41926
|
+
text-align: center;
|
|
41927
|
+
}
|
|
41928
|
+
.config-item {
|
|
41929
|
+
display: flex;
|
|
41930
|
+
justify-content: space-between;
|
|
41931
|
+
padding: 8px 0;
|
|
41932
|
+
border-bottom: 1px solid #e1e4e8;
|
|
41933
|
+
font-size: 13px;
|
|
41934
|
+
}
|
|
41935
|
+
.config-item:last-child { border-bottom: none; }
|
|
41936
|
+
.config-label { color: #666; font-weight: 500; }
|
|
41937
|
+
.config-value {
|
|
41938
|
+
color: #333;
|
|
41939
|
+
font-family: 'Courier New', monospace;
|
|
41940
|
+
max-width: 300px;
|
|
41941
|
+
overflow: hidden;
|
|
41942
|
+
text-overflow: ellipsis;
|
|
41943
|
+
white-space: nowrap;
|
|
41944
|
+
}
|
|
41945
|
+
.config-value.masked { color: #999; }
|
|
41946
|
+
.form-view { display: none; }
|
|
41947
|
+
.form-group { margin-bottom: 16px; }
|
|
41948
|
+
label {
|
|
41949
|
+
display: flex;
|
|
41950
|
+
align-items: center;
|
|
41951
|
+
gap: 6px;
|
|
41952
|
+
margin-bottom: 6px;
|
|
41953
|
+
color: #333;
|
|
41954
|
+
font-weight: 500;
|
|
41955
|
+
font-size: 14px;
|
|
41956
|
+
}
|
|
41957
|
+
input {
|
|
41958
|
+
width: 100%;
|
|
41959
|
+
padding: 10px 12px;
|
|
41960
|
+
border: 2px solid #e1e4e8;
|
|
41961
|
+
border-radius: 8px;
|
|
41962
|
+
font-size: 13px;
|
|
41963
|
+
font-family: "Helvetica Neue LT Pro", "Open Sans", 'Courier New', monospace !important;
|
|
41964
|
+
transition: border-color 0.2s;
|
|
41965
|
+
}
|
|
41966
|
+
input:focus {
|
|
41967
|
+
outline: none;
|
|
41968
|
+
border-color: #b91d8f;
|
|
41969
|
+
}
|
|
41970
|
+
.optional {
|
|
41971
|
+
color: #999;
|
|
41972
|
+
font-weight: normal;
|
|
41973
|
+
font-size: 12px;
|
|
41974
|
+
}
|
|
41975
|
+
.tooltip {
|
|
41976
|
+
position: relative;
|
|
41977
|
+
display: inline-flex;
|
|
41978
|
+
align-items: center;
|
|
41979
|
+
justify-content: center;
|
|
41980
|
+
width: 16px;
|
|
41981
|
+
height: 16px;
|
|
41982
|
+
background: #b91d8f;
|
|
41983
|
+
color: white;
|
|
41984
|
+
border-radius: 50%;
|
|
41985
|
+
font-size: 11px;
|
|
41986
|
+
font-weight: bold;
|
|
41987
|
+
cursor: pointer;
|
|
41988
|
+
flex-shrink: 0;
|
|
41989
|
+
user-select: none;
|
|
41990
|
+
}
|
|
41991
|
+
.tooltip-content {
|
|
41992
|
+
display: none !important;
|
|
41993
|
+
position: fixed;
|
|
41994
|
+
max-width: 380px;
|
|
41995
|
+
width: max-content;
|
|
41996
|
+
background: white;
|
|
41997
|
+
border-radius: 8px;
|
|
41998
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
41999
|
+
z-index: 10000;
|
|
42000
|
+
overflow: hidden;
|
|
42001
|
+
border: 2px solid #b91d8f;
|
|
42002
|
+
pointer-events: auto;
|
|
42003
|
+
}
|
|
42004
|
+
.tooltip-content.active {
|
|
42005
|
+
display: block !important;
|
|
42006
|
+
}
|
|
42007
|
+
.tooltip-arrow {
|
|
42008
|
+
position: absolute;
|
|
42009
|
+
width: 0;
|
|
42010
|
+
height: 0;
|
|
42011
|
+
border: 8px solid transparent;
|
|
42012
|
+
z-index: 1;
|
|
42013
|
+
}
|
|
42014
|
+
.tooltip-arrow.left {
|
|
42015
|
+
left: -16px;
|
|
42016
|
+
top: 50%;
|
|
42017
|
+
transform: translateY(-50%);
|
|
42018
|
+
border-right-color: #b91d8f;
|
|
42019
|
+
}
|
|
42020
|
+
.tooltip-arrow.right {
|
|
42021
|
+
right: -16px;
|
|
42022
|
+
top: 50%;
|
|
42023
|
+
transform: translateY(-50%);
|
|
42024
|
+
border-left-color: #b91d8f;
|
|
42025
|
+
}
|
|
42026
|
+
.tooltip-arrow.top {
|
|
42027
|
+
top: -16px;
|
|
42028
|
+
left: 50%;
|
|
42029
|
+
transform: translateX(-50%);
|
|
42030
|
+
border-bottom-color: #b91d8f;
|
|
42031
|
+
}
|
|
42032
|
+
.tooltip-arrow.bottom {
|
|
42033
|
+
bottom: -16px;
|
|
42034
|
+
left: 50%;
|
|
42035
|
+
transform: translateX(-50%);
|
|
42036
|
+
border-top-color: #b91d8f;
|
|
42037
|
+
}
|
|
42038
|
+
.tooltip-header {
|
|
42039
|
+
background: #b91d8f;
|
|
42040
|
+
color: white;
|
|
42041
|
+
padding: 8px 12px;
|
|
42042
|
+
font-weight: 600;
|
|
42043
|
+
font-size: 13px;
|
|
42044
|
+
}
|
|
42045
|
+
.tooltip-body {
|
|
42046
|
+
padding: 10px 12px;
|
|
42047
|
+
}
|
|
42048
|
+
.tooltip-image {
|
|
42049
|
+
width: 100%;
|
|
42050
|
+
max-height: 200px;
|
|
42051
|
+
object-fit: contain;
|
|
42052
|
+
border-radius: 4px;
|
|
42053
|
+
margin-bottom: 6px;
|
|
42054
|
+
border: 1px solid #e1e4e8;
|
|
42055
|
+
background: #f8f9fa;
|
|
42056
|
+
}
|
|
42057
|
+
.tooltip-text {
|
|
42058
|
+
color: #555;
|
|
42059
|
+
font-size: 12px;
|
|
42060
|
+
line-height: 1.4;
|
|
42061
|
+
font-style: italic;
|
|
42062
|
+
}
|
|
42063
|
+
.button-group {
|
|
42064
|
+
display: flex;
|
|
42065
|
+
gap: 10px;
|
|
42066
|
+
margin-top: 20px;
|
|
42067
|
+
}
|
|
42068
|
+
button {
|
|
42069
|
+
flex: 1;
|
|
42070
|
+
padding: 12px;
|
|
42071
|
+
border: 2px solid transparent;
|
|
42072
|
+
border-radius: 8px;
|
|
42073
|
+
font-size: 15px;
|
|
42074
|
+
font-weight: 600;
|
|
42075
|
+
cursor: pointer;
|
|
42076
|
+
transition: all 0.2s;
|
|
42077
|
+
}
|
|
42078
|
+
.btn-primary {
|
|
42079
|
+
background: linear-gradient(135deg, #b91d8f 0%, #7a1460 100%);
|
|
42080
|
+
color: white;
|
|
42081
|
+
}
|
|
42082
|
+
.btn-primary:hover {
|
|
42083
|
+
transform: translateY(-2px);
|
|
42084
|
+
box-shadow: 0 6px 20px rgba(185, 29, 143, 0.4);
|
|
42085
|
+
}
|
|
42086
|
+
.btn-secondary {
|
|
42087
|
+
background: #f6f8fa;
|
|
42088
|
+
color: #666;
|
|
42089
|
+
}
|
|
42090
|
+
.btn-secondary:hover {
|
|
42091
|
+
background: #e1e4e8;
|
|
42092
|
+
}
|
|
42093
|
+
.btn-danger {
|
|
42094
|
+
background: white;
|
|
42095
|
+
color: #b91d8f;
|
|
42096
|
+
border: 2px solid #b91d8f;
|
|
42097
|
+
}
|
|
42098
|
+
.btn-danger:hover {
|
|
42099
|
+
background: #fef1fd;
|
|
42100
|
+
transform: translateY(-1px);
|
|
42101
|
+
}
|
|
42102
|
+
.btn-link {
|
|
42103
|
+
background: transparent;
|
|
42104
|
+
color: #b91d8f;
|
|
42105
|
+
padding: 8px;
|
|
42106
|
+
font-size: 14px;
|
|
42107
|
+
}
|
|
42108
|
+
.btn-link:hover {
|
|
42109
|
+
background: #f6f8fa;
|
|
42110
|
+
}
|
|
42111
|
+
.status {
|
|
42112
|
+
margin-top: 20px;
|
|
42113
|
+
padding: 12px;
|
|
42114
|
+
border-radius: 8px;
|
|
42115
|
+
font-size: 14px;
|
|
42116
|
+
display: none;
|
|
42117
|
+
}
|
|
42118
|
+
.status.success {
|
|
42119
|
+
background: #d4edda;
|
|
42120
|
+
color: #155724;
|
|
42121
|
+
border: 1px solid #c3e6cb;
|
|
42122
|
+
}
|
|
42123
|
+
.status.error {
|
|
42124
|
+
background: #f8d7da;
|
|
42125
|
+
color: #721c24;
|
|
42126
|
+
border: 1px solid #f5c6cb;
|
|
42127
|
+
}
|
|
42128
|
+
.status.info {
|
|
42129
|
+
background: #d1ecf1;
|
|
42130
|
+
color: #0c5460;
|
|
42131
|
+
border: 1px solid #bee5eb;
|
|
42132
|
+
}
|
|
42133
|
+
/* Loading overlay and spinner */
|
|
42134
|
+
.loading-overlay {
|
|
42135
|
+
display: none;
|
|
42136
|
+
position: absolute;
|
|
42137
|
+
top: -32px;
|
|
42138
|
+
left: -32px;
|
|
42139
|
+
right: -32px;
|
|
42140
|
+
bottom: -32px;
|
|
42141
|
+
background: rgba(255, 255, 255, 0.85);
|
|
42142
|
+
backdrop-filter: blur(2px);
|
|
42143
|
+
border-radius: 16px;
|
|
42144
|
+
z-index: 1000;
|
|
42145
|
+
justify-content: center;
|
|
42146
|
+
align-items: center;
|
|
42147
|
+
flex-direction: column;
|
|
42148
|
+
gap: 16px;
|
|
42149
|
+
}
|
|
42150
|
+
.loading-overlay.active {
|
|
42151
|
+
display: flex;
|
|
42152
|
+
}
|
|
42153
|
+
.spinner {
|
|
42154
|
+
width: 48px;
|
|
42155
|
+
height: 48px;
|
|
42156
|
+
border: 4px solid #e1e4e8;
|
|
42157
|
+
border-top-color: #b91d8f;
|
|
42158
|
+
border-radius: 50%;
|
|
42159
|
+
animation: spin 0.8s linear infinite;
|
|
42160
|
+
}
|
|
42161
|
+
@keyframes spin {
|
|
42162
|
+
to { transform: rotate(360deg); }
|
|
42163
|
+
}
|
|
42164
|
+
.loading-message {
|
|
42165
|
+
color: #666;
|
|
42166
|
+
font-size: 14px;
|
|
42167
|
+
font-weight: 500;
|
|
42168
|
+
text-align: center;
|
|
42169
|
+
max-width: 300px;
|
|
42170
|
+
}
|
|
42171
|
+
.form-view {
|
|
42172
|
+
position: relative;
|
|
42173
|
+
}
|
|
42174
|
+
.modal-overlay {
|
|
42175
|
+
display: none;
|
|
42176
|
+
position: fixed;
|
|
42177
|
+
top: 0;
|
|
42178
|
+
left: 0;
|
|
42179
|
+
right: 0;
|
|
42180
|
+
bottom: 0;
|
|
42181
|
+
background: rgba(0, 0, 0, 0.5);
|
|
42182
|
+
z-index: 10001;
|
|
42183
|
+
justify-content: center;
|
|
42184
|
+
align-items: center;
|
|
42185
|
+
}
|
|
42186
|
+
.modal-overlay.active {
|
|
42187
|
+
display: flex;
|
|
42188
|
+
}
|
|
42189
|
+
.modal-content {
|
|
42190
|
+
background: white;
|
|
42191
|
+
border-radius: 12px;
|
|
42192
|
+
padding: 30px;
|
|
42193
|
+
max-width: 400px;
|
|
42194
|
+
width: 90%;
|
|
42195
|
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
|
42196
|
+
}
|
|
42197
|
+
.modal-title {
|
|
42198
|
+
font-size: 20px;
|
|
42199
|
+
font-weight: 600;
|
|
42200
|
+
color: #333;
|
|
42201
|
+
margin-bottom: 12px;
|
|
42202
|
+
}
|
|
42203
|
+
.modal-message {
|
|
42204
|
+
font-size: 14px;
|
|
42205
|
+
color: #666;
|
|
42206
|
+
margin-bottom: 24px;
|
|
42207
|
+
line-height: 1.5;
|
|
42208
|
+
}
|
|
42209
|
+
.modal-buttons {
|
|
42210
|
+
display: flex;
|
|
42211
|
+
gap: 10px;
|
|
42212
|
+
justify-content: flex-end;
|
|
42213
|
+
}
|
|
42214
|
+
.modal-buttons button {
|
|
42215
|
+
padding: 10px 20px;
|
|
42216
|
+
font-size: 14px;
|
|
42217
|
+
flex: none;
|
|
42218
|
+
}
|
|
42219
|
+
</style>
|
|
42220
|
+
</head>
|
|
42221
|
+
<body>
|
|
42222
|
+
<div class="container">
|
|
42223
|
+
<div id="quickSigninView" class="quick-signin">
|
|
42224
|
+
<div id="loadingOverlayQuickSignin" class="loading-overlay">
|
|
42225
|
+
<div class="spinner"></div>
|
|
42226
|
+
<div id="loadingMessageQuickSignin" class="loading-message">Redirecting to login...</div>
|
|
42227
|
+
</div>
|
|
42228
|
+
<div class="icon">\uD83D\uDD10</div>
|
|
42229
|
+
<h1>Welcome Back!</h1>
|
|
42230
|
+
<p class="subtitle">Ready to sign in with your saved configuration</p>
|
|
42231
|
+
<div class="saved-config">
|
|
42232
|
+
<div class="saved-config-title">Saved Configuration</div>
|
|
42233
|
+
<div id="savedConfigList"></div>
|
|
42234
|
+
</div>
|
|
42235
|
+
<div class="button-group">
|
|
42236
|
+
<button type="button" class="btn-danger" onclick="clearConfigAndShowForm()">Clear All</button>
|
|
42237
|
+
<button type="button" class="btn-primary" onclick="signInWithSavedConfig()">Sign In</button>
|
|
42238
|
+
</div>
|
|
42239
|
+
<button type="button" class="btn-link" onclick="showForm()" style="width: 100%; margin-top: 10px;">Edit Configuration</button>
|
|
42240
|
+
</div>
|
|
42241
|
+
<div id="formView" class="form-view">
|
|
42242
|
+
<div id="loadingOverlay" class="loading-overlay">
|
|
42243
|
+
<div class="spinner"></div>
|
|
42244
|
+
<div id="loadingMessage" class="loading-message">Saving configuration...</div>
|
|
42245
|
+
</div>
|
|
42246
|
+
<h1>\uD83D\uDD10 eGain MCP Configuration</h1>
|
|
42247
|
+
<p class="subtitle">Enter details from your eGain <strong>Admin Console</strong></p>
|
|
42248
|
+
<form id="configForm">
|
|
42249
|
+
<div class="form-group">
|
|
42250
|
+
<label for="egainUrl">
|
|
42251
|
+
<span>eGain Environment URL</span>
|
|
42252
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'egainUrl')" onmouseleave="hideTooltip(event, 'egainUrl')">?</span>
|
|
42253
|
+
</label>
|
|
42254
|
+
<input type="text" id="egainUrl" name="egainUrl" placeholder="https://your-environment.egain.cloud" required>
|
|
42255
|
+
</div>
|
|
42256
|
+
<div class="form-group">
|
|
42257
|
+
<label for="authUrl">
|
|
42258
|
+
<span>Authorization URL</span>
|
|
42259
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'authUrl')" onmouseleave="hideTooltip(event, 'authUrl')">?</span>
|
|
42260
|
+
</label>
|
|
42261
|
+
<input type="text" id="authUrl" name="authUrl" placeholder="https://login.egain.cloud/.../oauth2/authorize" required>
|
|
42262
|
+
</div>
|
|
42263
|
+
<div class="form-group">
|
|
42264
|
+
<label for="accessTokenUrl">
|
|
42265
|
+
<span>Access Token URL</span>
|
|
42266
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'accessTokenUrl')" onmouseleave="hideTooltip(event, 'accessTokenUrl')">?</span>
|
|
42267
|
+
</label>
|
|
42268
|
+
<input type="text" id="accessTokenUrl" name="accessTokenUrl" placeholder="https://login.egain.cloud/.../oauth2/token" required>
|
|
42269
|
+
</div>
|
|
42270
|
+
<div class="form-group">
|
|
42271
|
+
<label for="clientId">
|
|
42272
|
+
<span>Client ID</span>
|
|
42273
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'clientId')" onmouseleave="hideTooltip(event, 'clientId')">?</span>
|
|
42274
|
+
</label>
|
|
42275
|
+
<input type="text" id="clientId" name="clientId" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" required>
|
|
42276
|
+
</div>
|
|
42277
|
+
<div class="form-group">
|
|
42278
|
+
<label for="redirectUrl">
|
|
42279
|
+
<span>Redirect URL</span>
|
|
42280
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'redirectUrl')" onmouseleave="hideTooltip(event, 'redirectUrl')">?</span>
|
|
42281
|
+
</label>
|
|
42282
|
+
<input type="text" id="redirectUrl" name="redirectUrl" placeholder="https://your-redirect-url.com/" required>
|
|
42283
|
+
</div>
|
|
42284
|
+
|
|
42285
|
+
<!-- Advanced Settings Toggle -->
|
|
42286
|
+
<div style="margin: 12px 0;">
|
|
42287
|
+
<button type="button" onclick="toggleAdvancedSettings()" style="padding: 6px 0; font-size: 13px; display: flex; align-items: center; gap: 6px; background: none; border: none; color: #b91d8f; cursor: pointer; font-family: inherit;">
|
|
42288
|
+
<span id="advancedToggleIcon">▶</span>
|
|
42289
|
+
<span>Advanced Settings</span>
|
|
42290
|
+
<span style="color: #999; font-size: 11px;">(optional)</span>
|
|
42291
|
+
</button>
|
|
42292
|
+
</div>
|
|
42293
|
+
|
|
42294
|
+
<!-- Advanced Settings Section (hidden by default) -->
|
|
42295
|
+
<div id="advancedSettings" style="display: none;">
|
|
42296
|
+
<div class="form-group">
|
|
42297
|
+
<label for="clientSecret">
|
|
42298
|
+
<span>Client Secret</span>
|
|
42299
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'clientSecret')" onmouseleave="hideTooltip(event, 'clientSecret')">?</span>
|
|
42300
|
+
<span class="optional">(optional)</span>
|
|
42301
|
+
</label>
|
|
42302
|
+
<input type="password" id="clientSecret" name="clientSecret" placeholder="Required for normal authentication flow/non-PKCE">
|
|
42303
|
+
</div>
|
|
42304
|
+
<div class="form-group">
|
|
42305
|
+
<label for="scopePrefix">
|
|
42306
|
+
<span>Scope Prefix</span>
|
|
42307
|
+
<span class="tooltip" onmouseenter="showTooltip(event, 'scopePrefix')" onmouseleave="hideTooltip(event, 'scopePrefix')">?</span>
|
|
42308
|
+
<span class="optional">(optional)</span>
|
|
42309
|
+
</label>
|
|
42310
|
+
<input type="text" id="scopePrefix" name="scopePrefix" placeholder="https://your.scope-prefix.cloud/auth/">
|
|
42311
|
+
</div>
|
|
42312
|
+
</div>
|
|
42313
|
+
<div style="font-size: 11px; color: #999; margin: 12px 0 0 0; line-height: 1.4;">
|
|
42314
|
+
\uD83D\uDD12 Your configuration will be securely saved to your <code style="background: #f0f0f0; padding: 2px 4px; border-radius: 3px; font-size: 10px;">~/.egain-mcp/config.json</code>.
|
|
42315
|
+
</div>
|
|
42316
|
+
<div class="button-group">
|
|
42317
|
+
<button type="button" class="btn-secondary" onclick="cancelForm()">Cancel</button>
|
|
42318
|
+
<button type="submit" class="btn-primary">Save & Authenticate</button>
|
|
42319
|
+
</div>
|
|
42320
|
+
</form>
|
|
42321
|
+
</div>
|
|
42322
|
+
<div id="status" class="status"></div>
|
|
42323
|
+
</div>
|
|
42324
|
+
|
|
42325
|
+
<!-- Confirmation Modal -->
|
|
42326
|
+
<div id="confirmModal" class="modal-overlay" onclick="if(event.target === this) closeModal(false)">
|
|
42327
|
+
<div class="modal-content">
|
|
42328
|
+
<div class="modal-title" id="modalTitle">Confirm Action</div>
|
|
42329
|
+
<div class="modal-message" id="modalMessage">Are you sure?</div>
|
|
42330
|
+
<div class="modal-buttons">
|
|
42331
|
+
<button type="button" class="btn-secondary" onclick="closeModal(false)">Cancel</button>
|
|
42332
|
+
<button type="button" class="btn-danger" id="modalConfirmBtn" onclick="closeModal(true)">Confirm</button>
|
|
42333
|
+
</div>
|
|
42334
|
+
</div>
|
|
42335
|
+
</div>
|
|
42336
|
+
|
|
42337
|
+
<!-- Tooltip Popups (outside container for proper fixed positioning) -->
|
|
42338
|
+
<div id="tooltip-egainUrl" class="tooltip-content">
|
|
42339
|
+
<div class="tooltip-header">eGain Environment URL</div>
|
|
42340
|
+
<div class="tooltip-body">
|
|
42341
|
+
<img src="/img/env-tooltip.png" class="tooltip-image" alt="eGain Environment URL" onerror="this.style.display='none'">
|
|
42342
|
+
<div class="tooltip-text">Enter the domain URL displayed in your browser when accessing the eGain application.</div>
|
|
42343
|
+
</div>
|
|
42344
|
+
</div>
|
|
42345
|
+
|
|
42346
|
+
<div id="tooltip-authUrl" class="tooltip-content">
|
|
42347
|
+
<div class="tooltip-header">Authorization URL</div>
|
|
42348
|
+
<div class="tooltip-body">
|
|
42349
|
+
<img src="/img/authurl-tooltip.png" class="tooltip-image" alt="Authorization URL" onerror="this.style.display='none'">
|
|
42350
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the Authorization URL.</div>
|
|
42351
|
+
</div>
|
|
42352
|
+
</div>
|
|
42353
|
+
|
|
42354
|
+
<div id="tooltip-accessTokenUrl" class="tooltip-content">
|
|
42355
|
+
<div class="tooltip-header">Access Token URL</div>
|
|
42356
|
+
<div class="tooltip-body">
|
|
42357
|
+
<img src="/img/accesstoken-tooltip.png" class="tooltip-image" alt="Access Token URL" onerror="this.style.display='none'">
|
|
42358
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the Access Token URL.</div>
|
|
42359
|
+
</div>
|
|
42360
|
+
</div>
|
|
42361
|
+
|
|
42362
|
+
<div id="tooltip-clientId" class="tooltip-content">
|
|
42363
|
+
<div class="tooltip-header">Client ID</div>
|
|
42364
|
+
<div class="tooltip-body">
|
|
42365
|
+
<img src="/img/clientid-tooltip.png" class="tooltip-image" alt="Client ID" onerror="this.style.display='none'">
|
|
42366
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Client ID.</div>
|
|
42367
|
+
</div>
|
|
42368
|
+
</div>
|
|
42369
|
+
|
|
42370
|
+
<div id="tooltip-redirectUrl" class="tooltip-content">
|
|
42371
|
+
<div class="tooltip-header">Redirect URL</div>
|
|
42372
|
+
<div class="tooltip-body">
|
|
42373
|
+
<img src="/img/redirect-tooltip.png" class="tooltip-image" alt="Redirect URL" onerror="this.style.display='none'">
|
|
42374
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Redirect URL.</div>
|
|
42375
|
+
</div>
|
|
42376
|
+
</div>
|
|
42377
|
+
|
|
42378
|
+
<div id="tooltip-clientSecret" class="tooltip-content">
|
|
42379
|
+
<div class="tooltip-header">Client Secret</div>
|
|
42380
|
+
<div class="tooltip-body">
|
|
42381
|
+
<img src="/img/clientsecret-tooltip.png" class="tooltip-image" alt="Client Secret" onerror="this.style.display='none'">
|
|
42382
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application, select your client app, and copy the Client Secret under Secrets.</div>
|
|
42383
|
+
</div>
|
|
42384
|
+
</div>
|
|
42385
|
+
|
|
42386
|
+
<div id="tooltip-scopePrefix" class="tooltip-content">
|
|
42387
|
+
<div class="tooltip-header">Scope Prefix</div>
|
|
42388
|
+
<div class="tooltip-body">
|
|
42389
|
+
<img src="/img/scopeprefix-tooltip.png" class="tooltip-image" alt="Scope Prefix" onerror="this.style.display='none'">
|
|
42390
|
+
<div class="tooltip-text">In the Partition space, go to Integration → Client Application → Metadata, and copy the API Permission Prefix.</div>
|
|
42391
|
+
</div>
|
|
42392
|
+
</div>
|
|
42393
|
+
|
|
42394
|
+
<script src="/config-page.js"></script>
|
|
42395
|
+
</body>
|
|
42396
|
+
</html>`, CONFIG_PAGE_JS = `const FIELDS = ['egainUrl', 'authUrl', 'accessTokenUrl', 'clientId', 'redirectUrl', 'clientSecret', 'scopePrefix'];
|
|
42397
|
+
const FIELD_LABELS = {
|
|
42398
|
+
egainUrl: 'eGain URL', authUrl: 'Auth URL', accessTokenUrl: 'Token URL',
|
|
42399
|
+
clientId: 'Client ID', redirectUrl: 'Redirect URL', clientSecret: 'Client Secret',
|
|
42400
|
+
scopePrefix: 'Scope Prefix'
|
|
42401
|
+
};
|
|
42402
|
+
|
|
42403
|
+
let savedConfigData = null; // Store config in memory only
|
|
42404
|
+
let authenticationStarted = false; // Track if user started authentication process
|
|
42405
|
+
let lastSubmittedConfig = null; // Track last submitted config to prevent duplicate submissions
|
|
42406
|
+
let isSubmitting = false; // Track if form submission is in progress
|
|
42407
|
+
|
|
42408
|
+
// Fetch saved config from backend (secure file storage)
|
|
42409
|
+
async function loadSavedConfig() {
|
|
42410
|
+
try {
|
|
42411
|
+
const response = await fetch('/get-config');
|
|
42412
|
+
if (response.ok) {
|
|
42413
|
+
const data = await response.json();
|
|
42414
|
+
if (data.config && data.config.egainUrl && data.config.clientId) {
|
|
42415
|
+
// Only set if we have valid required fields
|
|
42416
|
+
savedConfigData = data.config;
|
|
42417
|
+
return true;
|
|
42418
|
+
}
|
|
42419
|
+
}
|
|
42420
|
+
} catch (error) {
|
|
42421
|
+
console.error('Could not load saved config:', error);
|
|
42422
|
+
}
|
|
42423
|
+
savedConfigData = null;
|
|
42424
|
+
return false;
|
|
42425
|
+
}
|
|
42426
|
+
|
|
42427
|
+
function hasSavedConfig() {
|
|
42428
|
+
return savedConfigData &&
|
|
42429
|
+
savedConfigData.egainUrl &&
|
|
42430
|
+
savedConfigData.clientId &&
|
|
42431
|
+
savedConfigData.authUrl &&
|
|
42432
|
+
savedConfigData.accessTokenUrl;
|
|
42433
|
+
}
|
|
42434
|
+
|
|
42435
|
+
function displaySavedConfig() {
|
|
42436
|
+
const listEl = document.getElementById('savedConfigList');
|
|
42437
|
+
listEl.innerHTML = '';
|
|
42438
|
+
if (!savedConfigData) return;
|
|
42439
|
+
|
|
42440
|
+
FIELDS.forEach(field => {
|
|
42441
|
+
const value = savedConfigData[field];
|
|
42442
|
+
if (value) {
|
|
42443
|
+
const item = document.createElement('div');
|
|
42444
|
+
item.className = 'config-item';
|
|
42445
|
+
const label = document.createElement('span');
|
|
42446
|
+
label.className = 'config-label';
|
|
42447
|
+
label.textContent = FIELD_LABELS[field];
|
|
42448
|
+
const valueSpan = document.createElement('span');
|
|
42449
|
+
valueSpan.className = 'config-value';
|
|
42450
|
+
if (field === 'clientSecret') {
|
|
42451
|
+
valueSpan.classList.add('masked');
|
|
42452
|
+
valueSpan.textContent = '••••••••';
|
|
42453
|
+
} else if (field === 'clientId') {
|
|
42454
|
+
valueSpan.textContent = value.substring(0, 8) + '...';
|
|
42455
|
+
} else {
|
|
42456
|
+
valueSpan.textContent = value.length > 40 ? value.substring(0, 40) + '...' : value;
|
|
42457
|
+
}
|
|
42458
|
+
item.appendChild(label);
|
|
42459
|
+
item.appendChild(valueSpan);
|
|
42460
|
+
listEl.appendChild(item);
|
|
42461
|
+
}
|
|
42462
|
+
});
|
|
42463
|
+
}
|
|
42464
|
+
|
|
42465
|
+
function showQuickSignin() {
|
|
42466
|
+
document.getElementById('quickSigninView').style.display = 'block';
|
|
42467
|
+
document.getElementById('formView').style.display = 'none';
|
|
42468
|
+
displaySavedConfig();
|
|
42469
|
+
}
|
|
42470
|
+
|
|
42471
|
+
function showForm() {
|
|
42472
|
+
document.getElementById('quickSigninView').style.display = 'none';
|
|
42473
|
+
document.getElementById('formView').style.display = 'block';
|
|
42474
|
+
loadFormValues();
|
|
42475
|
+
}
|
|
42476
|
+
|
|
42477
|
+
function loadFormValues() {
|
|
42478
|
+
if (!savedConfigData) return;
|
|
42479
|
+
|
|
42480
|
+
// Load all field values
|
|
42481
|
+
FIELDS.forEach(field => {
|
|
42482
|
+
const value = savedConfigData[field];
|
|
42483
|
+
if (value) document.getElementById(field).value = value;
|
|
42484
|
+
});
|
|
42485
|
+
|
|
42486
|
+
// Show advanced settings if clientSecret or scopePrefix exist
|
|
42487
|
+
if (savedConfigData.clientSecret || savedConfigData.scopePrefix) {
|
|
42488
|
+
toggleAdvancedSettings();
|
|
42489
|
+
}
|
|
42490
|
+
}
|
|
42491
|
+
|
|
42492
|
+
async function clearConfigAndShowForm() {
|
|
42493
|
+
showModal(
|
|
42494
|
+
'Clear All Configuration?',
|
|
42495
|
+
'This will delete all saved OAuth settings from your home directory. You will need to re-enter them next time.',
|
|
42496
|
+
async (confirmed) => {
|
|
42497
|
+
if (confirmed) {
|
|
42498
|
+
try {
|
|
42499
|
+
const response = await fetch('/clear-config', { method: 'POST' });
|
|
42500
|
+
if (response.ok) {
|
|
42501
|
+
savedConfigData = null;
|
|
42502
|
+
FIELDS.forEach(field => {
|
|
42503
|
+
document.getElementById(field).value = '';
|
|
42504
|
+
});
|
|
42505
|
+
showStatus('Configuration cleared successfully', 'success');
|
|
42506
|
+
showForm();
|
|
42507
|
+
} else {
|
|
42508
|
+
showStatus('Failed to clear configuration', 'error');
|
|
42509
|
+
}
|
|
42510
|
+
} catch (error) {
|
|
42511
|
+
showStatus('Error clearing configuration: ' + error.message, 'error');
|
|
42512
|
+
}
|
|
42513
|
+
}
|
|
42514
|
+
},
|
|
42515
|
+
'Clear All'
|
|
42516
|
+
);
|
|
42517
|
+
}
|
|
42518
|
+
|
|
42519
|
+
function cancelForm() {
|
|
42520
|
+
if (hasSavedConfig()) {
|
|
42521
|
+
showQuickSignin();
|
|
42522
|
+
} else {
|
|
42523
|
+
showModal(
|
|
42524
|
+
'Cancel Authentication?',
|
|
42525
|
+
"You haven't saved any configuration yet. This will cancel the authentication process.",
|
|
42526
|
+
async (confirmed) => {
|
|
42527
|
+
if (confirmed) {
|
|
42528
|
+
// Notify server that user cancelled
|
|
42529
|
+
try {
|
|
42530
|
+
await fetch('/cancel', { method: 'POST' });
|
|
42531
|
+
} catch (error) {
|
|
42532
|
+
console.error('Could not notify server of cancellation:', error);
|
|
42533
|
+
}
|
|
42534
|
+
window.close();
|
|
42535
|
+
}
|
|
42536
|
+
},
|
|
42537
|
+
'Cancel'
|
|
42538
|
+
);
|
|
42539
|
+
}
|
|
42540
|
+
}
|
|
42541
|
+
|
|
42542
|
+
async function signInWithSavedConfig() {
|
|
42543
|
+
authenticationStarted = true; // Mark that auth has started
|
|
42544
|
+
|
|
42545
|
+
// Show loading overlay
|
|
42546
|
+
showLoadingOverlay('Redirecting to login...');
|
|
42547
|
+
|
|
42548
|
+
try {
|
|
42549
|
+
const response = await fetch('/get-oauth-url', { method: 'POST' });
|
|
42550
|
+
const result = await response.json();
|
|
42551
|
+
|
|
42552
|
+
if (response.ok && result.oauthUrl) {
|
|
42553
|
+
console.log('\uD83D\uDD17 OAuth URL:', result.oauthUrl);
|
|
42554
|
+
// Redirect after a brief delay to show loading state
|
|
42555
|
+
setTimeout(() => {
|
|
42556
|
+
window.location.href = result.oauthUrl;
|
|
42557
|
+
}, 500);
|
|
42558
|
+
} else {
|
|
42559
|
+
hideLoadingOverlay();
|
|
42560
|
+
showStatus('❌ ' + (result.error || 'Failed to get OAuth URL'), 'error');
|
|
42561
|
+
authenticationStarted = false; // Reset on error
|
|
42562
|
+
}
|
|
42563
|
+
} catch (error) {
|
|
42564
|
+
hideLoadingOverlay();
|
|
42565
|
+
showStatus('❌ Error: ' + error.message, 'error');
|
|
42566
|
+
authenticationStarted = false; // Reset on error
|
|
42567
|
+
}
|
|
42568
|
+
}
|
|
42569
|
+
|
|
42570
|
+
function showStatus(message, type) {
|
|
42571
|
+
const statusEl = document.getElementById('status');
|
|
42572
|
+
statusEl.textContent = message;
|
|
42573
|
+
statusEl.className = 'status ' + type;
|
|
42574
|
+
statusEl.style.display = 'block';
|
|
42575
|
+
// Auto-hide info and success messages after a delay
|
|
42576
|
+
if (type === 'info') {
|
|
42577
|
+
setTimeout(() => {
|
|
42578
|
+
// Only hide if it's still an info message (not changed to success/error)
|
|
42579
|
+
if (statusEl.className === 'status info') {
|
|
42580
|
+
statusEl.style.display = 'none';
|
|
42581
|
+
}
|
|
42582
|
+
}, 3000);
|
|
42583
|
+
} else if (type === 'success') {
|
|
42584
|
+
setTimeout(() => {
|
|
42585
|
+
// Only hide if it's still a success message (not changed to error)
|
|
42586
|
+
if (statusEl.className === 'status success') {
|
|
42587
|
+
statusEl.style.display = 'none';
|
|
42588
|
+
}
|
|
42589
|
+
}, 4000);
|
|
42590
|
+
}
|
|
42591
|
+
}
|
|
42592
|
+
|
|
42593
|
+
function configValuesEqual(config1, config2) {
|
|
42594
|
+
// Compare all fields that matter
|
|
42595
|
+
const fieldsToCompare = ['egainUrl', 'authUrl', 'accessTokenUrl', 'clientId', 'redirectUrl', 'clientSecret', 'scopePrefix'];
|
|
42596
|
+
for (const field of fieldsToCompare) {
|
|
42597
|
+
const val1 = (config1[field] || '').trim();
|
|
42598
|
+
const val2 = (config2[field] || '').trim();
|
|
42599
|
+
if (val1 !== val2) {
|
|
42600
|
+
return false;
|
|
42601
|
+
}
|
|
42602
|
+
}
|
|
42603
|
+
return true;
|
|
42604
|
+
}
|
|
42605
|
+
|
|
42606
|
+
function showLoadingOverlay(message) {
|
|
42607
|
+
// Show overlay for form view
|
|
42608
|
+
const overlay = document.getElementById('loadingOverlay');
|
|
42609
|
+
const loadingMessage = document.getElementById('loadingMessage');
|
|
42610
|
+
if (overlay) {
|
|
42611
|
+
overlay.classList.add('active');
|
|
42612
|
+
if (loadingMessage) {
|
|
42613
|
+
loadingMessage.textContent = message || 'Saving configuration...';
|
|
42614
|
+
}
|
|
42615
|
+
}
|
|
42616
|
+
|
|
42617
|
+
// Show overlay for quick signin view
|
|
42618
|
+
const overlayQuickSignin = document.getElementById('loadingOverlayQuickSignin');
|
|
42619
|
+
const loadingMessageQuickSignin = document.getElementById('loadingMessageQuickSignin');
|
|
42620
|
+
if (overlayQuickSignin) {
|
|
42621
|
+
overlayQuickSignin.classList.add('active');
|
|
42622
|
+
if (loadingMessageQuickSignin) {
|
|
42623
|
+
loadingMessageQuickSignin.textContent = message || 'Redirecting to login...';
|
|
42624
|
+
}
|
|
42625
|
+
}
|
|
42626
|
+
}
|
|
42627
|
+
|
|
42628
|
+
function hideLoadingOverlay() {
|
|
42629
|
+
// Hide overlay for form view
|
|
42630
|
+
const overlay = document.getElementById('loadingOverlay');
|
|
42631
|
+
if (overlay) {
|
|
42632
|
+
overlay.classList.remove('active');
|
|
42633
|
+
}
|
|
42634
|
+
|
|
42635
|
+
// Hide overlay for quick signin view
|
|
42636
|
+
const overlayQuickSignin = document.getElementById('loadingOverlayQuickSignin');
|
|
42637
|
+
if (overlayQuickSignin) {
|
|
42638
|
+
overlayQuickSignin.classList.remove('active');
|
|
42639
|
+
}
|
|
42640
|
+
}
|
|
42641
|
+
|
|
42642
|
+
async function authenticateWithConfig(config) {
|
|
42643
|
+
// Prevent duplicate submissions
|
|
42644
|
+
if (isSubmitting) {
|
|
42645
|
+
return; // Already submitting, ignore
|
|
42646
|
+
}
|
|
42647
|
+
|
|
42648
|
+
// Check if values have changed since last submission
|
|
42649
|
+
if (lastSubmittedConfig && configValuesEqual(config, lastSubmittedConfig)) {
|
|
42650
|
+
showStatus('⚠️ Configuration unchanged. Already saved.', 'info');
|
|
42651
|
+
return; // Values haven't changed, don't submit again
|
|
42652
|
+
}
|
|
42653
|
+
|
|
42654
|
+
try {
|
|
42655
|
+
isSubmitting = true; // Mark as submitting
|
|
42656
|
+
const submitButton = document.querySelector('button[type="submit"]');
|
|
42657
|
+
if (submitButton) {
|
|
42658
|
+
submitButton.disabled = true;
|
|
42659
|
+
submitButton.textContent = 'Saving...';
|
|
42660
|
+
}
|
|
42661
|
+
|
|
42662
|
+
// Show loading overlay with spinner
|
|
42663
|
+
showLoadingOverlay('Saving configuration...');
|
|
42664
|
+
authenticationStarted = true; // Mark that auth has started
|
|
42665
|
+
|
|
42666
|
+
const response = await fetch('/authenticate', {
|
|
42667
|
+
method: 'POST',
|
|
42668
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42669
|
+
body: JSON.stringify(config)
|
|
42670
|
+
});
|
|
42671
|
+
const result = await response.json();
|
|
42672
|
+
|
|
42673
|
+
if (response.ok && result.oauthUrl) {
|
|
42674
|
+
// Config saved! Store this config as last submitted
|
|
42675
|
+
lastSubmittedConfig = { ...config };
|
|
42676
|
+
|
|
42677
|
+
console.log('\uD83D\uDD17 OAuth URL:', result.oauthUrl);
|
|
42678
|
+
|
|
42679
|
+
// Update loading message (overlay already shows the status, no need for status message)
|
|
42680
|
+
showLoadingOverlay('Configuration saved! Redirecting to login...');
|
|
42681
|
+
|
|
42682
|
+
setTimeout(() => {
|
|
42683
|
+
window.location.href = result.oauthUrl;
|
|
42684
|
+
}, 500);
|
|
42685
|
+
} else if (response.ok && result.success) {
|
|
42686
|
+
lastSubmittedConfig = { ...config };
|
|
42687
|
+
hideLoadingOverlay();
|
|
42688
|
+
showStatus('✅ ' + result.message, 'success');
|
|
42689
|
+
setTimeout(() => { window.close(); }, 2000);
|
|
42690
|
+
} else {
|
|
42691
|
+
hideLoadingOverlay();
|
|
42692
|
+
showStatus('❌ ' + (result.error || 'Authentication failed'), 'error');
|
|
42693
|
+
authenticationStarted = false; // Reset on error
|
|
42694
|
+
isSubmitting = false; // Reset submitting flag
|
|
42695
|
+
if (submitButton) {
|
|
42696
|
+
submitButton.disabled = false;
|
|
42697
|
+
submitButton.textContent = 'Save & Authenticate';
|
|
42698
|
+
}
|
|
42699
|
+
}
|
|
42700
|
+
} catch (error) {
|
|
42701
|
+
hideLoadingOverlay();
|
|
42702
|
+
showStatus('❌ Error: ' + error.message, 'error');
|
|
42703
|
+
authenticationStarted = false; // Reset on error
|
|
42704
|
+
isSubmitting = false; // Reset submitting flag
|
|
42705
|
+
const submitButton = document.querySelector('button[type="submit"]');
|
|
42706
|
+
if (submitButton) {
|
|
42707
|
+
submitButton.disabled = false;
|
|
42708
|
+
submitButton.textContent = 'Save & Authenticate';
|
|
42709
|
+
}
|
|
42710
|
+
}
|
|
42711
|
+
}
|
|
42712
|
+
|
|
42713
|
+
document.getElementById('configForm').addEventListener('submit', async (e) => {
|
|
42714
|
+
e.preventDefault();
|
|
42715
|
+
|
|
42716
|
+
// Prevent duplicate submissions
|
|
42717
|
+
if (isSubmitting) {
|
|
42718
|
+
return;
|
|
42719
|
+
}
|
|
42720
|
+
|
|
42721
|
+
const formData = new FormData(e.target);
|
|
42722
|
+
const config = {};
|
|
42723
|
+
for (let [key, value] of formData.entries()) {
|
|
42724
|
+
config[key] = value;
|
|
42725
|
+
}
|
|
42726
|
+
|
|
42727
|
+
// Config is now sent to backend for secure file storage (not cookies)
|
|
42728
|
+
await authenticateWithConfig(config);
|
|
42729
|
+
});
|
|
42730
|
+
|
|
42731
|
+
// Initialize: Load saved config from backend
|
|
42732
|
+
(async () => {
|
|
42733
|
+
const hasConfig = await loadSavedConfig();
|
|
42734
|
+
if (hasConfig) {
|
|
42735
|
+
showQuickSignin();
|
|
42736
|
+
} else {
|
|
42737
|
+
showForm();
|
|
42738
|
+
}
|
|
42739
|
+
})();
|
|
42740
|
+
|
|
42741
|
+
// Custom modal functions
|
|
42742
|
+
let modalCallback = null;
|
|
42743
|
+
|
|
42744
|
+
function showModal(title, message, callback, confirmText = 'Confirm') {
|
|
42745
|
+
document.getElementById('modalTitle').textContent = title;
|
|
42746
|
+
document.getElementById('modalMessage').textContent = message;
|
|
42747
|
+
document.getElementById('modalConfirmBtn').textContent = confirmText;
|
|
42748
|
+
modalCallback = callback;
|
|
42749
|
+
document.getElementById('confirmModal').classList.add('active');
|
|
42750
|
+
}
|
|
42751
|
+
|
|
42752
|
+
function closeModal(confirmed) {
|
|
42753
|
+
document.getElementById('confirmModal').classList.remove('active');
|
|
42754
|
+
if (modalCallback) {
|
|
42755
|
+
modalCallback(confirmed);
|
|
42756
|
+
modalCallback = null;
|
|
42757
|
+
}
|
|
42758
|
+
}
|
|
42759
|
+
|
|
42760
|
+
// Advanced settings toggle
|
|
42761
|
+
function toggleAdvancedSettings() {
|
|
42762
|
+
const advancedSection = document.getElementById('advancedSettings');
|
|
42763
|
+
const toggleIcon = document.getElementById('advancedToggleIcon');
|
|
42764
|
+
|
|
42765
|
+
if (advancedSection.style.display === 'none') {
|
|
42766
|
+
advancedSection.style.display = 'block';
|
|
42767
|
+
toggleIcon.textContent = '▼';
|
|
42768
|
+
} else {
|
|
42769
|
+
advancedSection.style.display = 'none';
|
|
42770
|
+
toggleIcon.textContent = '▶';
|
|
42771
|
+
}
|
|
42772
|
+
}
|
|
42773
|
+
|
|
42774
|
+
// Tooltip functions
|
|
42775
|
+
function showTooltip(event, fieldName) {
|
|
42776
|
+
event.preventDefault(); // Prevent label from focusing input
|
|
42777
|
+
event.stopPropagation(); // Prevent event from bubbling
|
|
42778
|
+
|
|
42779
|
+
const tooltipId = 'tooltip-' + fieldName;
|
|
42780
|
+
let tooltipElement = document.getElementById(tooltipId);
|
|
42781
|
+
const button = event.currentTarget;
|
|
42782
|
+
|
|
42783
|
+
if (tooltipElement) {
|
|
42784
|
+
// Show the tooltip first to get its dimensions
|
|
42785
|
+
tooltipElement.classList.add('active');
|
|
42786
|
+
|
|
42787
|
+
// Get actual dimensions after showing
|
|
42788
|
+
const buttonRect = button.getBoundingClientRect();
|
|
42789
|
+
const tooltipRect = tooltipElement.getBoundingClientRect();
|
|
42790
|
+
const tooltipWidth = tooltipRect.width || 380;
|
|
42791
|
+
const tooltipHeight = tooltipRect.height || 300;
|
|
42792
|
+
|
|
42793
|
+
const spacing = 16; // Space between button and tooltip
|
|
42794
|
+
const viewportPadding = 10; // Padding from viewport edges
|
|
42795
|
+
const horizontalComfortZone = 50; // Extra space needed to avoid cramped horizontal positioning
|
|
42796
|
+
|
|
42797
|
+
// Calculate available space on all sides
|
|
42798
|
+
const spaceOnRight = window.innerWidth - buttonRect.right;
|
|
42799
|
+
const spaceOnLeft = buttonRect.left;
|
|
42800
|
+
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
|
42801
|
+
const spaceAbove = buttonRect.top;
|
|
42802
|
+
|
|
42803
|
+
let left, top;
|
|
42804
|
+
let arrowSide = 'left'; // Default: tooltip on right, arrow on left
|
|
42805
|
+
|
|
42806
|
+
// Check if horizontal positioning would be too cramped (tooltip might cover the icon)
|
|
42807
|
+
const horizontalSpaceTight = (spaceOnRight < tooltipWidth + horizontalComfortZone) &&
|
|
42808
|
+
(spaceOnLeft < tooltipWidth + horizontalComfortZone);
|
|
42809
|
+
|
|
42810
|
+
if (horizontalSpaceTight) {
|
|
42811
|
+
// Use vertical positioning to avoid covering the icon
|
|
42812
|
+
// Determine if we're in the top or bottom half of the viewport
|
|
42813
|
+
const inTopHalf = buttonRect.top < window.innerHeight / 2;
|
|
42814
|
+
|
|
42815
|
+
if (inTopHalf && spaceBelow >= tooltipHeight + spacing + viewportPadding) {
|
|
42816
|
+
// Position below
|
|
42817
|
+
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42818
|
+
top = buttonRect.bottom + spacing;
|
|
42819
|
+
arrowSide = 'top';
|
|
42820
|
+
} else if (!inTopHalf && spaceAbove >= tooltipHeight + spacing + viewportPadding) {
|
|
42821
|
+
// Position above
|
|
42822
|
+
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42823
|
+
top = buttonRect.top - tooltipHeight - spacing;
|
|
42824
|
+
arrowSide = 'bottom';
|
|
42825
|
+
} else if (spaceBelow > spaceAbove) {
|
|
42826
|
+
// Not enough vertical space either, prefer below
|
|
42827
|
+
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42828
|
+
top = buttonRect.bottom + spacing;
|
|
42829
|
+
arrowSide = 'top';
|
|
42830
|
+
} else {
|
|
42831
|
+
// Prefer above
|
|
42832
|
+
left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
|
|
42833
|
+
top = buttonRect.top - tooltipHeight - spacing;
|
|
42834
|
+
arrowSide = 'bottom';
|
|
42835
|
+
}
|
|
42836
|
+
|
|
42837
|
+
// Keep horizontally centered within viewport
|
|
42838
|
+
if (left < viewportPadding) {
|
|
42839
|
+
left = viewportPadding;
|
|
42840
|
+
}
|
|
42841
|
+
if (left + tooltipWidth > window.innerWidth - viewportPadding) {
|
|
42842
|
+
left = window.innerWidth - tooltipWidth - viewportPadding;
|
|
42843
|
+
}
|
|
42844
|
+
|
|
42845
|
+
} else {
|
|
42846
|
+
// Use horizontal positioning (original logic)
|
|
42847
|
+
// Prefer right side if there's enough space
|
|
42848
|
+
if (spaceOnRight >= tooltipWidth + spacing + viewportPadding) {
|
|
42849
|
+
// Position to the right
|
|
42850
|
+
left = buttonRect.right + spacing;
|
|
42851
|
+
arrowSide = 'left';
|
|
42852
|
+
} else if (spaceOnLeft >= tooltipWidth + spacing + viewportPadding) {
|
|
42853
|
+
// Position to the left
|
|
42854
|
+
left = buttonRect.left - tooltipWidth - spacing;
|
|
42855
|
+
arrowSide = 'right';
|
|
42856
|
+
} else {
|
|
42857
|
+
// Not enough space on either side, use the side with more space
|
|
42858
|
+
if (spaceOnRight > spaceOnLeft) {
|
|
42859
|
+
left = buttonRect.right + spacing;
|
|
42860
|
+
arrowSide = 'left';
|
|
42861
|
+
// Allow tooltip to go to edge of screen
|
|
42862
|
+
if (left + tooltipWidth > window.innerWidth - viewportPadding) {
|
|
42863
|
+
left = window.innerWidth - tooltipWidth - viewportPadding;
|
|
42864
|
+
}
|
|
42865
|
+
} else {
|
|
42866
|
+
left = buttonRect.left - tooltipWidth - spacing;
|
|
42867
|
+
arrowSide = 'right';
|
|
42868
|
+
// Allow tooltip to go to edge of screen
|
|
42869
|
+
if (left < viewportPadding) {
|
|
42870
|
+
left = viewportPadding;
|
|
42871
|
+
}
|
|
42872
|
+
}
|
|
42873
|
+
}
|
|
42874
|
+
|
|
42875
|
+
// Center vertically relative to button
|
|
42876
|
+
top = buttonRect.top + (buttonRect.height / 2) - (tooltipHeight / 2);
|
|
42877
|
+
|
|
42878
|
+
// Keep tooltip within viewport vertically
|
|
42879
|
+
if (top < viewportPadding) {
|
|
42880
|
+
top = viewportPadding;
|
|
42881
|
+
}
|
|
42882
|
+
if (top + tooltipHeight > window.innerHeight - viewportPadding) {
|
|
42883
|
+
top = window.innerHeight - tooltipHeight - viewportPadding;
|
|
42884
|
+
}
|
|
42885
|
+
}
|
|
42886
|
+
|
|
42887
|
+
// Apply positioning
|
|
42888
|
+
tooltipElement.style.left = left + 'px';
|
|
42889
|
+
tooltipElement.style.top = top + 'px';
|
|
42890
|
+
|
|
42891
|
+
// Update arrow direction
|
|
42892
|
+
const arrow = tooltipElement.querySelector('.tooltip-arrow');
|
|
42893
|
+
if (arrow) {
|
|
42894
|
+
arrow.className = 'tooltip-arrow ' + arrowSide;
|
|
42895
|
+
}
|
|
42896
|
+
}
|
|
42897
|
+
}
|
|
42898
|
+
|
|
42899
|
+
function hideTooltip(event, fieldName) {
|
|
42900
|
+
const tooltipId = 'tooltip-' + fieldName;
|
|
42901
|
+
let tooltipElement = document.getElementById(tooltipId);
|
|
42902
|
+
|
|
42903
|
+
if (tooltipElement) {
|
|
42904
|
+
tooltipElement.classList.remove('active');
|
|
42905
|
+
}
|
|
42906
|
+
}
|
|
42907
|
+
|
|
42908
|
+
// Close tooltip on ESC key
|
|
42909
|
+
document.addEventListener('keydown', function(e) {
|
|
42910
|
+
if (e.key === 'Escape') {
|
|
42911
|
+
document.querySelectorAll('.tooltip-content').forEach(tip => {
|
|
42912
|
+
tip.classList.remove('active');
|
|
42913
|
+
});
|
|
42914
|
+
}
|
|
42915
|
+
});
|
|
42916
|
+
|
|
42917
|
+
// Notify server if window is closed without starting authentication
|
|
42918
|
+
window.addEventListener('beforeunload', function(e) {
|
|
42919
|
+
// Only send cancel if user never started the authentication process
|
|
42920
|
+
// (If they started auth, they either completed it or clicked cancel explicitly)
|
|
42921
|
+
if (!authenticationStarted) {
|
|
42922
|
+
// Use sendBeacon for reliable delivery even as page unloads
|
|
42923
|
+
navigator.sendBeacon('/cancel', '');
|
|
42924
|
+
}
|
|
42925
|
+
});`, SAFARI_WARNING_HTML = `<!DOCTYPE html>
|
|
42926
|
+
<html lang="en">
|
|
42927
|
+
<head>
|
|
42928
|
+
<meta charset="UTF-8">
|
|
42929
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
42930
|
+
<title>Safari Not Supported - eGain MCP</title>
|
|
42931
|
+
<style>
|
|
42932
|
+
* {
|
|
42933
|
+
margin: 0;
|
|
42934
|
+
padding: 0;
|
|
42935
|
+
box-sizing: border-box;
|
|
42936
|
+
}
|
|
42937
|
+
|
|
42938
|
+
body {
|
|
42939
|
+
font-family: "Open Sans", "Segoe UI", "SegoeUI", "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
|
42940
|
+
background: #fef1fd;
|
|
42941
|
+
min-height: 100vh;
|
|
42942
|
+
display: flex;
|
|
42943
|
+
justify-content: center;
|
|
42944
|
+
align-items: center;
|
|
42945
|
+
padding: 20px;
|
|
42946
|
+
}
|
|
42947
|
+
|
|
42948
|
+
.container {
|
|
42949
|
+
background: white;
|
|
42950
|
+
border-radius: 16px;
|
|
42951
|
+
box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.12);
|
|
42952
|
+
max-width: 500px;
|
|
42953
|
+
width: 100%;
|
|
42954
|
+
padding: 32px;
|
|
42955
|
+
text-align: center;
|
|
42956
|
+
}
|
|
42957
|
+
|
|
42958
|
+
.warning-icon {
|
|
42959
|
+
font-size: 64px;
|
|
42960
|
+
margin-bottom: 20px;
|
|
42961
|
+
}
|
|
42962
|
+
|
|
42963
|
+
h1 {
|
|
42964
|
+
color: #e74c3c;
|
|
42965
|
+
font-size: 28px;
|
|
42966
|
+
margin-bottom: 30px;
|
|
42967
|
+
font-weight: 600;
|
|
42968
|
+
}
|
|
42969
|
+
|
|
42970
|
+
.reason {
|
|
42971
|
+
background: #fff0f6;
|
|
42972
|
+
border-left: 4px solid #d946a6;
|
|
42973
|
+
padding: 20px;
|
|
42974
|
+
text-align: left;
|
|
42975
|
+
border-radius: 4px;
|
|
42976
|
+
}
|
|
42977
|
+
|
|
42978
|
+
.reason strong {
|
|
42979
|
+
color: #a21361;
|
|
42980
|
+
display: block;
|
|
42981
|
+
margin-bottom: 12px;
|
|
42982
|
+
font-size: 16px;
|
|
42983
|
+
}
|
|
42984
|
+
|
|
42985
|
+
.reason p {
|
|
42986
|
+
color: #a21361;
|
|
42987
|
+
font-size: 14px;
|
|
42988
|
+
line-height: 1.6;
|
|
42989
|
+
}
|
|
42990
|
+
</style>
|
|
42991
|
+
</head>
|
|
42992
|
+
<body>
|
|
42993
|
+
<div class="container">
|
|
42994
|
+
<div class="warning-icon">⚠️</div>
|
|
42995
|
+
<h1>Safari Not Supported</h1>
|
|
42996
|
+
|
|
42997
|
+
<div class="reason">
|
|
42998
|
+
<strong>Why?</strong>
|
|
42999
|
+
<p>
|
|
43000
|
+
Safari doesn't support private browsing mode via command line, which is required
|
|
43001
|
+
to protect your OAuth credentials from being cached or leaked. We prioritize your
|
|
43002
|
+
security over convenience.
|
|
43003
|
+
</p>
|
|
43004
|
+
</div>
|
|
43005
|
+
</div>
|
|
43006
|
+
</body>
|
|
43007
|
+
</html>`;
|
|
41871
43008
|
var init_auth_hook = __esm(() => {
|
|
41872
43009
|
__filename2 = fileURLToPath(import.meta.url);
|
|
41873
43010
|
__dirname2 = path.dirname(__filename2);
|
|
@@ -46680,7 +47817,7 @@ The Search API is a hybrid search service that combines semantic understanding w
|
|
|
46680
47817
|
function createMCPServer(deps) {
|
|
46681
47818
|
const server = new McpServer({
|
|
46682
47819
|
name: "EgainMcp",
|
|
46683
|
-
version: "1.0.
|
|
47820
|
+
version: "1.0.4"
|
|
46684
47821
|
});
|
|
46685
47822
|
const getClient = deps.getSDK || (() => new EgainMcpCore({
|
|
46686
47823
|
security: deps.security,
|
|
@@ -47927,7 +49064,7 @@ var routes = ln({
|
|
|
47927
49064
|
var app = _e(routes, {
|
|
47928
49065
|
name: "mcp",
|
|
47929
49066
|
versionInfo: {
|
|
47930
|
-
currentVersion: "1.0.
|
|
49067
|
+
currentVersion: "1.0.4"
|
|
47931
49068
|
}
|
|
47932
49069
|
});
|
|
47933
49070
|
Yt(app, process3.argv.slice(2), buildContext(process3));
|
|
@@ -47935,5 +49072,5 @@ export {
|
|
|
47935
49072
|
app
|
|
47936
49073
|
};
|
|
47937
49074
|
|
|
47938
|
-
//# debugId=
|
|
49075
|
+
//# debugId=86F26C1E2362842864756E2164756E21
|
|
47939
49076
|
//# sourceMappingURL=mcp-server.js.map
|