mcp-sunsama 0.2.0

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.
Files changed (53) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.claude/settings.local.json +29 -0
  4. package/.env.example +10 -0
  5. package/CHANGELOG.md +29 -0
  6. package/CLAUDE.md +137 -0
  7. package/LICENSE +21 -0
  8. package/README.md +143 -0
  9. package/TODO_PREPUBLISH.md +182 -0
  10. package/bun.lock +515 -0
  11. package/dist/auth/http.d.ts +20 -0
  12. package/dist/auth/http.d.ts.map +1 -0
  13. package/dist/auth/http.js +52 -0
  14. package/dist/auth/stdio.d.ts +13 -0
  15. package/dist/auth/stdio.d.ts.map +1 -0
  16. package/dist/auth/stdio.js +27 -0
  17. package/dist/auth/types.d.ts +9 -0
  18. package/dist/auth/types.d.ts.map +1 -0
  19. package/dist/auth/types.js +1 -0
  20. package/dist/config/transport.d.ts +32 -0
  21. package/dist/config/transport.d.ts.map +1 -0
  22. package/dist/config/transport.js +62 -0
  23. package/dist/main.d.ts +2 -0
  24. package/dist/main.d.ts.map +1 -0
  25. package/dist/main.js +473 -0
  26. package/dist/schemas.d.ts +522 -0
  27. package/dist/schemas.d.ts.map +1 -0
  28. package/dist/schemas.js +124 -0
  29. package/dist/utils/client-resolver.d.ts +10 -0
  30. package/dist/utils/client-resolver.d.ts.map +1 -0
  31. package/dist/utils/client-resolver.js +19 -0
  32. package/dist/utils/task-filters.d.ts +29 -0
  33. package/dist/utils/task-filters.d.ts.map +1 -0
  34. package/dist/utils/task-filters.js +42 -0
  35. package/dist/utils/task-trimmer.d.ts +47 -0
  36. package/dist/utils/task-trimmer.d.ts.map +1 -0
  37. package/dist/utils/task-trimmer.js +50 -0
  38. package/dist/utils/to-tsv.d.ts +8 -0
  39. package/dist/utils/to-tsv.d.ts.map +1 -0
  40. package/dist/utils/to-tsv.js +64 -0
  41. package/mcp-inspector.json +14 -0
  42. package/package.json +56 -0
  43. package/src/auth/http.ts +61 -0
  44. package/src/auth/stdio.ts +33 -0
  45. package/src/auth/types.ts +9 -0
  46. package/src/config/transport.ts +80 -0
  47. package/src/main.ts +542 -0
  48. package/src/schemas.ts +169 -0
  49. package/src/utils/client-resolver.ts +23 -0
  50. package/src/utils/task-filters.ts +49 -0
  51. package/src/utils/task-trimmer.ts +81 -0
  52. package/src/utils/to-tsv.ts +73 -0
  53. package/tsconfig.json +36 -0
