acuity-mcp-server 1.0.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 (99) hide show
  1. package/README.md +541 -0
  2. package/dist/auth/device-flow.d.ts +46 -0
  3. package/dist/auth/device-flow.d.ts.map +1 -0
  4. package/dist/auth/device-flow.js +141 -0
  5. package/dist/auth/device-flow.js.map +1 -0
  6. package/dist/auth/http-auth.d.ts +25 -0
  7. package/dist/auth/http-auth.d.ts.map +1 -0
  8. package/dist/auth/http-auth.js +101 -0
  9. package/dist/auth/http-auth.js.map +1 -0
  10. package/dist/auth/jwt-validator.d.ts +20 -0
  11. package/dist/auth/jwt-validator.d.ts.map +1 -0
  12. package/dist/auth/jwt-validator.js +83 -0
  13. package/dist/auth/jwt-validator.js.map +1 -0
  14. package/dist/auth/token-storage.d.ts +88 -0
  15. package/dist/auth/token-storage.d.ts.map +1 -0
  16. package/dist/auth/token-storage.js +273 -0
  17. package/dist/auth/token-storage.js.map +1 -0
  18. package/dist/clients/hasura-client.d.ts +33 -0
  19. package/dist/clients/hasura-client.d.ts.map +1 -0
  20. package/dist/clients/hasura-client.js +79 -0
  21. package/dist/clients/hasura-client.js.map +1 -0
  22. package/dist/config/environments.d.ts +51 -0
  23. package/dist/config/environments.d.ts.map +1 -0
  24. package/dist/config/environments.js +183 -0
  25. package/dist/config/environments.js.map +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +593 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/server/http-server.d.ts +14 -0
  31. package/dist/server/http-server.d.ts.map +1 -0
  32. package/dist/server/http-server.js +167 -0
  33. package/dist/server/http-server.js.map +1 -0
  34. package/dist/server/mcp-core.d.ts +12 -0
  35. package/dist/server/mcp-core.d.ts.map +1 -0
  36. package/dist/server/mcp-core.js +200 -0
  37. package/dist/server/mcp-core.js.map +1 -0
  38. package/dist/tools/acuity-init.d.ts +84 -0
  39. package/dist/tools/acuity-init.d.ts.map +1 -0
  40. package/dist/tools/acuity-init.js +239 -0
  41. package/dist/tools/acuity-init.js.map +1 -0
  42. package/dist/tools/get-dashboard-summary.d.ts +96 -0
  43. package/dist/tools/get-dashboard-summary.d.ts.map +1 -0
  44. package/dist/tools/get-dashboard-summary.js +264 -0
  45. package/dist/tools/get-dashboard-summary.js.map +1 -0
  46. package/dist/tools/get-issue.d.ts +62 -0
  47. package/dist/tools/get-issue.d.ts.map +1 -0
  48. package/dist/tools/get-issue.js +150 -0
  49. package/dist/tools/get-issue.js.map +1 -0
  50. package/dist/tools/get-lesson-learned.d.ts +53 -0
  51. package/dist/tools/get-lesson-learned.d.ts.map +1 -0
  52. package/dist/tools/get-lesson-learned.js +117 -0
  53. package/dist/tools/get-lesson-learned.js.map +1 -0
  54. package/dist/tools/get-lookup-values.d.ts +41 -0
  55. package/dist/tools/get-lookup-values.d.ts.map +1 -0
  56. package/dist/tools/get-lookup-values.js +127 -0
  57. package/dist/tools/get-lookup-values.js.map +1 -0
  58. package/dist/tools/get-project.d.ts +131 -0
  59. package/dist/tools/get-project.d.ts.map +1 -0
  60. package/dist/tools/get-project.js +340 -0
  61. package/dist/tools/get-project.js.map +1 -0
  62. package/dist/tools/get-risk.d.ts +65 -0
  63. package/dist/tools/get-risk.d.ts.map +1 -0
  64. package/dist/tools/get-risk.js +173 -0
  65. package/dist/tools/get-risk.js.map +1 -0
  66. package/dist/tools/get-status-reports.d.ts +46 -0
  67. package/dist/tools/get-status-reports.d.ts.map +1 -0
  68. package/dist/tools/get-status-reports.js +151 -0
  69. package/dist/tools/get-status-reports.js.map +1 -0
  70. package/dist/tools/init-auth.d.ts +47 -0
  71. package/dist/tools/init-auth.d.ts.map +1 -0
  72. package/dist/tools/init-auth.js +213 -0
  73. package/dist/tools/init-auth.js.map +1 -0
  74. package/dist/tools/list-issues.d.ts +134 -0
  75. package/dist/tools/list-issues.d.ts.map +1 -0
  76. package/dist/tools/list-issues.js +285 -0
  77. package/dist/tools/list-issues.js.map +1 -0
  78. package/dist/tools/list-lessons-learned.d.ts +79 -0
  79. package/dist/tools/list-lessons-learned.d.ts.map +1 -0
  80. package/dist/tools/list-lessons-learned.js +155 -0
  81. package/dist/tools/list-lessons-learned.js.map +1 -0
  82. package/dist/tools/list-projects.d.ts +200 -0
  83. package/dist/tools/list-projects.d.ts.map +1 -0
  84. package/dist/tools/list-projects.js +396 -0
  85. package/dist/tools/list-projects.js.map +1 -0
  86. package/dist/tools/list-risks.d.ts +166 -0
  87. package/dist/tools/list-risks.d.ts.map +1 -0
  88. package/dist/tools/list-risks.js +356 -0
  89. package/dist/tools/list-risks.js.map +1 -0
  90. package/dist/tools/search-projects.d.ts +90 -0
  91. package/dist/tools/search-projects.d.ts.map +1 -0
  92. package/dist/tools/search-projects.js +191 -0
  93. package/dist/tools/search-projects.js.map +1 -0
  94. package/dist/utils/formatters.d.ts +12 -0
  95. package/dist/utils/formatters.d.ts.map +1 -0
  96. package/dist/utils/formatters.js +28 -0
  97. package/dist/utils/formatters.js.map +1 -0
  98. package/openapi.yaml +194 -0
  99. package/package.json +68 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * MCP Tool: get_risk
