supporthero-mcp-server 1.1.2 → 1.1.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/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts +14 -16
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +97 -93
- package/dist/session.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ if (writeEnabled) {
|
|
|
28
28
|
// ── Server Setup ────────────────────────────────────────────
|
|
29
29
|
const server = new McpServer({
|
|
30
30
|
name: "supporthero-mcp-server",
|
|
31
|
-
version: "1.1.
|
|
31
|
+
version: "1.1.4",
|
|
32
32
|
});
|
|
33
33
|
const client = new SupportHeroClient(SUPPORTHERO_DOMAIN, SUPPORTHERO_API_KEY, session);
|
|
34
34
|
registerTools(server, client);
|
|
@@ -37,17 +37,16 @@ if (writeEnabled) {
|
|
|
37
37
|
}
|
|
38
38
|
// ── Transport ───────────────────────────────────────────────
|
|
39
39
|
async function main() {
|
|
40
|
-
//
|
|
41
|
-
//
|
|
40
|
+
// Attempt login at startup to validate credentials early.
|
|
41
|
+
// Non-fatal: if it fails, write tools will retry on first use.
|
|
42
42
|
if (session) {
|
|
43
43
|
try {
|
|
44
44
|
await session.login();
|
|
45
|
+
console.error("[startup] Write session authenticated successfully");
|
|
45
46
|
}
|
|
46
47
|
catch (error) {
|
|
47
|
-
console.error("
|
|
48
|
-
"Check SUPPORTHERO_EMAIL and SUPPORTHERO_PASSWORD.\n" +
|
|
48
|
+
console.error("[startup] WARNING: Initial login failed. Write tools will retry on first use.\n" +
|
|
49
49
|
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
-
process.exit(1);
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
const transport = new StdioServerTransport();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,+DAA+D;AAE/D,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAC1D,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AAC5D,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACxD,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAE9D,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACxB,OAAO,CAAC,KAAK,CACX,sCAAsC;QACtC,yEAAyE,CAC1E,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,CACX,uCAAuC;QACvC,+DAA+D,CAChE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,+DAA+D;AAE/D,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,iBAAiB,IAAI,oBAAoB,CAAC,CAAC;AACnE,IAAI,OAAmC,CAAC;AAExC,IAAI,YAAY,EAAE,CAAC;IACjB,OAAO,GAAG,IAAI,cAAc,CAAC,iBAAkB,EAAE,oBAAqB,EAAE,kBAAkB,CAAC,CAAC;AAC9F,CAAC;AAED,+DAA+D;AAE/D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,OAAO,CAAC,CAAC;AAEvF,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9B,IAAI,YAAY,EAAE,CAAC;IACjB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,+DAA+D;IAC/D,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,+DAA+D;AAE/D,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAC1D,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AAC5D,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACxD,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAE9D,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACxB,OAAO,CAAC,KAAK,CACX,sCAAsC;QACtC,yEAAyE,CAC1E,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,CACX,uCAAuC;QACvC,+DAA+D,CAChE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,+DAA+D;AAE/D,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,iBAAiB,IAAI,oBAAoB,CAAC,CAAC;AACnE,IAAI,OAAmC,CAAC;AAExC,IAAI,YAAY,EAAE,CAAC;IACjB,OAAO,GAAG,IAAI,cAAc,CAAC,iBAAkB,EAAE,oBAAqB,EAAE,kBAAkB,CAAC,CAAC;AAC9F,CAAC;AAED,+DAA+D;AAE/D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,OAAO,CAAC,CAAC;AAEvF,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9B,IAAI,YAAY,EAAE,CAAC;IACjB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,0DAA0D;IAC1D,+DAA+D;IAC/D,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,iFAAiF;gBACjF,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CACX,yDAAyD,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,GAAG,CAClG,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/session.d.ts
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
* Session management for SupportHero write operations.
|
|
3
3
|
*
|
|
4
4
|
* SupportHero's write API requires session-based authentication via cookies
|
|
5
|
-
* (JSESSIONID
|
|
6
|
-
* on signin.supporthero.io.
|
|
5
|
+
* (JSESSIONID), obtained through a two-step login flow discovered by
|
|
6
|
+
* reverse-engineering the AngularJS SPA on signin.supporthero.io.
|
|
7
7
|
*
|
|
8
|
-
* The login flow
|
|
9
|
-
* 1. GET /api/session/preLogin
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* The login flow:
|
|
9
|
+
* 1. GET /api/session/preLogin on signin.supporthero.io
|
|
10
|
+
* params: domain={subdomain}, email={email}, password={base64}, redirect=true
|
|
11
|
+
* returns: { success: true, salt: "...", subDomain: "propel" }
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - Making authenticated requests with automatic session renewal
|
|
13
|
+
* 2. GET https://{subDomain}.supporthero.io?signedIn=true&email={email}&salt={salt}
|
|
14
|
+
* The server validates the salt and establishes an authenticated session,
|
|
15
|
+
* returning JSESSIONID cookies that authenticate write API calls.
|
|
17
16
|
*/
|
|
18
17
|
export declare class SessionManager {
|
|
19
18
|
private email;
|
|
@@ -32,13 +31,12 @@ export declare class SessionManager {
|
|
|
32
31
|
*/
|
|
33
32
|
private getCookieHeader;
|
|
34
33
|
/**
|
|
35
|
-
* Log in to SupportHero
|
|
34
|
+
* Log in to SupportHero.
|
|
36
35
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* On success, the server responds with a redirect chain that sets session cookies.
|
|
36
|
+
* Step 1: GET preLogin on signin.supporthero.io to validate credentials
|
|
37
|
+
* and receive a salt token.
|
|
38
|
+
* Step 2: GET {subdomain}.supporthero.io?signedIn=true&email=...&salt=...
|
|
39
|
+
* to establish an authenticated session with JSESSIONID cookies.
|
|
42
40
|
*/
|
|
43
41
|
login(): Promise<void>;
|
|
44
42
|
/**
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,eAAe,CAAS;gBAEpB,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAS3D;;OAEG;IACH,OAAO,CAAC,cAAc;IAoBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2G5B;;;OAGG;IACG,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;CA2CpF"}
|
package/dist/session.js
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
* Session management for SupportHero write operations.
|
|
3
3
|
*
|
|
4
4
|
* SupportHero's write API requires session-based authentication via cookies
|
|
5
|
-
* (JSESSIONID
|
|
6
|
-
* on signin.supporthero.io.
|
|
5
|
+
* (JSESSIONID), obtained through a two-step login flow discovered by
|
|
6
|
+
* reverse-engineering the AngularJS SPA on signin.supporthero.io.
|
|
7
7
|
*
|
|
8
|
-
* The login flow
|
|
9
|
-
* 1. GET /api/session/preLogin
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* The login flow:
|
|
9
|
+
* 1. GET /api/session/preLogin on signin.supporthero.io
|
|
10
|
+
* params: domain={subdomain}, email={email}, password={base64}, redirect=true
|
|
11
|
+
* returns: { success: true, salt: "...", subDomain: "propel" }
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - Making authenticated requests with automatic session renewal
|
|
13
|
+
* 2. GET https://{subDomain}.supporthero.io?signedIn=true&email={email}&salt={salt}
|
|
14
|
+
* The server validates the salt and establishes an authenticated session,
|
|
15
|
+
* returning JSESSIONID cookies that authenticate write API calls.
|
|
17
16
|
*/
|
|
18
17
|
export class SessionManager {
|
|
19
18
|
email;
|
|
@@ -25,7 +24,6 @@ export class SessionManager {
|
|
|
25
24
|
constructor(email, password, domain) {
|
|
26
25
|
this.email = email;
|
|
27
26
|
this.password = password;
|
|
28
|
-
// Extract subdomain from domain URL (e.g. "https://propel.supporthero.io" -> "propel")
|
|
29
27
|
const hostname = new URL(domain).hostname;
|
|
30
28
|
this.subdomain = hostname.split(".")[0];
|
|
31
29
|
this.baseUrl = domain.replace(/\/+$/, "");
|
|
@@ -37,17 +35,17 @@ export class SessionManager {
|
|
|
37
35
|
collectCookies(response, label) {
|
|
38
36
|
const setCookieHeaders = response.headers.getSetCookie?.() ?? [];
|
|
39
37
|
if (setCookieHeaders.length === 0) {
|
|
40
|
-
console.error(`[session] ${label}: No Set-Cookie headers
|
|
38
|
+
console.error(`[session] ${label}: No Set-Cookie headers`);
|
|
41
39
|
return;
|
|
42
40
|
}
|
|
43
41
|
for (const header of setCookieHeaders) {
|
|
44
|
-
const nameValue = header.split(";")[0];
|
|
42
|
+
const nameValue = header.split(";")[0];
|
|
45
43
|
const eqIndex = nameValue.indexOf("=");
|
|
46
44
|
if (eqIndex > 0) {
|
|
47
45
|
const name = nameValue.slice(0, eqIndex).trim();
|
|
48
46
|
const value = nameValue.slice(eqIndex + 1).trim();
|
|
49
47
|
this.cookies.set(name, value);
|
|
50
|
-
console.error(`[session] ${label}:
|
|
48
|
+
console.error(`[session] ${label}: cookie ${name}=${value.slice(0, 20)}...`);
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
}
|
|
@@ -60,75 +58,96 @@ export class SessionManager {
|
|
|
60
58
|
.join("; ");
|
|
61
59
|
}
|
|
62
60
|
/**
|
|
63
|
-
* Log in to SupportHero
|
|
61
|
+
* Log in to SupportHero.
|
|
64
62
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* On success, the server responds with a redirect chain that sets session cookies.
|
|
63
|
+
* Step 1: GET preLogin on signin.supporthero.io to validate credentials
|
|
64
|
+
* and receive a salt token.
|
|
65
|
+
* Step 2: GET {subdomain}.supporthero.io?signedIn=true&email=...&salt=...
|
|
66
|
+
* to establish an authenticated session with JSESSIONID cookies.
|
|
70
67
|
*/
|
|
71
68
|
async login() {
|
|
72
69
|
this.cookies.clear();
|
|
73
70
|
this.isAuthenticated = false;
|
|
74
|
-
console.error("[session] Starting login
|
|
75
|
-
//
|
|
71
|
+
console.error("[session] Starting login...");
|
|
72
|
+
// ── Step 1: preLogin ─────────────────────────────────────────────
|
|
76
73
|
const encodedPassword = Buffer.from(this.password).toString("base64");
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
console.error(`[session] GET preLogin
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
const preLoginUrl = new URL("https://signin.supporthero.io/api/session/preLogin");
|
|
75
|
+
preLoginUrl.searchParams.set("domain", this.subdomain);
|
|
76
|
+
preLoginUrl.searchParams.set("email", this.email);
|
|
77
|
+
preLoginUrl.searchParams.set("password", encodedPassword);
|
|
78
|
+
preLoginUrl.searchParams.set("redirect", "true");
|
|
79
|
+
console.error(`[session] Step 1: GET preLogin domain="${this.subdomain}"`);
|
|
80
|
+
const preLoginResp = await fetch(preLoginUrl.toString(), { redirect: "manual" });
|
|
81
|
+
console.error(`[session] Step 1: status=${preLoginResp.status}`);
|
|
82
|
+
this.collectCookies(preLoginResp, "preLogin");
|
|
83
|
+
const preLoginBody = await preLoginResp.text();
|
|
84
|
+
console.error(`[session] Step 1: body length=${preLoginBody.length}`);
|
|
85
|
+
let preLoginData;
|
|
86
|
+
try {
|
|
87
|
+
preLoginData = JSON.parse(preLoginBody);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
throw new Error(`preLogin returned non-JSON: ${preLoginBody.slice(0, 200)}`);
|
|
91
|
+
}
|
|
92
|
+
if (preLoginData.error) {
|
|
93
|
+
throw new Error(`Login failed: ${preLoginData.error}`);
|
|
94
|
+
}
|
|
95
|
+
if (!preLoginData.success || !preLoginData.salt) {
|
|
96
|
+
throw new Error(`Unexpected preLogin response: ${preLoginBody.slice(0, 200)}`);
|
|
97
|
+
}
|
|
98
|
+
const salt = preLoginData.salt;
|
|
99
|
+
const confirmedSubDomain = preLoginData.subDomain ?? this.subdomain;
|
|
100
|
+
console.error(`[session] Step 1: OK. subDomain="${confirmedSubDomain}", salt received`);
|
|
101
|
+
// ── Step 2: Hit subdomain with signedIn + salt ───────────────────
|
|
102
|
+
// This is what the browser does after preLogin succeeds:
|
|
103
|
+
// window.location.href = "https://{subDomain}.supporthero.io?signedIn=true&email={email}&salt={salt}"
|
|
104
|
+
// The server validates the salt and creates an authenticated session.
|
|
105
|
+
const signedInUrl = `https://${confirmedSubDomain}.supporthero.io` +
|
|
106
|
+
`?signedIn=true&email=${encodeURIComponent(this.email)}&salt=${salt}`;
|
|
107
|
+
console.error(`[session] Step 2: GET ${confirmedSubDomain}.supporthero.io?signedIn=true&...`);
|
|
108
|
+
let resp = await fetch(signedInUrl, { redirect: "manual" });
|
|
109
|
+
console.error(`[session] Step 2: status=${resp.status}`);
|
|
110
|
+
this.collectCookies(resp, "signedIn");
|
|
111
|
+
// Follow any redirect chain, collecting cookies at each hop
|
|
90
112
|
const maxRedirects = 10;
|
|
91
113
|
let redirectCount = 0;
|
|
92
|
-
while (isRedirect(
|
|
93
|
-
const location =
|
|
94
|
-
if (!location)
|
|
95
|
-
console.error(`[session] Redirect ${redirectCount + 1}: No Location header, stopping`);
|
|
114
|
+
while (isRedirect(resp.status) && redirectCount < maxRedirects) {
|
|
115
|
+
const location = resp.headers.get("location");
|
|
116
|
+
if (!location)
|
|
96
117
|
break;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
method: "GET",
|
|
102
|
-
headers: {
|
|
103
|
-
"Cookie": this.getCookieHeader(),
|
|
104
|
-
},
|
|
118
|
+
const nextUrl = new URL(location, signedInUrl).toString();
|
|
119
|
+
console.error(`[session] Step 2: redirect ${redirectCount + 1} -> ${nextUrl}`);
|
|
120
|
+
resp = await fetch(nextUrl, {
|
|
121
|
+
headers: { "Cookie": this.getCookieHeader() },
|
|
105
122
|
redirect: "manual",
|
|
106
123
|
});
|
|
107
|
-
console.error(`[session]
|
|
108
|
-
this.collectCookies(
|
|
124
|
+
console.error(`[session] Step 2: redirect ${redirectCount + 1} status=${resp.status}`);
|
|
125
|
+
this.collectCookies(resp, `redirect ${redirectCount + 1}`);
|
|
109
126
|
redirectCount++;
|
|
110
127
|
}
|
|
111
|
-
// If no redirects happened (status 200), the login may have failed.
|
|
112
|
-
// Check the response body for error indicators.
|
|
113
|
-
if (redirectCount === 0 && response.status === 200) {
|
|
114
|
-
const body = await response.text();
|
|
115
|
-
console.error(`[session] No redirects after preLogin. Response body length=${body.length}`);
|
|
116
|
-
if (body.includes("credentials") || body.includes("error") || body.includes("invalid")) {
|
|
117
|
-
console.error(`[session] Response appears to contain an error message`);
|
|
118
|
-
}
|
|
119
|
-
// Even without redirects, check if we got useful cookies
|
|
120
|
-
}
|
|
121
|
-
// Log the final cookie state
|
|
122
128
|
const cookieNames = Array.from(this.cookies.keys());
|
|
123
|
-
console.error(`[session]
|
|
124
|
-
console.error(`[session] Has JSESSIONID=${this.cookies.has("JSESSIONID")}, Has X-Session-Token=${this.cookies.has("X-Session-Token")}`);
|
|
129
|
+
console.error(`[session] Cookies: ${JSON.stringify(cookieNames)}`);
|
|
125
130
|
if (!this.cookies.has("JSESSIONID")) {
|
|
126
|
-
throw new Error(
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
throw new Error(`Login flow completed but no JSESSIONID cookie. Cookies: ${JSON.stringify(cookieNames)}`);
|
|
132
|
+
}
|
|
133
|
+
// ── Verify session works ─────────────────────────────────────────
|
|
134
|
+
// SupportHero returns 200 + empty body for unauthenticated GET /api/article,
|
|
135
|
+
// so we check the response has content.
|
|
136
|
+
console.error("[session] Verifying session...");
|
|
137
|
+
const verifyResp = await fetch(`${this.baseUrl}/api/article`, {
|
|
138
|
+
headers: {
|
|
139
|
+
"Cookie": this.getCookieHeader(),
|
|
140
|
+
"Accept": "application/json",
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
const verifyBody = await verifyResp.text();
|
|
144
|
+
console.error(`[session] Verify: status=${verifyResp.status}, bodyLength=${verifyBody.length}`);
|
|
145
|
+
if (verifyBody.length === 0) {
|
|
146
|
+
throw new Error("Session cookies received but verification failed (empty response from /api/article). " +
|
|
147
|
+
`Cookies: ${JSON.stringify(cookieNames)}`);
|
|
129
148
|
}
|
|
130
149
|
this.isAuthenticated = true;
|
|
131
|
-
console.error("[session] Login successful
|
|
150
|
+
console.error("[session] Login successful and verified!");
|
|
132
151
|
}
|
|
133
152
|
/**
|
|
134
153
|
* Make an authenticated HTTP request. Automatically logs in if needed
|
|
@@ -136,67 +155,52 @@ export class SessionManager {
|
|
|
136
155
|
*/
|
|
137
156
|
async authenticatedFetch(url, options = {}) {
|
|
138
157
|
if (!this.isAuthenticated) {
|
|
139
|
-
console.error(`[session] Not authenticated
|
|
158
|
+
console.error(`[session] Not authenticated, logging in before ${url}`);
|
|
140
159
|
await this.login();
|
|
141
160
|
}
|
|
142
161
|
const doFetch = async () => {
|
|
143
162
|
const headers = new Headers(options.headers);
|
|
144
163
|
headers.set("Cookie", this.getCookieHeader());
|
|
145
|
-
console.error(`[session]
|
|
146
|
-
|
|
147
|
-
return fetch(url, {
|
|
148
|
-
...options,
|
|
149
|
-
headers,
|
|
150
|
-
redirect: "manual",
|
|
151
|
-
});
|
|
164
|
+
console.error(`[session] fetch: ${options.method || "GET"} ${url}`);
|
|
165
|
+
return fetch(url, { ...options, headers, redirect: "manual" });
|
|
152
166
|
};
|
|
153
167
|
let response = await doFetch();
|
|
154
|
-
console.error(`[session]
|
|
155
|
-
// Detect session expiry: 401, 403, or redirect back to signin
|
|
168
|
+
console.error(`[session] fetch: status=${response.status}`);
|
|
156
169
|
if (isSessionExpired(response)) {
|
|
157
|
-
console.error("[session] Session expired
|
|
170
|
+
console.error("[session] Session expired, re-authenticating...");
|
|
158
171
|
await this.login();
|
|
159
172
|
response = await doFetch();
|
|
160
|
-
console.error(`[session]
|
|
173
|
+
console.error(`[session] fetch retry: status=${response.status}`);
|
|
161
174
|
if (isSessionExpired(response)) {
|
|
162
|
-
throw new Error("
|
|
163
|
-
"Check your credentials and try again.");
|
|
175
|
+
throw new Error("Authentication failed after retry.");
|
|
164
176
|
}
|
|
165
177
|
}
|
|
166
|
-
//
|
|
178
|
+
// Follow non-login redirects with cookies
|
|
167
179
|
if (isRedirect(response.status)) {
|
|
168
180
|
const location = response.headers.get("location");
|
|
169
181
|
if (location) {
|
|
170
182
|
const redirectUrl = new URL(location, url).toString();
|
|
171
|
-
console.error(`[session]
|
|
183
|
+
console.error(`[session] fetch: following redirect to ${redirectUrl}`);
|
|
172
184
|
const headers = new Headers();
|
|
173
185
|
headers.set("Cookie", this.getCookieHeader());
|
|
174
186
|
headers.set("Accept", "application/json");
|
|
175
187
|
response = await fetch(redirectUrl, { headers });
|
|
176
|
-
console.error(`[session] authenticatedFetch: Redirect response status=${response.status}`);
|
|
177
188
|
}
|
|
178
189
|
}
|
|
190
|
+
this.collectCookies(response, "fetch response");
|
|
179
191
|
return response;
|
|
180
192
|
}
|
|
181
193
|
}
|
|
182
|
-
/**
|
|
183
|
-
* Check if an HTTP status code is a redirect.
|
|
184
|
-
*/
|
|
185
194
|
function isRedirect(status) {
|
|
186
195
|
return status >= 300 && status < 400;
|
|
187
196
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Detect whether a response indicates an expired or invalid session.
|
|
190
|
-
*/
|
|
191
197
|
function isSessionExpired(response) {
|
|
192
|
-
if (response.status === 401 || response.status === 403)
|
|
198
|
+
if (response.status === 401 || response.status === 403)
|
|
193
199
|
return true;
|
|
194
|
-
}
|
|
195
200
|
if (isRedirect(response.status)) {
|
|
196
201
|
const location = response.headers.get("location") ?? "";
|
|
197
|
-
if (location.includes("signin.supporthero.io"))
|
|
202
|
+
if (location.includes("signin.supporthero.io"))
|
|
198
203
|
return true;
|
|
199
|
-
}
|
|
200
204
|
}
|
|
201
205
|
return false;
|
|
202
206
|
}
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supporthero-mcp-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "MCP server for SupportHero Help Center API. Enables Claude and other LLMs to search, browse, read, and update help center articles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|