@@ -0,0 +1,52 @@
1
+ import { IncomingMessage } from "http";
2
+ import { SunsamaClient } from "sunsama-api";
3
+ /**
4
+ * Parse HTTP Basic Auth credentials from Authorization header
5
+ * @param authHeader - The Authorization header value
6
+ * @returns Object containing email and password
7
+ * @throws {Error} If the header format is invalid
8
+ */
9
+ export function parseBasicAuth(authHeader) {
10
+ const base64Credentials = authHeader.replace('Basic ', '');
11
+ const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
12
+ const [email, password] = credentials.split(':');
13
+ if (!email || !password) {
14
+ throw new Error("Invalid Basic Auth format");
15
+ }
16
+ return { email, password };
17
+ }
18
+ /**
19
+ * HTTP Basic Auth authenticator for httpStream transport
20
+ * @param request - The incoming request object
21
+ * @returns SessionData with authenticated SunsamaClient
22
+ * @throws {Response} HTTP 401 response for authentication failures
23
+ */
24
+ export async function httpStreamAuthenticator(request) {
25
+ const authHeader = request.headers["authorization"];
26
+ if (!authHeader || Array.isArray(authHeader) || !authHeader.startsWith('Basic ')) {
27
+ throw new Response(null, {
28
+ status: 401,
29
+ statusText: "Unauthorized: Basic Auth required",
30
+ headers: { 'WWW-Authenticate': 'Basic realm="Sunsama MCP"' }
31
+ });
32
+ }
33
+ try {
34
+ // Parse Basic Auth credentials
35
+ const { email, password } = parseBasicAuth(authHeader);
36
+ // Create and authenticate SunsamaClient
37
+ const sunsamaClient = new SunsamaClient();
38
+ await sunsamaClient.login(email, password);
39
+ console.log(`HTTP session authenticated for user: ${email}`);
40
+ return {
41
+ sunsamaClient,
42
+ email
43
+ };
44
+ }
45
+ catch (error) {
46
+ console.log("Authentication failed:", error instanceof Error ? error.message : 'Unknown error');
47
+ throw new Response(null, {
48
+ status: 401,
49
+ statusText: "Unauthorized: Invalid Sunsama credentials"
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,13 @@
1
+ import { SunsamaClient } from "sunsama-api";
2
+ /**
3
+ * Initialize stdio authentication using environment variables
4
+ * @throws {Error} If credentials are missing or authentication fails
5
+ */
6
+ export declare function initializeStdioAuth(): Promise<void>;
7
+ /**
8
+ * Get the global Sunsama client instance for stdio transport
9
+ * @returns {SunsamaClient} The authenticated global client
10
+ * @throws {Error} If global client is not initialized
11
+ */
12
+ export declare function getGlobalSunsamaClient(): SunsamaClient;
13
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CASzD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,aAAa,CAKtD"}
@@ -0,0 +1,27 @@
1
+ import { SunsamaClient } from "sunsama-api";
2
+ /**
3
+ * Global Sunsama client instance for stdio transport
4
+ */
5
+ let globalSunsamaClient = null;
6
+ /**
7
+ * Initialize stdio authentication using environment variables
8
+ * @throws {Error} If credentials are missing or authentication fails
9
+ */
10
+ export async function initializeStdioAuth() {
11
+ if (!process.env.SUNSAMA_EMAIL || !process.env.SUNSAMA_PASSWORD) {
12
+ throw new Error("Sunsama credentials not configured. Please set SUNSAMA_EMAIL and SUNSAMA_PASSWORD environment variables.");
13
+ }
14
+ globalSunsamaClient = new SunsamaClient();
15
+ await globalSunsamaClient.login(process.env.SUNSAMA_EMAIL, process.env.SUNSAMA_PASSWORD);
16
+ }
17
+ /**
18
+ * Get the global Sunsama client instance for stdio transport
19
+ * @returns {SunsamaClient} The authenticated global client
20
+ * @throws {Error} If global client is not initialized
21
+ */
22
+ export function getGlobalSunsamaClient() {
23
+ if (!globalSunsamaClient) {
24
+ throw new Error("Global Sunsama client not initialized.");
25
+ }
26
+ return globalSunsamaClient;
27
+ }
@@ -0,0 +1,9 @@
1
+ import { SunsamaClient } from "sunsama-api";
2
+ /**
3
+ * Session data interface for HTTP transport
4
+ */
5
+ export interface SessionData extends Record<string, unknown> {
6
+ sunsamaClient: SunsamaClient;
7
+ email: string;
8
+ }
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1 @@
1
+ import { SunsamaClient } from "sunsama-api";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Transport configuration for the Sunsama MCP Server
3
+ * Supports both stdio and httpStream transports based on environment variables
4
+ */
5
+ export type TransportType = "stdio" | "httpStream";
6
+ export interface TransportConfig {
7
+ transportType: TransportType;
8
+ httpStream?: {
9
+ port: number;
10
+ endpoint: string;
11
+ };
12
+ }
13
+ /**
14
+ * Gets the transport configuration based on environment variables
15
+ *
16
+ * Environment Variables:
17
+ * - TRANSPORT_TYPE: "stdio" | "httpStream" (default: "stdio")
18
+ * - PORT: HTTP server port (default: 3000, only for httpStream)
19
+ * - HTTP_ENDPOINT: HTTP endpoint path (default: "/mcp", only for httpStream)
20
+ *
21
+ * @throws {z.ZodError} When environment variables are invalid
22
+ */
23
+ export declare function getTransportConfig(): TransportConfig;
24
+ /**
25
+ * Returns true if the current transport configuration is for HTTP streaming
26
+ */
27
+ export declare function isHttpStreamTransport(): boolean;
28
+ /**
29
+ * Returns true if the current transport configuration is for stdio
30
+ */
31
+ export declare function isStdioTransport(): boolean;
32
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/config/transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,YAAY,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAcD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CA0BpD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Transport configuration for the Sunsama MCP Server
3
+ * Supports both stdio and httpStream transports based on environment variables
4
+ */
5
+ import { z } from "zod";
6
+ /**
7
+ * Zod schema for validating transport-related environment variables
8
+ */
9
+ const TransportEnvSchema = z.object({
10
+ TRANSPORT_TYPE: z.enum(["stdio", "httpStream"]).default("stdio"),
11
+ PORT: z.string()
12
+ .transform(val => parseInt(val, 10))
13
+ .pipe(z.number().min(1).max(65535))
14
+ .optional(),
15
+ HTTP_ENDPOINT: z.string().default("/mcp")
16
+ });
17
+ /**
18
+ * Gets the transport configuration based on environment variables
19
+ *
20
+ * Environment Variables:
21
+ * - TRANSPORT_TYPE: "stdio" | "httpStream" (default: "stdio")
22
+ * - PORT: HTTP server port (default: 3000, only for httpStream)
23
+ * - HTTP_ENDPOINT: HTTP endpoint path (default: "/mcp", only for httpStream)
24
+ *
25
+ * @throws {z.ZodError} When environment variables are invalid
26
+ */
27
+ export function getTransportConfig() {
28
+ try {
29
+ const env = TransportEnvSchema.parse(process.env);
30
+ if (env.TRANSPORT_TYPE === "httpStream") {
31
+ return {
32
+ transportType: "httpStream",
33
+ httpStream: {
34
+ port: env.PORT || 3000,
35
+ endpoint: env.HTTP_ENDPOINT
36
+ }
37
+ };
38
+ }
39
+ return {
40
+ transportType: "stdio"
41
+ };
42
+ }
43
+ catch (error) {
44
+ if (error instanceof z.ZodError) {
45
+ const issues = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`).join(', ');
46
+ throw new Error(`Invalid transport configuration: ${issues}`);
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+ /**
52
+ * Returns true if the current transport configuration is for HTTP streaming
53
+ */
54
+ export function isHttpStreamTransport() {
55
+ return getTransportConfig().transportType === "httpStream";
56
+ }
57
+ /**
58
+ * Returns true if the current transport configuration is for stdio
59
+ */
60
+ export function isStdioTransport() {
61
+ return getTransportConfig().transportType === "stdio";
62
+ }
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}