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.
Files changed (51) hide show
  1. package/.releaserc.json +34 -0
  2. package/README.md +687 -0
  3. package/dist/cli/index.d.ts +7 -0
  4. package/dist/cli/index.js +43 -0
  5. package/dist/cli/latitude.cli.d.ts +10 -0
  6. package/dist/cli/latitude.cli.js +286 -0
  7. package/dist/controllers/latitude.controller.d.ts +115 -0
  8. package/dist/controllers/latitude.controller.js +287 -0
  9. package/dist/index.d.ts +6 -0
  10. package/dist/index.js +166 -0
  11. package/dist/resources/latitude.resource.d.ts +12 -0
  12. package/dist/resources/latitude.resource.js +145 -0
  13. package/dist/services/vendor.latitude.service.d.ts +49 -0
  14. package/dist/services/vendor.latitude.service.js +294 -0
  15. package/dist/tools/latitude.tool.d.ts +6 -0
  16. package/dist/tools/latitude.tool.js +517 -0
  17. package/dist/types/common.types.d.ts +20 -0
  18. package/dist/types/common.types.js +7 -0
  19. package/dist/types/latitude.types.d.ts +487 -0
  20. package/dist/types/latitude.types.js +311 -0
  21. package/dist/utils/cli.test.util.d.ts +34 -0
  22. package/dist/utils/cli.test.util.js +143 -0
  23. package/dist/utils/config.util.d.ts +43 -0
  24. package/dist/utils/config.util.js +145 -0
  25. package/dist/utils/config.util.test.d.ts +1 -0
  26. package/dist/utils/constants.util.d.ts +26 -0
  27. package/dist/utils/constants.util.js +29 -0
  28. package/dist/utils/error-handler.util.d.ts +54 -0
  29. package/dist/utils/error-handler.util.js +202 -0
  30. package/dist/utils/error-handler.util.test.d.ts +1 -0
  31. package/dist/utils/error.util.d.ts +73 -0
  32. package/dist/utils/error.util.js +174 -0
  33. package/dist/utils/error.util.test.d.ts +1 -0
  34. package/dist/utils/formatter.util.d.ts +36 -0
  35. package/dist/utils/formatter.util.js +116 -0
  36. package/dist/utils/jest.setup.d.ts +5 -0
  37. package/dist/utils/jest.setup.js +36 -0
  38. package/dist/utils/jq.util.d.ts +34 -0
  39. package/dist/utils/jq.util.js +87 -0
  40. package/dist/utils/logger.util.d.ts +78 -0
  41. package/dist/utils/logger.util.js +344 -0
  42. package/dist/utils/toon.util.d.ts +15 -0
  43. package/dist/utils/toon.util.js +65 -0
  44. package/dist/utils/transport.util.d.ts +49 -0
  45. package/dist/utils/transport.util.js +162 -0
  46. package/eslint.config.mjs +46 -0
  47. package/openapi.json +12592 -0
  48. package/package.json +118 -0
  49. package/scripts/ensure-executable.js +38 -0
  50. package/scripts/package.json +3 -0
  51. 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
+ };
@@ -0,0 +1,6 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ declare function registerTools(server: McpServer): void;
3
+ declare const _default: {
4
+ registerTools: typeof registerTools;
5
+ };
6
+ export default _default;