lexic-mcp 0.1.12 → 0.1.13
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/bundle.cjs +40 -40
- package/dist/index.js +105 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import { logger } from './utils/logger.js';
|
|
|
31
31
|
import { getTriggers } from './utils/trigger-cache.js';
|
|
32
32
|
import { getDomains } from './utils/domain-cache.js';
|
|
33
33
|
import { buildDescription } from './utils/description-builder.js';
|
|
34
|
-
import { startBrowserOAuthFlow, getCredentials, hasValidCredentials, clearAllCredentials, removeCredentials, listStoredProjects, BrowserOAuthError } from './auth/index.js';
|
|
34
|
+
import { startBrowserOAuthFlow, getCredentials, hasValidCredentials, hasExpiredCredentials, clearAllCredentials, removeCredentials, listStoredProjects, getDefaultProject, getValidToken, tryDiscoverAuthConfig, BrowserOAuthError } from './auth/index.js';
|
|
35
35
|
import * as readline from 'readline';
|
|
36
36
|
// ============================================================================
|
|
37
37
|
// TOOL REGISTRATION
|
|
@@ -92,15 +92,113 @@ async function registerTools(lexicClient, triggers, domains) {
|
|
|
92
92
|
return tools;
|
|
93
93
|
}
|
|
94
94
|
// ============================================================================
|
|
95
|
-
// STDIO TRANSPORT (PAT Authentication)
|
|
95
|
+
// STDIO TRANSPORT (OAuth or PAT Authentication)
|
|
96
96
|
// ============================================================================
|
|
97
97
|
async function runStdioServer() {
|
|
98
|
-
//
|
|
99
|
-
const
|
|
100
|
-
logger.setLevel(
|
|
98
|
+
// Set log level from environment
|
|
99
|
+
const logLevel = process.env.LOG_LEVEL || 'info';
|
|
100
|
+
logger.setLevel(logLevel);
|
|
101
101
|
logger.info('Starting Lexic MCP Server (stdio transport)');
|
|
102
|
-
|
|
103
|
-
const
|
|
102
|
+
let lexicClient;
|
|
103
|
+
const apiUrl = process.env.LEXIC_API_URL || 'https://app.lexic.io/api';
|
|
104
|
+
// Check for OAuth credentials first
|
|
105
|
+
const defaultProject = getDefaultProject();
|
|
106
|
+
const isValid = defaultProject ? hasValidCredentials(defaultProject) : false;
|
|
107
|
+
const isExpired = defaultProject ? hasExpiredCredentials(defaultProject) : false;
|
|
108
|
+
const hasOAuth = defaultProject && (isValid || isExpired);
|
|
109
|
+
logger.debug('OAuth credential check', {
|
|
110
|
+
defaultProject,
|
|
111
|
+
hasValidCredentials: isValid,
|
|
112
|
+
hasExpiredCredentials: isExpired,
|
|
113
|
+
hasOAuth
|
|
114
|
+
});
|
|
115
|
+
if (hasOAuth && defaultProject) {
|
|
116
|
+
logger.info('Using OAuth authentication');
|
|
117
|
+
// Get auth config for token refresh
|
|
118
|
+
const authConfig = await tryDiscoverAuthConfig();
|
|
119
|
+
if (!authConfig) {
|
|
120
|
+
logger.error('Failed to discover auth config for OAuth');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
logger.debug('Auth config discovered', {
|
|
124
|
+
supabaseUrl: authConfig.supabaseUrl,
|
|
125
|
+
matchesDefaultProject: authConfig.supabaseUrl === defaultProject
|
|
126
|
+
});
|
|
127
|
+
// Get valid token (may refresh if expired)
|
|
128
|
+
// Use defaultProject for credential lookup since that's where they're stored
|
|
129
|
+
// Use authConfig.supabaseAnonKey for token refresh (needed for Supabase auth)
|
|
130
|
+
const accessToken = await getValidToken({
|
|
131
|
+
supabaseUrl: defaultProject,
|
|
132
|
+
supabaseAnonKey: authConfig.supabaseAnonKey
|
|
133
|
+
});
|
|
134
|
+
// Warn if there's a URL mismatch (shouldn't happen normally)
|
|
135
|
+
if (authConfig.supabaseUrl !== defaultProject) {
|
|
136
|
+
logger.warn('Supabase URL mismatch between discovery and stored credentials', {
|
|
137
|
+
discoveredUrl: authConfig.supabaseUrl,
|
|
138
|
+
storedUrl: defaultProject
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
logger.debug('Token retrieval result', {
|
|
142
|
+
hasToken: !!accessToken,
|
|
143
|
+
tokenLength: accessToken?.length
|
|
144
|
+
});
|
|
145
|
+
if (!accessToken) {
|
|
146
|
+
logger.error('Failed to get valid OAuth token. Please run: lexic-mcp login');
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
// Create client with OAuth
|
|
150
|
+
lexicClient = createLexicClientWithAuth({
|
|
151
|
+
apiUrl,
|
|
152
|
+
auth: {
|
|
153
|
+
type: 'oauth',
|
|
154
|
+
token: accessToken
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
// Log OAuth user info
|
|
158
|
+
const credentials = getCredentials(defaultProject);
|
|
159
|
+
if (credentials?.email) {
|
|
160
|
+
logger.info('Authenticated as', { email: credentials.email });
|
|
161
|
+
}
|
|
162
|
+
// For OAuth, we trust the local token validation
|
|
163
|
+
// The API will validate on each request
|
|
164
|
+
logger.info('Connected to Lexic (OAuth mode)');
|
|
165
|
+
}
|
|
166
|
+
else if (process.env.LEXIC_PAT) {
|
|
167
|
+
// Fall back to PAT authentication
|
|
168
|
+
logger.info('Using PAT authentication');
|
|
169
|
+
const config = loadConfig();
|
|
170
|
+
lexicClient = createLexicClient(config);
|
|
171
|
+
// Validate connection and log PAT expiration
|
|
172
|
+
const validation = await lexicClient.validateConnection();
|
|
173
|
+
if (!validation.valid) {
|
|
174
|
+
logger.error('Failed to connect to Lexic', { error: validation.error });
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
// Log PAT expiration info
|
|
178
|
+
if (validation.expiresAt) {
|
|
179
|
+
const now = new Date();
|
|
180
|
+
const daysUntilExpiry = Math.ceil((validation.expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
181
|
+
const expiresAt = validation.expiresAt.toISOString();
|
|
182
|
+
const dayLabel = daysUntilExpiry === 1 ? 'day' : 'days';
|
|
183
|
+
switch (true) {
|
|
184
|
+
case daysUntilExpiry <= 0:
|
|
185
|
+
logger.error('PAT has expired', { expiresAt });
|
|
186
|
+
break;
|
|
187
|
+
case daysUntilExpiry <= 3:
|
|
188
|
+
logger.warn(`PAT expires in ${daysUntilExpiry} ${dayLabel}`, { expiresAt });
|
|
189
|
+
break;
|
|
190
|
+
case daysUntilExpiry <= 7:
|
|
191
|
+
logger.info(`PAT expires in ${daysUntilExpiry} ${dayLabel}`, { expiresAt });
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// No authentication available
|
|
198
|
+
logger.error('No authentication found. Please run: lexic-mcp login');
|
|
199
|
+
logger.error('Or set LEXIC_PAT environment variable');
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
104
202
|
// Validate connection
|
|
105
203
|
const validation = await lexicClient.validateConnection();
|
|
106
204
|
if (!validation.valid) {
|
|
@@ -111,24 +209,6 @@ async function runStdioServer() {
|
|
|
111
209
|
lexiconId: validation.lexiconId,
|
|
112
210
|
isUserScoped: validation.isUserScoped
|
|
113
211
|
});
|
|
114
|
-
// Log PAT expiration info (ascending thresholds: 0 -> 3 -> 7)
|
|
115
|
-
if (validation.expiresAt) {
|
|
116
|
-
const now = new Date();
|
|
117
|
-
const daysUntilExpiry = Math.ceil((validation.expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
118
|
-
const expiresAt = validation.expiresAt.toISOString();
|
|
119
|
-
const dayLabel = daysUntilExpiry === 1 ? 'day' : 'days';
|
|
120
|
-
switch (true) {
|
|
121
|
-
case daysUntilExpiry <= 0:
|
|
122
|
-
logger.error('PAT has expired', { expiresAt });
|
|
123
|
-
break;
|
|
124
|
-
case daysUntilExpiry <= 3:
|
|
125
|
-
logger.warn(`PAT expires in ${daysUntilExpiry} ${dayLabel}`, { expiresAt });
|
|
126
|
-
break;
|
|
127
|
-
case daysUntilExpiry <= 7:
|
|
128
|
-
logger.info(`PAT expires in ${daysUntilExpiry} ${dayLabel}`, { expiresAt });
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
212
|
// Load domains and triggers
|
|
133
213
|
const { domains, triggers } = await loadConfiguration(lexicClient);
|
|
134
214
|
// Register tools
|