latitude-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.
- package/.releaserc.json +34 -0
- package/README.md +687 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +43 -0
- package/dist/cli/latitude.cli.d.ts +10 -0
- package/dist/cli/latitude.cli.js +286 -0
- package/dist/controllers/latitude.controller.d.ts +115 -0
- package/dist/controllers/latitude.controller.js +287 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +166 -0
- package/dist/resources/latitude.resource.d.ts +12 -0
- package/dist/resources/latitude.resource.js +145 -0
- package/dist/services/vendor.latitude.service.d.ts +49 -0
- package/dist/services/vendor.latitude.service.js +294 -0
- package/dist/tools/latitude.tool.d.ts +6 -0
- package/dist/tools/latitude.tool.js +517 -0
- package/dist/types/common.types.d.ts +20 -0
- package/dist/types/common.types.js +7 -0
- package/dist/types/latitude.types.d.ts +487 -0
- package/dist/types/latitude.types.js +311 -0
- package/dist/utils/cli.test.util.d.ts +34 -0
- package/dist/utils/cli.test.util.js +143 -0
- package/dist/utils/config.util.d.ts +43 -0
- package/dist/utils/config.util.js +145 -0
- package/dist/utils/config.util.test.d.ts +1 -0
- package/dist/utils/constants.util.d.ts +26 -0
- package/dist/utils/constants.util.js +29 -0
- package/dist/utils/error-handler.util.d.ts +54 -0
- package/dist/utils/error-handler.util.js +202 -0
- package/dist/utils/error-handler.util.test.d.ts +1 -0
- package/dist/utils/error.util.d.ts +73 -0
- package/dist/utils/error.util.js +174 -0
- package/dist/utils/error.util.test.d.ts +1 -0
- package/dist/utils/formatter.util.d.ts +36 -0
- package/dist/utils/formatter.util.js +116 -0
- package/dist/utils/jest.setup.d.ts +5 -0
- package/dist/utils/jest.setup.js +36 -0
- package/dist/utils/jq.util.d.ts +34 -0
- package/dist/utils/jq.util.js +87 -0
- package/dist/utils/logger.util.d.ts +78 -0
- package/dist/utils/logger.util.js +344 -0
- package/dist/utils/toon.util.d.ts +15 -0
- package/dist/utils/toon.util.js +65 -0
- package/dist/utils/transport.util.d.ts +49 -0
- package/dist/utils/transport.util.js +162 -0
- package/eslint.config.mjs +46 -0
- package/openapi.json +12592 -0
- package/package.json +118 -0
- package/scripts/ensure-executable.js +38 -0
- package/scripts/package.json +3 -0
- package/scripts/update-version.js +204 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const logger_util_js_1 = require("../utils/logger.util.js");
|
|
4
|
+
const config_util_js_1 = require("../utils/config.util.js");
|
|
5
|
+
const error_util_js_1 = require("../utils/error.util.js");
|
|
6
|
+
const constants_util_js_1 = require("../utils/constants.util.js");
|
|
7
|
+
const latitude_types_js_1 = require("../types/latitude.types.js");
|
|
8
|
+
// Create a contextualized logger for this file
|
|
9
|
+
const serviceLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts');
|
|
10
|
+
// Log service initialization
|
|
11
|
+
serviceLogger.debug('Latitude API service initialized');
|
|
12
|
+
/**
|
|
13
|
+
* Get Latitude API credentials from configuration
|
|
14
|
+
*/
|
|
15
|
+
function getLatitudeCredentials() {
|
|
16
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'getLatitudeCredentials');
|
|
17
|
+
const apiKey = config_util_js_1.config.get('LATITUDE_API_KEY');
|
|
18
|
+
const baseUrl = config_util_js_1.config.get('LATITUDE_BASE_URL') || constants_util_js_1.LATITUDE_BASE_URL;
|
|
19
|
+
if (!apiKey) {
|
|
20
|
+
methodLogger.error('LATITUDE_API_KEY is not configured');
|
|
21
|
+
throw (0, error_util_js_1.createAuthInvalidError)('LATITUDE_API_KEY is required. Set it in your environment or .env file.');
|
|
22
|
+
}
|
|
23
|
+
methodLogger.debug('Latitude credentials loaded successfully');
|
|
24
|
+
return { apiKey, baseUrl };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generic fetch function for Latitude API
|
|
28
|
+
*/
|
|
29
|
+
async function fetchLatitudeApi(endpoint, options = {}) {
|
|
30
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'fetchLatitudeApi');
|
|
31
|
+
const { apiKey, baseUrl } = getLatitudeCredentials();
|
|
32
|
+
const url = `${baseUrl}/api/${constants_util_js_1.LATITUDE_API_VERSION}${endpoint}`;
|
|
33
|
+
const requestOptions = {
|
|
34
|
+
method: options.method || 'GET',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
Accept: 'application/json',
|
|
38
|
+
Authorization: `Bearer ${apiKey}`,
|
|
39
|
+
...options.headers,
|
|
40
|
+
},
|
|
41
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
42
|
+
};
|
|
43
|
+
methodLogger.debug(`Executing API call: ${requestOptions.method} ${url}`);
|
|
44
|
+
const startTime = performance.now();
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(url, requestOptions);
|
|
47
|
+
const endTime = performance.now();
|
|
48
|
+
const duration = (endTime - startTime).toFixed(2);
|
|
49
|
+
methodLogger.debug(`API call completed in ${duration}ms with status: ${response.status}`);
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
const errorText = await response.text();
|
|
52
|
+
methodLogger.error(`API error response (${response.status}):`, errorText);
|
|
53
|
+
// Try to parse as Latitude error format
|
|
54
|
+
let errorData;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(errorText);
|
|
57
|
+
errorData = latitude_types_js_1.LatitudeErrorSchema.parse(parsed);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Not a standard Latitude error format
|
|
61
|
+
}
|
|
62
|
+
if (response.status === 401) {
|
|
63
|
+
throw (0, error_util_js_1.createAuthInvalidError)(errorData?.message || 'Authentication failed. Check your LATITUDE_API_KEY.');
|
|
64
|
+
}
|
|
65
|
+
else if (response.status === 403) {
|
|
66
|
+
throw (0, error_util_js_1.createAuthInvalidError)(errorData?.message || 'Permission denied for the requested resource.');
|
|
67
|
+
}
|
|
68
|
+
else if (response.status === 404) {
|
|
69
|
+
throw (0, error_util_js_1.createApiError)(errorData?.message || 'Resource not found.', response.status, errorData || errorText);
|
|
70
|
+
}
|
|
71
|
+
else if (response.status === 422) {
|
|
72
|
+
throw (0, error_util_js_1.createApiError)(errorData?.message || 'Validation error.', response.status, errorData || errorText);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
throw (0, error_util_js_1.createApiError)(errorData?.message ||
|
|
76
|
+
`API request failed with status ${response.status}`, response.status, errorData || errorText);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Handle empty responses
|
|
80
|
+
const contentLength = response.headers.get('content-length');
|
|
81
|
+
if (contentLength === '0' || response.status === 204) {
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
const responseData = await response.json();
|
|
85
|
+
methodLogger.debug('Response body successfully parsed as JSON.');
|
|
86
|
+
return responseData;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof error_util_js_1.McpError) {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
if (error instanceof TypeError) {
|
|
93
|
+
throw (0, error_util_js_1.createApiError)(`Network error during API call: ${error.message}`, undefined, error);
|
|
94
|
+
}
|
|
95
|
+
throw (0, error_util_js_1.createUnexpectedError)(`Unexpected error during API call: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Fetch with streaming support for run/chat endpoints
|
|
100
|
+
*/
|
|
101
|
+
async function fetchLatitudeStream(endpoint, body) {
|
|
102
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'fetchLatitudeStream');
|
|
103
|
+
const { apiKey, baseUrl } = getLatitudeCredentials();
|
|
104
|
+
const url = `${baseUrl}/api/${constants_util_js_1.LATITUDE_API_VERSION}${endpoint}`;
|
|
105
|
+
const response = await fetch(url, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
Accept: 'text/event-stream',
|
|
110
|
+
Authorization: `Bearer ${apiKey}`,
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(body),
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const errorText = await response.text();
|
|
116
|
+
throw (0, error_util_js_1.createApiError)(`Stream request failed: ${response.status}`, response.status, errorText);
|
|
117
|
+
}
|
|
118
|
+
if (!response.body) {
|
|
119
|
+
throw (0, error_util_js_1.createApiError)('No response body for stream', 500, null);
|
|
120
|
+
}
|
|
121
|
+
const reader = response.body.getReader();
|
|
122
|
+
const decoder = new TextDecoder();
|
|
123
|
+
async function* streamGenerator() {
|
|
124
|
+
try {
|
|
125
|
+
while (true) {
|
|
126
|
+
const { done, value } = await reader.read();
|
|
127
|
+
if (done)
|
|
128
|
+
break;
|
|
129
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
130
|
+
yield chunk;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
reader.releaseLock();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
methodLogger.debug('Stream initiated successfully');
|
|
138
|
+
return streamGenerator();
|
|
139
|
+
}
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// Projects API
|
|
142
|
+
// ============================================================================
|
|
143
|
+
async function listProjects() {
|
|
144
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'listProjects');
|
|
145
|
+
methodLogger.debug('Listing all projects');
|
|
146
|
+
const data = await fetchLatitudeApi('/projects');
|
|
147
|
+
return latitude_types_js_1.ProjectListSchema.parse(data);
|
|
148
|
+
}
|
|
149
|
+
async function createProject(name) {
|
|
150
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'createProject');
|
|
151
|
+
methodLogger.debug(`Creating project: ${name}`);
|
|
152
|
+
const data = await fetchLatitudeApi('/projects', {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
body: { name },
|
|
155
|
+
});
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
// ============================================================================
|
|
159
|
+
// Versions API
|
|
160
|
+
// ============================================================================
|
|
161
|
+
async function listVersions(projectId) {
|
|
162
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'listVersions');
|
|
163
|
+
methodLogger.debug(`Listing versions for project: ${projectId}`);
|
|
164
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions`);
|
|
165
|
+
return latitude_types_js_1.VersionListSchema.parse(data);
|
|
166
|
+
}
|
|
167
|
+
async function getVersion(projectId, versionUuid) {
|
|
168
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'getVersion');
|
|
169
|
+
methodLogger.debug(`Getting version: ${versionUuid} for project: ${projectId}`);
|
|
170
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}`);
|
|
171
|
+
return latitude_types_js_1.VersionSchema.parse(data);
|
|
172
|
+
}
|
|
173
|
+
async function createVersion(projectId, name) {
|
|
174
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'createVersion');
|
|
175
|
+
methodLogger.debug(`Creating version: ${name} for project: ${projectId}`);
|
|
176
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions`, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
body: { name },
|
|
179
|
+
});
|
|
180
|
+
return latitude_types_js_1.VersionSchema.parse(data);
|
|
181
|
+
}
|
|
182
|
+
async function publishVersion(projectId, versionUuid, options) {
|
|
183
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'publishVersion');
|
|
184
|
+
methodLogger.debug(`Publishing version: ${versionUuid}`);
|
|
185
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/publish`, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
body: options || {},
|
|
188
|
+
});
|
|
189
|
+
return latitude_types_js_1.VersionSchema.parse(data);
|
|
190
|
+
}
|
|
191
|
+
async function pushChanges(projectId, versionUuid, changes) {
|
|
192
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'pushChanges');
|
|
193
|
+
methodLogger.debug(`Pushing ${changes.changes.length} changes to version: ${versionUuid}`);
|
|
194
|
+
return fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/push`, {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
body: changes,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// ============================================================================
|
|
200
|
+
// Documents/Prompts API
|
|
201
|
+
// ============================================================================
|
|
202
|
+
async function listDocuments(projectId, versionUuid) {
|
|
203
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'listDocuments');
|
|
204
|
+
methodLogger.debug(`Listing documents for project: ${projectId}, version: ${versionUuid}`);
|
|
205
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/documents`);
|
|
206
|
+
return latitude_types_js_1.DocumentListSchema.parse(data);
|
|
207
|
+
}
|
|
208
|
+
async function getDocument(projectId, versionUuid, path) {
|
|
209
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'getDocument');
|
|
210
|
+
// Ensure path doesn't start with / for URL construction
|
|
211
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
212
|
+
methodLogger.debug(`Getting document: ${normalizedPath}`);
|
|
213
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/documents/${normalizedPath}`);
|
|
214
|
+
return latitude_types_js_1.DocumentSchema.parse(data);
|
|
215
|
+
}
|
|
216
|
+
async function createOrUpdateDocument(projectId, versionUuid, path, prompt, force = false) {
|
|
217
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'createOrUpdateDocument');
|
|
218
|
+
methodLogger.debug(`Creating/updating document: ${path}`);
|
|
219
|
+
const data = await fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/documents/create-or-update`, {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
body: { path, prompt, force },
|
|
222
|
+
});
|
|
223
|
+
return latitude_types_js_1.DocumentSchema.parse(data);
|
|
224
|
+
}
|
|
225
|
+
async function runDocument(projectId, versionUuid, options) {
|
|
226
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'runDocument');
|
|
227
|
+
methodLogger.debug(`Running document: ${options.path}`);
|
|
228
|
+
if (options.stream) {
|
|
229
|
+
return fetchLatitudeStream(`/projects/${projectId}/versions/${versionUuid}/documents/run`, options);
|
|
230
|
+
}
|
|
231
|
+
return fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/documents/run`, {
|
|
232
|
+
method: 'POST',
|
|
233
|
+
body: options,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async function createDocumentLog(projectId, versionUuid, path, messages) {
|
|
237
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'createDocumentLog');
|
|
238
|
+
methodLogger.debug(`Creating log for document: ${path}`);
|
|
239
|
+
return fetchLatitudeApi(`/projects/${projectId}/versions/${versionUuid}/documents/logs`, {
|
|
240
|
+
method: 'POST',
|
|
241
|
+
body: { path, messages },
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
// ============================================================================
|
|
245
|
+
// Conversations API
|
|
246
|
+
// ============================================================================
|
|
247
|
+
async function getConversation(conversationUuid) {
|
|
248
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'getConversation');
|
|
249
|
+
methodLogger.debug(`Getting conversation: ${conversationUuid}`);
|
|
250
|
+
const data = await fetchLatitudeApi(`/conversations/${conversationUuid}`);
|
|
251
|
+
return data;
|
|
252
|
+
}
|
|
253
|
+
async function chatConversation(conversationUuid, messages, stream = false) {
|
|
254
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'chatConversation');
|
|
255
|
+
methodLogger.debug(`Chatting in conversation: ${conversationUuid}`);
|
|
256
|
+
if (stream) {
|
|
257
|
+
return fetchLatitudeStream(`/conversations/${conversationUuid}/chat`, { messages, stream: true });
|
|
258
|
+
}
|
|
259
|
+
return fetchLatitudeApi(`/conversations/${conversationUuid}/chat`, {
|
|
260
|
+
method: 'POST',
|
|
261
|
+
body: { messages, stream: false },
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function stopConversation(conversationUuid) {
|
|
265
|
+
const methodLogger = logger_util_js_1.Logger.forContext('services/vendor.latitude.service.ts', 'stopConversation');
|
|
266
|
+
methodLogger.debug(`Stopping conversation: ${conversationUuid}`);
|
|
267
|
+
return fetchLatitudeApi(`/conversations/${conversationUuid}/stop`, {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
// ============================================================================
|
|
272
|
+
// Export Service
|
|
273
|
+
// ============================================================================
|
|
274
|
+
exports.default = {
|
|
275
|
+
// Projects
|
|
276
|
+
listProjects,
|
|
277
|
+
createProject,
|
|
278
|
+
// Versions
|
|
279
|
+
listVersions,
|
|
280
|
+
getVersion,
|
|
281
|
+
createVersion,
|
|
282
|
+
publishVersion,
|
|
283
|
+
pushChanges,
|
|
284
|
+
// Documents/Prompts
|
|
285
|
+
listDocuments,
|
|
286
|
+
getDocument,
|
|
287
|
+
createOrUpdateDocument,
|
|
288
|
+
runDocument,
|
|
289
|
+
createDocumentLog,
|
|
290
|
+
// Conversations
|
|
291
|
+
getConversation,
|
|
292
|
+
chatConversation,
|
|
293
|
+
stopConversation,
|
|
294
|
+
};
|