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/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
- // Load legacy config for backward compatibility
99
- const config = loadConfig();
100
- logger.setLevel(config.logLevel);
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
- // Initialize Lexic client with PAT
103
- const lexicClient = createLexicClient(config);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lexic-mcp",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "MCP server connecting Claude Code to Lexic knowledge management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",