mcp-sunsama 0.15.1 → 0.15.3
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/CHANGELOG.md +12 -0
- package/dist/auth/http.d.ts.map +1 -1
- package/dist/auth/http.js +8 -3
- package/dist/auth/stdio.d.ts +1 -1
- package/dist/auth/stdio.d.ts.map +1 -1
- package/dist/auth/stdio.js +1 -1
- package/dist/auth/types.d.ts +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/main.js +1 -1
- package/dist/resources/index.js +1 -1
- package/dist/utils/client-resolver.d.ts +1 -1
- package/dist/utils/client-resolver.d.ts.map +1 -1
- package/dist/utils/client-resolver.js +1 -1
- package/dist/utils/task-filters.d.ts +1 -1
- package/dist/utils/task-filters.d.ts.map +1 -1
- package/dist/utils/task-trimmer.d.ts +1 -1
- package/dist/utils/task-trimmer.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/auth/http.ts +1 -1
- package/src/auth/stdio.ts +1 -1
- package/src/auth/types.ts +1 -1
- package/src/main.ts +1 -1
- package/src/tools/task-tools.ts +1 -1
- package/src/utils/client-resolver.ts +1 -1
- package/src/utils/task-filters.ts +1 -1
- package/src/utils/task-trimmer.ts +1 -1
- package/tsconfig.json +2 -1
- package/dist/__tests__/integration/http-transport.test.d.ts +0 -2
- package/dist/__tests__/integration/http-transport.test.d.ts.map +0 -1
- package/dist/__tests__/integration/http-transport.test.js +0 -265
- package/dist/__tests__/unit/auth/http.test.d.ts +0 -2
- package/dist/__tests__/unit/auth/http.test.d.ts.map +0 -1
- package/dist/__tests__/unit/auth/http.test.js +0 -211
- package/dist/__tests__/unit/config/session-config.test.d.ts +0 -2
- package/dist/__tests__/unit/config/session-config.test.d.ts.map +0 -1
- package/dist/__tests__/unit/config/session-config.test.js +0 -134
- package/dist/__tests__/unit/session/session-manager.test.d.ts +0 -2
- package/dist/__tests__/unit/session/session-manager.test.d.ts.map +0 -1
- package/dist/__tests__/unit/session/session-manager.test.js +0 -192
- package/dist/context/index.d.ts +0 -9
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js +0 -5
- package/dist/src/auth/http.d.ts +0 -23
- package/dist/src/auth/http.d.ts.map +0 -1
- package/dist/src/auth/http.js +0 -165
- package/dist/src/auth/stdio.d.ts +0 -13
- package/dist/src/auth/stdio.d.ts.map +0 -1
- package/dist/src/auth/stdio.js +0 -28
- package/dist/src/auth/types.d.ts +0 -11
- package/dist/src/auth/types.d.ts.map +0 -1
- package/dist/src/auth/types.js +0 -1
- package/dist/src/config/session-config.d.ts +0 -49
- package/dist/src/config/session-config.d.ts.map +0 -1
- package/dist/src/config/session-config.js +0 -54
- package/dist/src/config/transport.d.ts +0 -12
- package/dist/src/config/transport.d.ts.map +0 -1
- package/dist/src/config/transport.js +0 -27
- package/dist/src/main.d.ts +0 -3
- package/dist/src/main.d.ts.map +0 -1
- package/dist/src/main.js +0 -58
- package/dist/src/resources/index.d.ts +0 -13
- package/dist/src/resources/index.d.ts.map +0 -1
- package/dist/src/resources/index.js +0 -166
- package/dist/src/schemas.d.ts +0 -658
- package/dist/src/schemas.d.ts.map +0 -1
- package/dist/src/schemas.js +0 -193
- package/dist/src/schemas.test.d.ts +0 -2
- package/dist/src/schemas.test.d.ts.map +0 -1
- package/dist/src/schemas.test.js +0 -857
- package/dist/src/session/session-manager.d.ts +0 -53
- package/dist/src/session/session-manager.d.ts.map +0 -1
- package/dist/src/session/session-manager.js +0 -141
- package/dist/src/tools/index.d.ts +0 -11
- package/dist/src/tools/index.d.ts.map +0 -1
- package/dist/src/tools/index.js +0 -12
- package/dist/src/tools/shared.d.ts +0 -63
- package/dist/src/tools/shared.d.ts.map +0 -1
- package/dist/src/tools/shared.js +0 -84
- package/dist/src/tools/stream-tools.d.ts +0 -13
- package/dist/src/tools/stream-tools.d.ts.map +0 -1
- package/dist/src/tools/stream-tools.js +0 -12
- package/dist/src/tools/task-tools.d.ts +0 -91
- package/dist/src/tools/task-tools.d.ts.map +0 -1
- package/dist/src/tools/task-tools.js +0 -271
- package/dist/src/tools/user-tools.d.ts +0 -13
- package/dist/src/tools/user-tools.d.ts.map +0 -1
- package/dist/src/tools/user-tools.js +0 -13
- package/dist/src/transports/http.d.ts +0 -8
- package/dist/src/transports/http.d.ts.map +0 -1
- package/dist/src/transports/http.js +0 -245
- package/dist/src/transports/stdio.d.ts +0 -3
- package/dist/src/transports/stdio.d.ts.map +0 -1
- package/dist/src/transports/stdio.js +0 -11
- package/dist/src/utils/client-resolver.d.ts +0 -8
- package/dist/src/utils/client-resolver.d.ts.map +0 -1
- package/dist/src/utils/client-resolver.js +0 -23
- package/dist/src/utils/task-filters.d.ts +0 -29
- package/dist/src/utils/task-filters.d.ts.map +0 -1
- package/dist/src/utils/task-filters.js +0 -42
- package/dist/src/utils/task-trimmer.d.ts +0 -50
- package/dist/src/utils/task-trimmer.d.ts.map +0 -1
- package/dist/src/utils/task-trimmer.js +0 -59
- package/dist/src/utils/to-tsv.d.ts +0 -8
- package/dist/src/utils/to-tsv.d.ts.map +0 -1
- package/dist/src/utils/to-tsv.js +0 -64
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# mcp-sunsama
|
|
2
2
|
|
|
3
|
+
## 0.15.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b9cd204: Fix TypeScript build output by excluding **tests** from compilation. Version 0.15.2 broke because TypeScript was compiling both src/ and **tests**/ directories, causing files to be output to dist/src/ instead of dist/. Now excludes **tests** so production code builds directly to dist/.
|
|
8
|
+
|
|
9
|
+
## 0.15.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 6128d4c: Fix Node.js v20 compatibility by using sunsama-api subpath exports. Updates all imports to use explicit subpath exports ('sunsama-api/client' and 'sunsama-api/types') instead of root import, resolving ESM/CommonJS interoperability issues.
|
|
14
|
+
|
|
3
15
|
## 0.15.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/auth/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/auth/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAe9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/auth/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAe9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiBtF;AA+CD,wBAAgB,uBAAuB,IAAI,IAAI,CAQ9C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAM7C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAYxC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CAiEtB"}
|
package/dist/auth/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "crypto";
|
|
2
|
-
import { SunsamaClient } from "sunsama-api";
|
|
2
|
+
import { SunsamaClient } from "sunsama-api/client";
|
|
3
3
|
import { getSessionConfig } from "../config/session-config.js";
|
|
4
4
|
// Client cache with TTL management (keyed by credential hash for security)
|
|
5
5
|
const clientCache = new Map();
|
|
@@ -16,8 +16,13 @@ const CLEANUP_INTERVAL = sessionConfig.CLEANUP_INTERVAL;
|
|
|
16
16
|
export function parseBasicAuth(authHeader) {
|
|
17
17
|
const base64Credentials = authHeader.replace('Basic ', '');
|
|
18
18
|
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
19
|
+
const colonIndex = credentials.indexOf(':');
|
|
20
|
+
if (colonIndex === -1) {
|
|
21
|
+
throw new Error("Invalid Basic Auth format");
|
|
22
|
+
}
|
|
23
|
+
const email = credentials.substring(0, colonIndex);
|
|
24
|
+
const password = credentials.substring(colonIndex + 1);
|
|
25
|
+
if (!email || password === undefined) {
|
|
21
26
|
throw new Error("Invalid Basic Auth format");
|
|
22
27
|
}
|
|
23
28
|
return { email, password };
|
package/dist/auth/stdio.d.ts
CHANGED
package/dist/auth/stdio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnD;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAWlE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC,CAMrE"}
|
package/dist/auth/stdio.js
CHANGED
package/dist/auth/types.d.ts
CHANGED
package/dist/auth/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
|
package/dist/auth/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import { SunsamaClient } from "sunsama-api";
|
|
1
|
+
import { SunsamaClient } from "sunsama-api/client";
|
package/dist/main.js
CHANGED
|
@@ -9,7 +9,7 @@ import { apiDocumentationResource } from "./resources/index.js";
|
|
|
9
9
|
(async () => {
|
|
10
10
|
const server = new McpServer({
|
|
11
11
|
name: "Sunsama API Server",
|
|
12
|
-
version: "0.15.
|
|
12
|
+
version: "0.15.3",
|
|
13
13
|
instructions: `
|
|
14
14
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
15
15
|
|
package/dist/resources/index.js
CHANGED
|
@@ -151,7 +151,7 @@ Uses HTTP Basic Auth headers (per-request authentication):
|
|
|
151
151
|
- \`SUNSAMA_PASSWORD\`: Sunsama account password
|
|
152
152
|
|
|
153
153
|
### Optional Configuration
|
|
154
|
-
- \`
|
|
154
|
+
- \`TRANSPORT_MODE\`: "stdio" (default) | "http"
|
|
155
155
|
- \`PORT\`: Server port for HTTP transport (default: 3002)
|
|
156
156
|
|
|
157
157
|
## Error Handling
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-filters.d.ts","sourceRoot":"","sources":["../../src/utils/task-filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"task-filters.d.ts","sourceRoot":"","sources":["../../src/utils/task-filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,EAAE,CAoBvF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Task, TaskIntegration } from "sunsama-api";
|
|
1
|
+
import type { Task, TaskIntegration } from "sunsama-api/types";
|
|
2
2
|
/**
|
|
3
3
|
* Trimmed task type containing only essential properties for API responses.
|
|
4
4
|
* Reduces response size by 60-80% while preserving core task information.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAC/B,KAAK,GACL,MAAM,GACN,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,aAAa,GACb,cAAc,GACd,cAAc,GACd,SAAS,GACT,OAAO,GACP,WAAW,CACd,GAAG;IACF,2EAA2E;IAC3E,WAAW,EAAE;QACX,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACpC,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CA4B3D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAEjE"}
|
package/package.json
CHANGED
package/src/auth/http.ts
CHANGED
package/src/auth/stdio.ts
CHANGED
package/src/auth/types.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { apiDocumentationResource } from "./resources/index.js";
|
|
|
10
10
|
(async () => {
|
|
11
11
|
const server = new McpServer({
|
|
12
12
|
name: "Sunsama API Server",
|
|
13
|
-
version: "0.15.
|
|
13
|
+
version: "0.15.3",
|
|
14
14
|
instructions: `
|
|
15
15
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
16
16
|
|
package/src/tools/task-tools.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SunsamaClient } from "sunsama-api";
|
|
1
|
+
import { SunsamaClient } from "sunsama-api/client";
|
|
2
2
|
import { getGlobalSunsamaClient } from "../auth/stdio.js";
|
|
3
3
|
import type { SessionData } from "../auth/types.js";
|
|
4
4
|
import { sessionManager } from "../transports/http.js";
|
package/tsconfig.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-transport.test.d.ts","sourceRoot":"","sources":["../../../__tests__/integration/http-transport.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeAll, afterAll } from "bun:test";
|
|
2
|
-
const SUNSAMA_EMAIL = process.env.SUNSAMA_EMAIL;
|
|
3
|
-
const SUNSAMA_PASSWORD = process.env.SUNSAMA_PASSWORD;
|
|
4
|
-
const TEST_PORT = process.env.TEST_PORT || "3099";
|
|
5
|
-
const BASE_URL = `http://localhost:${TEST_PORT}`;
|
|
6
|
-
const shouldRunIntegrationTests = Boolean(SUNSAMA_EMAIL && SUNSAMA_PASSWORD);
|
|
7
|
-
// Helper to create Basic Auth header
|
|
8
|
-
function createAuthHeader(email, password) {
|
|
9
|
-
return `Basic ${Buffer.from(`${email}:${password}`).toString("base64")}`;
|
|
10
|
-
}
|
|
11
|
-
// Helper to make MCP requests with properly typed responses
|
|
12
|
-
async function mcpRequest(method, params = {}, auth) {
|
|
13
|
-
const headers = {
|
|
14
|
-
"Content-Type": "application/json",
|
|
15
|
-
"Accept": "application/json, text/event-stream",
|
|
16
|
-
};
|
|
17
|
-
if (auth) {
|
|
18
|
-
headers["Authorization"] = auth;
|
|
19
|
-
}
|
|
20
|
-
const response = await fetch(`${BASE_URL}/mcp`, {
|
|
21
|
-
method: "POST",
|
|
22
|
-
headers,
|
|
23
|
-
body: JSON.stringify({
|
|
24
|
-
jsonrpc: "2.0",
|
|
25
|
-
method,
|
|
26
|
-
params,
|
|
27
|
-
id: Math.floor(Math.random() * 10000),
|
|
28
|
-
}),
|
|
29
|
-
});
|
|
30
|
-
return response.json();
|
|
31
|
-
}
|
|
32
|
-
describe.skipIf(!shouldRunIntegrationTests)("HTTP Transport Integration Tests", () => {
|
|
33
|
-
beforeAll(() => {
|
|
34
|
-
console.log("\n🔧 Integration Test Setup");
|
|
35
|
-
console.log("═".repeat(50));
|
|
36
|
-
console.log(`Test server: ${BASE_URL}`);
|
|
37
|
-
console.log(`Using credentials: ${SUNSAMA_EMAIL}`);
|
|
38
|
-
console.log("Note: Server must be running separately on port", TEST_PORT);
|
|
39
|
-
console.log("═".repeat(50) + "\n");
|
|
40
|
-
});
|
|
41
|
-
afterAll(() => {
|
|
42
|
-
console.log("\n✅ Integration tests completed\n");
|
|
43
|
-
});
|
|
44
|
-
describe("Server Health", () => {
|
|
45
|
-
test("should return server info", async () => {
|
|
46
|
-
const response = await fetch(`${BASE_URL}/`);
|
|
47
|
-
const data = await response.json();
|
|
48
|
-
expect(response.status).toBe(200);
|
|
49
|
-
expect(data.name).toBe("mcp-sunsama");
|
|
50
|
-
expect(data.transport).toBe("http");
|
|
51
|
-
expect(data).toHaveProperty("activeSessions");
|
|
52
|
-
expect(data).toHaveProperty("version");
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
describe("Authentication", () => {
|
|
56
|
-
test("should authenticate with valid credentials", async () => {
|
|
57
|
-
const auth = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
58
|
-
const result = await mcpRequest("tools/list", {}, auth);
|
|
59
|
-
expect(result.error).toBeUndefined();
|
|
60
|
-
expect(result.result).toBeDefined();
|
|
61
|
-
expect(result.result.tools).toBeArray();
|
|
62
|
-
expect(result.result.tools.length).toBeGreaterThan(0);
|
|
63
|
-
});
|
|
64
|
-
test("should reject invalid credentials", async () => {
|
|
65
|
-
const auth = createAuthHeader("wrong@example.com", "wrongpassword");
|
|
66
|
-
const result = await mcpRequest("tools/list", {}, auth);
|
|
67
|
-
expect(result.error).toBeDefined();
|
|
68
|
-
expect(result.error.code).toBe(-32000);
|
|
69
|
-
expect(result.error.message).toContain("Authentication failed");
|
|
70
|
-
});
|
|
71
|
-
test("should reject missing authorization", async () => {
|
|
72
|
-
const result = await mcpRequest("tools/list", {});
|
|
73
|
-
expect(result.error).toBeDefined();
|
|
74
|
-
expect(result.error.code).toBe(-32000);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
describe("Session Caching", () => {
|
|
78
|
-
test("should cache authenticated sessions", async () => {
|
|
79
|
-
const auth = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
80
|
-
// First request - creates session
|
|
81
|
-
const result1 = await mcpRequest("tools/call", {
|
|
82
|
-
name: "get-user",
|
|
83
|
-
arguments: {},
|
|
84
|
-
}, auth);
|
|
85
|
-
expect(result1.error).toBeUndefined();
|
|
86
|
-
expect(result1.result).toBeDefined();
|
|
87
|
-
// Second request - should use cached session
|
|
88
|
-
const result2 = await mcpRequest("tools/call", {
|
|
89
|
-
name: "get-user",
|
|
90
|
-
arguments: {},
|
|
91
|
-
}, auth);
|
|
92
|
-
expect(result2.error).toBeUndefined();
|
|
93
|
-
expect(result2.result).toBeDefined();
|
|
94
|
-
// Both should return the same user
|
|
95
|
-
const user1 = JSON.parse(result1.result.content[0].text);
|
|
96
|
-
const user2 = JSON.parse(result2.result.content[0].text);
|
|
97
|
-
expect(user1._id).toBe(user2._id);
|
|
98
|
-
expect(user1.email).toBe(user2.email);
|
|
99
|
-
});
|
|
100
|
-
test("should create separate sessions for different credentials", async () => {
|
|
101
|
-
if (!process.env.SUNSAMA_EMAIL_2 || !process.env.SUNSAMA_PASSWORD_2) {
|
|
102
|
-
console.log("⏭️ Skipping multiple user test (SUNSAMA_EMAIL_2 not set)");
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const auth1 = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
106
|
-
const auth2 = createAuthHeader(process.env.SUNSAMA_EMAIL_2, process.env.SUNSAMA_PASSWORD_2);
|
|
107
|
-
const result1 = await mcpRequest("tools/call", {
|
|
108
|
-
name: "get-user",
|
|
109
|
-
arguments: {},
|
|
110
|
-
}, auth1);
|
|
111
|
-
const result2 = await mcpRequest("tools/call", {
|
|
112
|
-
name: "get-user",
|
|
113
|
-
arguments: {},
|
|
114
|
-
}, auth2);
|
|
115
|
-
expect(result1.error).toBeUndefined();
|
|
116
|
-
expect(result2.error).toBeUndefined();
|
|
117
|
-
const user1 = JSON.parse(result1.result.content[0].text);
|
|
118
|
-
const user2 = JSON.parse(result2.result.content[0].text);
|
|
119
|
-
// Should be different users
|
|
120
|
-
expect(user1.email).not.toBe(user2.email);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
describe("Tool Execution", () => {
|
|
124
|
-
const auth = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
125
|
-
test("should execute get-user tool", async () => {
|
|
126
|
-
const result = await mcpRequest("tools/call", {
|
|
127
|
-
name: "get-user",
|
|
128
|
-
arguments: {},
|
|
129
|
-
}, auth);
|
|
130
|
-
expect(result.error).toBeUndefined();
|
|
131
|
-
expect(result.result.content).toBeArray();
|
|
132
|
-
expect(result.result.content[0].type).toBe("text");
|
|
133
|
-
const user = JSON.parse(result.result.content[0].text);
|
|
134
|
-
expect(user).toHaveProperty("_id");
|
|
135
|
-
expect(user).toHaveProperty("email");
|
|
136
|
-
expect(user).toHaveProperty("profile");
|
|
137
|
-
expect(user.email).toBe(SUNSAMA_EMAIL);
|
|
138
|
-
});
|
|
139
|
-
test("should execute get-streams tool", async () => {
|
|
140
|
-
const result = await mcpRequest("tools/call", {
|
|
141
|
-
name: "get-streams",
|
|
142
|
-
arguments: {},
|
|
143
|
-
}, auth);
|
|
144
|
-
expect(result.error).toBeUndefined();
|
|
145
|
-
expect(result.result.content).toBeArray();
|
|
146
|
-
const response = result.result.content[0].text;
|
|
147
|
-
// Response should be TSV format
|
|
148
|
-
expect(response).toContain("\t"); // TSV uses tabs
|
|
149
|
-
});
|
|
150
|
-
test("should execute get-tasks-backlog tool", async () => {
|
|
151
|
-
const result = await mcpRequest("tools/call", {
|
|
152
|
-
name: "get-tasks-backlog",
|
|
153
|
-
arguments: {},
|
|
154
|
-
}, auth);
|
|
155
|
-
expect(result.error).toBeUndefined();
|
|
156
|
-
expect(result.result.content).toBeArray();
|
|
157
|
-
const response = result.result.content[0].text;
|
|
158
|
-
// Response should be TSV format
|
|
159
|
-
expect(typeof response).toBe("string");
|
|
160
|
-
});
|
|
161
|
-
test("should execute get-tasks-by-day tool", async () => {
|
|
162
|
-
const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
|
|
163
|
-
const result = await mcpRequest("tools/call", {
|
|
164
|
-
name: "get-tasks-by-day",
|
|
165
|
-
arguments: {
|
|
166
|
-
day: today,
|
|
167
|
-
completionFilter: "all",
|
|
168
|
-
},
|
|
169
|
-
}, auth);
|
|
170
|
-
expect(result.error).toBeUndefined();
|
|
171
|
-
expect(result.result.content).toBeArray();
|
|
172
|
-
const response = result.result.content[0].text;
|
|
173
|
-
expect(typeof response).toBe("string");
|
|
174
|
-
});
|
|
175
|
-
test("should handle tool errors gracefully", async () => {
|
|
176
|
-
const result = await mcpRequest("tools/call", {
|
|
177
|
-
name: "get-task-by-id",
|
|
178
|
-
arguments: {
|
|
179
|
-
taskId: "non-existent-task-id-12345",
|
|
180
|
-
},
|
|
181
|
-
}, auth);
|
|
182
|
-
// Should return an error or empty result, not crash
|
|
183
|
-
expect(result).toBeDefined();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
describe("Concurrent Requests", () => {
|
|
187
|
-
test("should handle multiple concurrent requests", async () => {
|
|
188
|
-
const auth = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
189
|
-
// Make 10 concurrent requests
|
|
190
|
-
const promises = Array.from({ length: 10 }, () => mcpRequest("tools/call", {
|
|
191
|
-
name: "get-user",
|
|
192
|
-
arguments: {},
|
|
193
|
-
}, auth));
|
|
194
|
-
const results = await Promise.all(promises);
|
|
195
|
-
// All should succeed
|
|
196
|
-
results.forEach((result) => {
|
|
197
|
-
expect(result.error).toBeUndefined();
|
|
198
|
-
expect(result.result).toBeDefined();
|
|
199
|
-
});
|
|
200
|
-
// All should return the same user
|
|
201
|
-
const users = results.map((r) => JSON.parse(r.result.content[0].text));
|
|
202
|
-
const firstUserId = users[0]._id;
|
|
203
|
-
users.forEach((user) => {
|
|
204
|
-
expect(user._id).toBe(firstUserId);
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
test("should handle concurrent requests with different credentials", async () => {
|
|
208
|
-
if (!process.env.SUNSAMA_EMAIL_2 || !process.env.SUNSAMA_PASSWORD_2) {
|
|
209
|
-
console.log("⏭️ Skipping concurrent multi-user test");
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const auth1 = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
213
|
-
const auth2 = createAuthHeader(process.env.SUNSAMA_EMAIL_2, process.env.SUNSAMA_PASSWORD_2);
|
|
214
|
-
// 5 requests for each user, interleaved
|
|
215
|
-
const promises = Array.from({ length: 10 }, (_, i) => mcpRequest("tools/call", {
|
|
216
|
-
name: "get-user",
|
|
217
|
-
arguments: {},
|
|
218
|
-
}, i % 2 === 0 ? auth1 : auth2));
|
|
219
|
-
const results = await Promise.all(promises);
|
|
220
|
-
// All should succeed
|
|
221
|
-
results.forEach((result) => {
|
|
222
|
-
expect(result.error).toBeUndefined();
|
|
223
|
-
});
|
|
224
|
-
// Check that we got two different users
|
|
225
|
-
const users = results.map((r) => JSON.parse(r.result.content[0].text));
|
|
226
|
-
const uniqueEmails = new Set(users.map((u) => u.email));
|
|
227
|
-
expect(uniqueEmails.size).toBe(2);
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
describe("Error Recovery", () => {
|
|
231
|
-
test("should recover from transient failures", async () => {
|
|
232
|
-
const auth = createAuthHeader(SUNSAMA_EMAIL, SUNSAMA_PASSWORD);
|
|
233
|
-
// Make a valid request
|
|
234
|
-
const result1 = await mcpRequest("tools/call", {
|
|
235
|
-
name: "get-user",
|
|
236
|
-
arguments: {},
|
|
237
|
-
}, auth);
|
|
238
|
-
expect(result1.error).toBeUndefined();
|
|
239
|
-
// Make an invalid request
|
|
240
|
-
const result2 = await mcpRequest("tools/call", {
|
|
241
|
-
name: "invalid-tool-name",
|
|
242
|
-
arguments: {},
|
|
243
|
-
}, auth);
|
|
244
|
-
expect(result2.error).toBeDefined();
|
|
245
|
-
// Make another valid request - should still work
|
|
246
|
-
const result3 = await mcpRequest("tools/call", {
|
|
247
|
-
name: "get-user",
|
|
248
|
-
arguments: {},
|
|
249
|
-
}, auth);
|
|
250
|
-
expect(result3.error).toBeUndefined();
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
// Print helpful message if tests are skipped
|
|
255
|
-
if (!shouldRunIntegrationTests) {
|
|
256
|
-
console.log("\n" + "⏭️".repeat(25));
|
|
257
|
-
console.log("⏭️ Integration tests SKIPPED");
|
|
258
|
-
console.log("⏭️");
|
|
259
|
-
console.log("⏭️ To run integration tests:");
|
|
260
|
-
console.log("⏭️ 1. Set SUNSAMA_EMAIL and SUNSAMA_PASSWORD in .env");
|
|
261
|
-
console.log("⏭️ 2. Start server: TRANSPORT_MODE=http PORT=3099 bun dev");
|
|
262
|
-
console.log("⏭️ 3. Run tests: bun test:integration");
|
|
263
|
-
console.log("⏭️");
|
|
264
|
-
console.log("⏭️".repeat(25) + "\n");
|
|
265
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.test.d.ts","sourceRoot":"","sources":["../../../../__tests__/unit/auth/http.test.ts"],"names":[],"mappings":""}
|