3
+ * Returns full details for a single risk by ID
4
+ *
5
+ * Features:
6
+ * - Enum conversion: DB integers → human-readable strings
7
+ * - Hasura relationships: returns resolved names instead of IDs
8
+ */
9
+ // ============================================================================
10
+ // Enum Mappings
11
+ // ============================================================================
12
+ const DB_TO_STATUS = {
13
+ 0: 'open',
14
+ 1: 'closed',
15
+ 2: 'realized'
16
+ };
17
+ const DB_TO_PRIORITY = {
18
+ 0: 'very_low',
19
+ 1: 'low',
20
+ 2: 'medium',
21
+ 3: 'high',
22
+ 4: 'critical'
23
+ };
24
+ const DB_TO_RISK_RESPONSE = {
25
+ 0: 'mitigate',
26
+ 1: 'accept',
27
+ 2: 'avoid',
28
+ 3: 'watch',
29
+ 4: 'transfer'
30
+ };
31
+ const DB_TO_SEVERITY = {
32
+ 0: 'very_low',
33
+ 1: 'low',
34
+ 2: 'medium',
35
+ 3: 'high',
36
+ 4: 'very_high'
37
+ };
38
+ const DB_TO_LIKELIHOOD = {
39
+ 0: 'very_low',
40
+ 1: 'low',
41
+ 2: 'medium',
42
+ 3: 'high',
43
+ 4: 'very_high'
44
+ };
45
+ // ============================================================================
46
+ // Helper Functions
47
+ // ============================================================================
48
+ function fromDbValue(value, mapping) {
49
+ if (value === null || value === undefined)
50
+ return null;
51
+ return mapping[value] ?? null;
52
+ }
53
+ function transformRisk(raw) {
54
+ return {
55
+ id: raw.id,
56
+ risk_id: raw.risk_id,
57
+ name: raw.name,
58
+ description: raw.description,
59
+ notes: raw.notes,
60
+ hyperlinks: raw.hyperlinks,
61
+ status: fromDbValue(raw.status, DB_TO_STATUS) ?? 'open',
62
+ priority: fromDbValue(raw.priority, DB_TO_PRIORITY) ?? 'low',
63
+ severity: fromDbValue(raw.severity, DB_TO_SEVERITY) ?? 'very_low',
64
+ likelihood: fromDbValue(raw.likelihood, DB_TO_LIKELIHOOD) ?? 'very_low',
65
+ risk_response: fromDbValue(raw.risk_response, DB_TO_RISK_RESPONSE) ?? 'mitigate',
66
+ impact_score: raw.impact_score ?? 0,
67
+ response_plan: raw.response_plan,
68
+ created_at: raw.created_at,
69
+ updated_at: raw.updated_at,
70
+ project: raw.project,
71
+ owner: raw.company_project_resource
72
+ };
73
+ }
74
+ // ============================================================================
75
+ // GraphQL Query
76
+ // ============================================================================
77
+ const GET_RISK_QUERY = `
78
+ query GetRisk($where: risks_bool_exp!) {
79
+ risks(where: $where, limit: 1) {
80
+ id
81
+ risk_id
82
+ name
83
+ description
84
+ notes
85
+ hyperlinks
86
+ status
87
+ priority
88
+ severity
89
+ likelihood
90
+ risk_response
91
+ impact_score
92
+ response_plan
93
+ created_at
94
+ updated_at
95
+
96
+ project { id name }
97
+ company_project_resource { id name }
98
+ }
99
+ }
100
+ `;
101
+ // ============================================================================
102
+ // Main Handler
103
+ // ============================================================================
104
+ export async function getRisk(input, hasuraClient) {
105
+ const { risk_id, risk_number } = input;
106
+ // Validate input
107
+ if (risk_id === undefined && risk_number === undefined) {
108
+ return { risk: null };
109
+ }
110
+ // Build where clause
111
+ let whereClause;
112
+ if (risk_id !== undefined) {
113
+ whereClause = { id: { _eq: risk_id } };
114
+ }
115
+ else {
116
+ whereClause = { risk_id: { _eq: risk_number } };
117
+ }
118
+ const result = await hasuraClient.query(GET_RISK_QUERY, {
119
+ where: whereClause
120
+ });
121
+ if (!result.risks || result.risks.length === 0) {
122
+ return { risk: null };
123
+ }
124
+ return {
125
+ risk: transformRisk(result.risks[0])
126
+ };
127
+ }
128
+ // ============================================================================
129
+ // Tool Definition
130
+ // ============================================================================
131
+ export const getRiskTool = {
132
+ name: 'get_risk',
133
+ description: `
134
+ Get full details for a single risk by ID.
135
+
136
+ Returns all risk information including:
137
+ - Identifiers: id (database), risk_id (human-readable number within company)
138
+ - Content: name, description, notes, hyperlinks, response_plan
139
+ - Classification: status, priority, severity, likelihood, risk_response
140
+ - Scoring: impact_score (severity × likelihood, range 1-25)
141
+ - Dates: created_at, updated_at
142
+ - Relationships: project { id, name }, owner { id, name }
143
+
144
+ SEARCH OPTIONS (provide one):
145
+ - risk_id: Database primary key (integer)
146
+ - risk_number: Human-readable risk number within company (e.g., 42)
147
+
148
+ ENUM VALUES:
149
+ - status: "open", "closed", "realized"
150
+ - priority: "very_low", "low", "medium", "high", "critical"
151
+ - severity: "very_low", "low", "medium", "high", "very_high"
152
+ - likelihood: "very_low", "low", "medium", "high", "very_high"
153
+ - risk_response: "mitigate", "accept", "avoid", "watch", "transfer"
154
+
155
+ EXAMPLES:
156
+ - Get by database ID: risk_id: 123
157
+ - Get by risk number: risk_number: 42
158
+ `.trim(),
159
+ inputSchema: {
160
+ type: 'object',
161
+ properties: {
162
+ risk_id: {
163
+ type: 'number',
164
+ description: 'Risk database ID (primary key)'
165
+ },
166
+ risk_number: {
167
+ type: 'number',
168
+ description: 'Human-readable risk number within company'
169
+ }
170
+ }
171
+ }
172
+ };
173
+ //# sourceMappingURL=get-risk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-risk.js","sourceRoot":"","sources":["../../src/tools/get-risk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * MCP Tool: get_status_reports
3
+ * Get status reports with optional filtering by project
4
+ */
5
+ import type { HasuraClient } from '../clients/hasura-client.js';
6
+ export interface GetStatusReportsInput {
7
+ project_id?: number;
8
+ project_name?: string;
9
+ limit?: number;
10
+ offset?: number;
11
+ }
12
+ /**
13
+ * Get status reports handler
14
+ */
15
+ export declare function getStatusReports(input: GetStatusReportsInput, hasuraClient: HasuraClient): Promise<string>;
16
+ /**
17
+ * MCP tool definition for get_status_reports
18
+ */
19
+ export declare const getStatusReportsTool: {
20
+ name: string;
21
+ description: string;
22
+ inputSchema: {
23
+ type: string;
24
+ properties: {
25
+ project_id: {
26
+ type: string;
27
+ description: string;
28
+ };
29
+ project_name: {
30
+ type: string;
31
+ description: string;
32
+ };
33
+ limit: {
34
+ type: string;
35
+ description: string;
36
+ default: number;
37
+ };
38
+ offset: {
39
+ type: string;
40
+ description: string;
41
+ default: number;
42
+ };
43
+ };
44
+ };
45
+ };
46
+ //# sourceMappingURL=get-status-reports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-status-reports.d.ts","sourceRoot":"","sources":["../../src/tools/get-status-reports.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsGD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,EAC5B,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDhC,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * MCP Tool: get_status_reports
3
+ * Get status reports with optional filtering by project
4
+ */
5
+ import { formatDate, divider } from '../utils/formatters.js';
6
+ /**
7
+ * Build GraphQL query for status reports
8
+ */
9
+ function buildStatusReportsQuery(projectId, projectName) {
10
+ let whereConditions = '';
11
+ if (projectId) {
12
+ whereConditions = `where: { project_id: { _eq: ${projectId} } }`;
13
+ }
14
+ else if (projectName) {
15
+ // Case-insensitive search by project name
16
+ whereConditions = `where: { project: { name: { _ilike: "%${projectName}%" } } }`;
17
+ }
18
+ return `
19
+ query GetStatusReports($limit: Int!, $offset: Int!) {
20
+ status_reports(
21
+ ${whereConditions}
22
+ order_by: { created_at: desc }
23
+ limit: $limit
24
+ offset: $offset
25
+ ) {
26
+ id
27
+ summary
28
+ accomplishments
29
+ look_ahead
30
+ help_needed
31
+ created_at
32
+ updated_at
33
+ project {
34
+ id
35
+ name
36
+ }
37
+ user {
38
+ name
39
+ email
40
+ }
41
+ }
42
+
43
+ status_reports_aggregate(
44
+ ${whereConditions}
45
+ ) {
46
+ aggregate {
47
+ count
48
+ }
49
+ }
50
+ }
51
+ `;
52
+ }
53
+ /**
54
+ * Format status reports for display
55
+ */
56
+ function formatStatusReports(reports, totalCount, hasMore) {
57
+ if (reports.length === 0) {
58
+ return 'No status reports found.';
59
+ }
60
+ const header = `Found ${totalCount} status report${totalCount !== 1 ? 's' : ''} total. Showing ${reports.length}.`;
61
+ const formatted = reports.map((report, idx) => {
62
+ return `
63
+ ${divider()}
64
+ STATUS REPORT #${idx + 1} (ID: ${report.id})
65
+ ${divider()}
66
+
67
+ Project: ${report.project.name} (ID: ${report.project.id})
68
+ Reported by: ${report.user?.name || 'Unknown'} ${report.user?.email ? `(${report.user.email})` : ''}
69
+ Date: ${formatDate(report.created_at)}
70
+ Last Updated: ${formatDate(report.updated_at)}
71
+
72
+ SUMMARY:
73
+ ${report.summary || 'No summary provided'}
74
+
75
+ ${report.accomplishments ? `ACCOMPLISHMENTS:\n${report.accomplishments}\n` : ''}
76
+ ${report.look_ahead ? `LOOKING AHEAD:\n${report.look_ahead}\n` : ''}
77
+ ${report.help_needed ? `HELP NEEDED:\n${report.help_needed}\n` : ''}
78
+ `.trim();
79
+ }).join('\n\n');
80
+ return `${header}\n\n${formatted}${hasMore ? '\n\n...(more reports available, use offset to see next page)' : ''}`;
81
+ }
82
+ /**
83
+ * Get status reports handler
84
+ */
85
+ export async function getStatusReports(input, hasuraClient) {
86
+ const { project_id, project_name, limit = 10, offset = 0 } = input;
87
+ // Build and execute GraphQL query
88
+ const query = buildStatusReportsQuery(project_id, project_name);
89
+ const result = await hasuraClient.query(query, {
90
+ limit,
91
+ offset
92
+ });
93
+ const totalCount = result.status_reports_aggregate.aggregate.count;
94
+ const hasMore = offset + result.status_reports.length < totalCount;
95
+ return formatStatusReports(result.status_reports, totalCount, hasMore);
96
+ }
97
+ /**
98
+ * MCP tool definition for get_status_reports
99
+ */
100
+ export const getStatusReportsTool = {
101
+ name: 'get_status_reports',
102
+ description: `
103
+ Get status reports with optional filtering by project ID or project name.
104
+
105
+ Returns detailed status report information:
106
+ - Summary of the report
107
+ - Accomplishments
108
+ - Looking ahead
109
+ - Help needed
110
+ - Project information (ID and name)
111
+ - Reporter information (name and email)
112
+ - Dates (created and updated)
113
+
114
+ Use this tool when users ask:
115
+ - "Show me all status reports"
116
+ - "Get status reports for project #123"
117
+ - "Show me status reports for project Auto Scrap"
118
+ - "What are the latest status updates?"
119
+ - "Show me recent status reports for [project name]"
120
+
121
+ You can filter by:
122
+ - project_id: Exact project ID (e.g., 123)
123
+ - project_name: Project name (case-insensitive, partial match, e.g., "Auto Scrap")
124
+
125
+ If no filters provided, returns all accessible status reports.
126
+ `.trim(),
127
+ inputSchema: {
128
+ type: 'object',
129
+ properties: {
130
+ project_id: {
131
+ type: 'number',
132
+ description: 'Filter by specific project ID'
133
+ },
134
+ project_name: {
135
+ type: 'string',
136
+ description: 'Filter by project name (case-insensitive, partial match)'
137
+ },
138
+ limit: {
139
+ type: 'number',
140
+ description: 'Maximum number of reports to return (default: 10)',
141
+ default: 10
142
+ },
143
+ offset: {
144
+ type: 'number',
145
+ description: 'Number of reports to skip for pagination (default: 0)',
146
+ default: 0
147
+ }
148
+ }
149
+ }
150
+ };
151
+ //# sourceMappingURL=get-status-reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-status-reports.js","sourceRoot":"","sources":["../../src/tools/get-status-reports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Authentication initialization tool
3
+ * Allows users to authenticate via Claude by triggering Device Flow
4
+ */
5
+ export declare const initAuthTool: {
6
+ name: string;
7
+ description: string;
8
+ inputSchema: {
9
+ type: string;
10
+ properties: {};
11
+ required: never[];
12
+ };
13
+ };
14
+ export declare const logoutTool: {
15
+ name: string;
16
+ description: string;
17
+ inputSchema: {
18
+ type: string;
19
+ properties: {};
20
+ required: never[];
21
+ };
22
+ };
23
+ export declare const authStatusTool: {
24
+ name: string;
25
+ description: string;
26
+ inputSchema: {
27
+ type: string;
28
+ properties: {};
29
+ required: never[];
30
+ };
31
+ };
32
+ /**
33
+ * Login - Two-phase Device Flow
34
+ *
35
+ * Phase 1: Request device code, show to user, open browser
36
+ * Phase 2: Poll for token completion when user calls again
37
+ */
38
+ export declare function initAuth(): Promise<string>;
39
+ /**
40
+ * Handle logout - clears credentials and pending auth
41
+ */
42
+ export declare function logout(): Promise<string>;
43
+ /**
44
+ * Check auth status
45
+ */
46
+ export declare function getAuthStatus(): Promise<string>;
47
+ //# sourceMappingURL=init-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-auth.d.ts","sourceRoot":"","sources":["../../src/tools/init-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,eAAO,MAAM,YAAY;;;;;;;;CAQxB,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;CAQtB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;CAQ1B,CAAC;AAYF;;;;;GAKG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CA2DhD;AA2ED;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAS9C;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAuCrD"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Authentication initialization tool
3
+ * Allows users to authenticate via Claude by triggering Device Flow
4
+ */
5
+ import open from 'open';
6
+ import { requestDeviceCode, pollForToken } from '../auth/device-flow.js';
7
+ import { saveCredentials, loadCredentials, clearCredentials, tokenResponseToCredentials, savePendingDeviceCode, loadPendingDeviceCode, clearPendingDeviceCode, } from '../auth/token-storage.js';
8
+ import { getEnvironment } from '../config/environments.js';
9
+ export const initAuthTool = {
10
+ name: 'acuity_login',
11
+ description: 'Login to Acuity. Opens a browser for secure login. Wait for the login to complete.',
12
+ inputSchema: {
13
+ type: 'object',
14
+ properties: {},
15
+ required: []
16
+ }
17
+ };
18
+ export const logoutTool = {
19
+ name: 'acuity_logout',
20
+ description: 'Logout from Acuity and clear stored credentials.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {},
24
+ required: []
25
+ }
26
+ };
27
+ export const authStatusTool = {
28
+ name: 'acuity_auth_status',
29
+ description: 'Check current Acuity authentication status.',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {},
33
+ required: []
34
+ }
35
+ };
36
+ function getAuth0Config() {
37
+ const env = getEnvironment();
38
+ return {
39
+ domain: env.auth0Domain,
40
+ clientId: env.auth0ClientId,
41
+ audience: process.env.AUTH0_AUDIENCE,
42
+ scope: 'openid profile email offline_access',
43
+ };
44
+ }
45
+ /**
46
+ * Login - Two-phase Device Flow
47
+ *
48
+ * Phase 1: Request device code, show to user, open browser
49
+ * Phase 2: Poll for token completion when user calls again
50
+ */
51
+ export async function initAuth() {
52
+ try {
53
+ // Check if already authenticated
54
+ const existingCreds = await loadCredentials();
55
+ if (existingCreds) {
56
+ const now = Math.floor(Date.now() / 1000);
57
+ if (existingCreds.expiresAt > now) {
58
+ return `Already authenticated as ${existingCreds.email || 'unknown user'}. Use acuity_logout first if you want to re-authenticate.`;
59
+ }
60
+ }
61
+ const config = getAuth0Config();
62
+ // Check if there's a pending device code (Phase 2)
63
+ const pending = await loadPendingDeviceCode();
64
+ if (pending) {
65
+ return await completePendingAuth(config, pending);
66
+ }
67
+ // Phase 1: Request new device code
68
+ const deviceCodeResponse = await requestDeviceCode(config);
69
+ // Save pending device code for Phase 2
70
+ const now = Math.floor(Date.now() / 1000);
71
+ const pendingCode = {
72
+ deviceCode: deviceCodeResponse.device_code,
73
+ userCode: deviceCodeResponse.user_code,
74
+ verificationUri: deviceCodeResponse.verification_uri,
75
+ interval: deviceCodeResponse.interval,
76
+ expiresAt: now + deviceCodeResponse.expires_in,
77
+ };
78
+ await savePendingDeviceCode(pendingCode);
79
+ // Open browser - logout from Auth0 first to force fresh login
80
+ const returnUrl = `https://${config.domain}/activate?user_code=${deviceCodeResponse.user_code}`;
81
+ const logoutUrl = `https://${config.domain}/v2/logout?client_id=${config.clientId}&returnTo=${encodeURIComponent(returnUrl)}`;
82
+ try {
83
+ await open(logoutUrl);
84
+ }
85
+ catch {
86
+ // Browser didn't open, will show manual instructions
87
+ }
88
+ // Return immediately with the code - user will call again after completing login
89
+ return `🔐 **Verification Code: ${deviceCodeResponse.user_code}**
90
+
91
+ A browser window is opening for login.
92
+
93
+ **Please verify this code matches what you see in the browser before confirming!**
94
+
95
+ After you complete the login in your browser, say **"continue login"** or call this tool again to complete authentication.
96
+
97
+ _Code expires in ${Math.floor(deviceCodeResponse.expires_in / 60)} minutes._`;
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ await clearPendingDeviceCode(); // Clean up on error
102
+ return `❌ Login failed: ${message}. Please try again.`;
103
+ }
104
+ }
105
+ /**
106
+ * Complete pending authentication (Phase 2)
107
+ */
108
+ async function completePendingAuth(config, pending) {
109
+ try {
110
+ console.error(`[Auth] Checking pending authorization for code: ${pending.userCode}`);
111
+ const now = Math.floor(Date.now() / 1000);
112
+ const remainingTime = pending.expiresAt - now;
113
+ // Poll for token
114
+ const token = await pollForToken(config, pending.deviceCode, pending.interval, remainingTime, () => { } // No progress callback needed in MCP context
115
+ );
116
+ // Clear pending code
117
+ await clearPendingDeviceCode();
118
+ // Extract email from id_token
119
+ let email;
120
+ if (token.id_token) {
121
+ try {
122
+ const payload = JSON.parse(Buffer.from(token.id_token.split('.')[1], 'base64').toString());
123
+ email = payload.email || payload['https://acuity.com/email'] || payload['https://acuityppm.com/email'];
124
+ }
125
+ catch {
126
+ // Ignore parsing errors
127
+ }
128
+ }
129
+ // Save credentials
130
+ const credentials = tokenResponseToCredentials(token, email);
131
+ await saveCredentials(credentials);
132
+ const env = getEnvironment();
133
+ return `✅ **Login Successful!**
134
+
135
+ Environment: ${env.name}
136
+ Logged in as: ${email || 'unknown user'}
137
+
138
+ You can now use Acuity tools:
139
+ - "Show me my projects"
140
+ - "List active projects"
141
+ - "Get status reports"`;
142
+ }
143
+ catch (error) {
144
+ const message = error instanceof Error ? error.message : String(error);
145
+ // Check if it's "authorization pending" - user hasn't completed yet
146
+ if (message.includes('authorization_pending') || message.includes('Authorization timed out')) {
147
+ const remaining = Math.floor((pending.expiresAt - Math.floor(Date.now() / 1000)) / 60);
148
+ if (remaining > 0) {
149
+ return `⏳ **Waiting for login...**
150
+
151
+ Your verification code: **${pending.userCode}**
152
+
153
+ Please complete the login in your browser, then call this tool again.
154
+
155
+ _Code expires in ${remaining} minutes._`;
156
+ }
157
+ }
158
+ // Real error or expired - clean up
159
+ await clearPendingDeviceCode();
160
+ return `❌ Login failed: ${message}. Please try again.`;
161
+ }
162
+ }
163
+ /**
164
+ * Handle logout - clears credentials and pending auth
165
+ */
166
+ export async function logout() {
167
+ const deletedCreds = await clearCredentials();
168
+ const deletedPending = await clearPendingDeviceCode();
169
+ if (deletedCreds || deletedPending) {
170
+ return '✅ Successfully logged out. Credentials removed from system keychain.';
171
+ }
172
+ else {
173
+ return 'No credentials found. You are not logged in.';
174
+ }
175
+ }
176
+ /**
177
+ * Check auth status
178
+ */
179
+ export async function getAuthStatus() {
180
+ // Check for pending auth first
181
+ const pending = await loadPendingDeviceCode();
182
+ if (pending) {
183
+ const now = Math.floor(Date.now() / 1000);
184
+ const remaining = Math.floor((pending.expiresAt - now) / 60);
185
+ return `⏳ **Login in progress...**
186
+
187
+ Your verification code: **${pending.userCode}**
188
+
189
+ Complete the login in your browser, then say "continue login".
190
+
191
+ _Code expires in ${remaining} minutes._`;
192
+ }
193
+ const creds = await loadCredentials();
194
+ if (!creds) {
195
+ return '❌ Not authenticated. Use "login to Acuity" to authenticate.';
196
+ }
197
+ const now = Math.floor(Date.now() / 1000);
198
+ const isExpired = creds.expiresAt <= now;
199
+ const expiresIn = creds.expiresAt - now;
200
+ if (isExpired) {
201
+ return `⚠️ Authentication expired for ${creds.email || 'unknown user'}. Use "login to Acuity" to re-authenticate.`;
202
+ }
203
+ const minutes = Math.floor(expiresIn / 60);
204
+ const refreshStatus = creds.refreshToken ? '✅ Auto-refresh enabled' : '⚠️ No refresh token';
205
+ const env = getEnvironment();
206
+ return `✅ **Authenticated**
207
+
208
+ Environment: ${env.name}
209
+ User: ${creds.email || 'unknown user'}
210
+ Token expires in: ${minutes} minutes
211
+ ${refreshStatus}`;
212
+ }
213
+ //# sourceMappingURL=init-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-auth.js","sourceRoot":"","sources":["../../src/tools/init-auth.ts"],"names":[],"mappings":"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"}