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,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const logger_util_js_1 = require("../utils/logger.util.js");
|
|
9
|
+
const vendor_latitude_service_js_1 = __importDefault(require("../services/vendor.latitude.service.js"));
|
|
10
|
+
const error_handler_util_js_1 = require("../utils/error-handler.util.js");
|
|
11
|
+
const jq_util_js_1 = require("../utils/jq.util.js");
|
|
12
|
+
/**
|
|
13
|
+
* Derive prompt path from filename
|
|
14
|
+
* e.g., "/path/to/my-prompt.md" → "my-prompt"
|
|
15
|
+
*/
|
|
16
|
+
function derivePromptPath(filePath) {
|
|
17
|
+
const base = (0, path_1.basename)(filePath);
|
|
18
|
+
const ext = (0, path_1.extname)(base);
|
|
19
|
+
// Remove .md, .promptl, .txt extensions
|
|
20
|
+
if (['.md', '.promptl', '.txt'].includes(ext)) {
|
|
21
|
+
return base.slice(0, -ext.length);
|
|
22
|
+
}
|
|
23
|
+
return base;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Format output data consistently
|
|
27
|
+
*/
|
|
28
|
+
async function formatOutput(data, options = {}) {
|
|
29
|
+
const filteredData = (0, jq_util_js_1.applyJqFilter)(data, options.jq);
|
|
30
|
+
const useToon = options.outputFormat !== 'json';
|
|
31
|
+
const content = await (0, jq_util_js_1.toOutputString)(filteredData, useToon);
|
|
32
|
+
return { content };
|
|
33
|
+
}
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Projects Controller
|
|
36
|
+
// ============================================================================
|
|
37
|
+
async function listProjects(options = {}) {
|
|
38
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'listProjects');
|
|
39
|
+
methodLogger.debug('Listing all projects');
|
|
40
|
+
try {
|
|
41
|
+
const projects = await vendor_latitude_service_js_1.default.listProjects();
|
|
42
|
+
return formatOutput(projects, options);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'listProjects', 'controllers/latitude.controller.ts@listProjects', 'projects', {}));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function createProject(args) {
|
|
49
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'createProject');
|
|
50
|
+
methodLogger.debug(`Creating project: ${args.name}`);
|
|
51
|
+
try {
|
|
52
|
+
const project = await vendor_latitude_service_js_1.default.createProject(args.name);
|
|
53
|
+
return formatOutput(project, args);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'createProject', 'controllers/latitude.controller.ts@createProject', args.name, { args }));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Versions Controller
|
|
61
|
+
// ============================================================================
|
|
62
|
+
async function listVersions(args) {
|
|
63
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'listVersions');
|
|
64
|
+
methodLogger.debug(`Listing versions for project: ${args.projectId}`);
|
|
65
|
+
try {
|
|
66
|
+
const versions = await vendor_latitude_service_js_1.default.listVersions(args.projectId);
|
|
67
|
+
return formatOutput(versions, args);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'listVersions', 'controllers/latitude.controller.ts@listVersions', args.projectId, { args }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function getVersion(args) {
|
|
74
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'getVersion');
|
|
75
|
+
methodLogger.debug(`Getting version: ${args.versionUuid}`);
|
|
76
|
+
try {
|
|
77
|
+
const version = await vendor_latitude_service_js_1.default.getVersion(args.projectId, args.versionUuid);
|
|
78
|
+
return formatOutput(version, args);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'getVersion', 'controllers/latitude.controller.ts@getVersion', args.versionUuid, { args }));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function createVersion(args) {
|
|
85
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'createVersion');
|
|
86
|
+
methodLogger.debug(`Creating version: ${args.name}`);
|
|
87
|
+
try {
|
|
88
|
+
const version = await vendor_latitude_service_js_1.default.createVersion(args.projectId, args.name);
|
|
89
|
+
return formatOutput(version, args);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'createVersion', 'controllers/latitude.controller.ts@createVersion', args.name, { args }));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function publishVersion(args) {
|
|
96
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'publishVersion');
|
|
97
|
+
methodLogger.debug(`Publishing version: ${args.versionUuid}`);
|
|
98
|
+
try {
|
|
99
|
+
const version = await vendor_latitude_service_js_1.default.publishVersion(args.projectId, args.versionUuid, { title: args.title, description: args.description });
|
|
100
|
+
return formatOutput(version, args);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'publishVersion', 'controllers/latitude.controller.ts@publishVersion', args.versionUuid, { args }));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function pushChanges(args) {
|
|
107
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'pushChanges');
|
|
108
|
+
methodLogger.debug(`Pushing ${args.changes.length} changes`);
|
|
109
|
+
try {
|
|
110
|
+
const result = await vendor_latitude_service_js_1.default.pushChanges(args.projectId, args.versionUuid, { changes: args.changes });
|
|
111
|
+
return formatOutput(result, args);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'pushChanges', 'controllers/latitude.controller.ts@pushChanges', args.versionUuid, { args }));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// Documents/Prompts Controller
|
|
119
|
+
// ============================================================================
|
|
120
|
+
async function listPrompts(args) {
|
|
121
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'listPrompts');
|
|
122
|
+
methodLogger.debug(`Listing prompts for version: ${args.versionUuid}`);
|
|
123
|
+
try {
|
|
124
|
+
const documents = await vendor_latitude_service_js_1.default.listDocuments(args.projectId, args.versionUuid);
|
|
125
|
+
return formatOutput(documents, args);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'listPrompts', 'controllers/latitude.controller.ts@listPrompts', args.versionUuid, { args }));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function getPrompt(args) {
|
|
132
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'getPrompt');
|
|
133
|
+
methodLogger.debug(`Getting prompt: ${args.path}`);
|
|
134
|
+
try {
|
|
135
|
+
const document = await vendor_latitude_service_js_1.default.getDocument(args.projectId, args.versionUuid, args.path);
|
|
136
|
+
return formatOutput(document, args);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'getPrompt', 'controllers/latitude.controller.ts@getPrompt', args.path, { args }));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function pushPrompt(args) {
|
|
143
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'pushPrompt');
|
|
144
|
+
methodLogger.debug(`Pushing prompt: ${args.path}`);
|
|
145
|
+
try {
|
|
146
|
+
const document = await vendor_latitude_service_js_1.default.createOrUpdateDocument(args.projectId, args.versionUuid, args.path, args.content, args.force);
|
|
147
|
+
return formatOutput(document, args);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'pushPrompt', 'controllers/latitude.controller.ts@pushPrompt', args.path, { args }));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function pushPromptFromFile(args) {
|
|
154
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'pushPromptFromFile');
|
|
155
|
+
// Resolve and validate file path
|
|
156
|
+
const absolutePath = (0, path_1.resolve)(args.filePath);
|
|
157
|
+
if (!(0, fs_1.existsSync)(absolutePath)) {
|
|
158
|
+
throw new Error(`File not found: ${absolutePath}`);
|
|
159
|
+
}
|
|
160
|
+
// Read file content
|
|
161
|
+
const content = (0, fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
162
|
+
// Derive prompt path from filename if not provided
|
|
163
|
+
const promptPath = args.promptPath || derivePromptPath(args.filePath);
|
|
164
|
+
methodLogger.debug(`Pushing prompt from file: ${absolutePath} → ${promptPath}`);
|
|
165
|
+
try {
|
|
166
|
+
const document = await vendor_latitude_service_js_1.default.createOrUpdateDocument(args.projectId, args.versionUuid, promptPath, content, args.force);
|
|
167
|
+
// Include file info in response
|
|
168
|
+
const result = {
|
|
169
|
+
...document,
|
|
170
|
+
_meta: {
|
|
171
|
+
sourceFile: absolutePath,
|
|
172
|
+
promptPath,
|
|
173
|
+
contentLength: content.length,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
return formatOutput(result, args);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'pushPromptFromFile', 'controllers/latitude.controller.ts@pushPromptFromFile', absolutePath, { args }));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function runPrompt(args) {
|
|
183
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'runPrompt');
|
|
184
|
+
methodLogger.debug(`Running prompt: ${args.path}`);
|
|
185
|
+
try {
|
|
186
|
+
const result = await vendor_latitude_service_js_1.default.runDocument(args.projectId, args.versionUuid, {
|
|
187
|
+
path: args.path,
|
|
188
|
+
parameters: args.parameters,
|
|
189
|
+
stream: args.stream,
|
|
190
|
+
tools: args.tools,
|
|
191
|
+
userMessage: args.userMessage,
|
|
192
|
+
});
|
|
193
|
+
// Handle streaming response
|
|
194
|
+
if (args.stream && result && typeof result === 'object' && Symbol.asyncIterator in result) {
|
|
195
|
+
const chunks = [];
|
|
196
|
+
for await (const chunk of result) {
|
|
197
|
+
chunks.push(chunk);
|
|
198
|
+
}
|
|
199
|
+
return { content: chunks.join('') };
|
|
200
|
+
}
|
|
201
|
+
return formatOutput(result, args);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'runPrompt', 'controllers/latitude.controller.ts@runPrompt', args.path, { args }));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function createLog(args) {
|
|
208
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'createLog');
|
|
209
|
+
methodLogger.debug(`Creating log for: ${args.path}`);
|
|
210
|
+
try {
|
|
211
|
+
const result = await vendor_latitude_service_js_1.default.createDocumentLog(args.projectId, args.versionUuid, args.path, args.messages);
|
|
212
|
+
return formatOutput(result, args);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'createLog', 'controllers/latitude.controller.ts@createLog', args.path, { args }));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// ============================================================================
|
|
219
|
+
// Conversations Controller
|
|
220
|
+
// ============================================================================
|
|
221
|
+
async function getConversation(args) {
|
|
222
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'getConversation');
|
|
223
|
+
methodLogger.debug(`Getting conversation: ${args.conversationUuid}`);
|
|
224
|
+
try {
|
|
225
|
+
const conversation = await vendor_latitude_service_js_1.default.getConversation(args.conversationUuid);
|
|
226
|
+
return formatOutput(conversation, args);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'getConversation', 'controllers/latitude.controller.ts@getConversation', args.conversationUuid, { args }));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function chat(args) {
|
|
233
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'chat');
|
|
234
|
+
methodLogger.debug(`Chatting in conversation: ${args.conversationUuid}`);
|
|
235
|
+
try {
|
|
236
|
+
const messages = [{ role: 'user', content: args.message }];
|
|
237
|
+
const result = await vendor_latitude_service_js_1.default.chatConversation(args.conversationUuid, messages, args.stream);
|
|
238
|
+
// Handle streaming response
|
|
239
|
+
if (args.stream && result && typeof result === 'object' && Symbol.asyncIterator in result) {
|
|
240
|
+
const chunks = [];
|
|
241
|
+
for await (const chunk of result) {
|
|
242
|
+
chunks.push(chunk);
|
|
243
|
+
}
|
|
244
|
+
return { content: chunks.join('') };
|
|
245
|
+
}
|
|
246
|
+
return formatOutput(result, args);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'chat', 'controllers/latitude.controller.ts@chat', args.conversationUuid, { args }));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function stopConversation(args) {
|
|
253
|
+
const methodLogger = logger_util_js_1.Logger.forContext('controllers/latitude.controller.ts', 'stopConversation');
|
|
254
|
+
methodLogger.debug(`Stopping conversation: ${args.conversationUuid}`);
|
|
255
|
+
try {
|
|
256
|
+
const result = await vendor_latitude_service_js_1.default.stopConversation(args.conversationUuid);
|
|
257
|
+
return formatOutput(result, args);
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_1.buildErrorContext)('Latitude', 'stopConversation', 'controllers/latitude.controller.ts@stopConversation', args.conversationUuid, { args }));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// ============================================================================
|
|
264
|
+
// Export Controller
|
|
265
|
+
// ============================================================================
|
|
266
|
+
exports.default = {
|
|
267
|
+
// Projects
|
|
268
|
+
listProjects,
|
|
269
|
+
createProject,
|
|
270
|
+
// Versions
|
|
271
|
+
listVersions,
|
|
272
|
+
getVersion,
|
|
273
|
+
createVersion,
|
|
274
|
+
publishVersion,
|
|
275
|
+
pushChanges,
|
|
276
|
+
// Documents/Prompts
|
|
277
|
+
listPrompts,
|
|
278
|
+
getPrompt,
|
|
279
|
+
pushPrompt,
|
|
280
|
+
pushPromptFromFile,
|
|
281
|
+
runPrompt,
|
|
282
|
+
createLog,
|
|
283
|
+
// Conversations
|
|
284
|
+
getConversation,
|
|
285
|
+
chat,
|
|
286
|
+
stopConversation,
|
|
287
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.startServer = startServer;
|
|
8
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
9
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
10
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
11
|
+
const logger_util_js_1 = require("./utils/logger.util.js");
|
|
12
|
+
const config_util_js_1 = require("./utils/config.util.js");
|
|
13
|
+
const constants_util_js_1 = require("./utils/constants.util.js");
|
|
14
|
+
const index_js_1 = require("./cli/index.js");
|
|
15
|
+
const express_1 = __importDefault(require("express"));
|
|
16
|
+
const cors_1 = __importDefault(require("cors"));
|
|
17
|
+
// Import tools and resources
|
|
18
|
+
const latitude_tool_js_1 = __importDefault(require("./tools/latitude.tool.js"));
|
|
19
|
+
const latitude_resource_js_1 = __importDefault(require("./resources/latitude.resource.js"));
|
|
20
|
+
const logger = logger_util_js_1.Logger.forContext('index.ts');
|
|
21
|
+
let serverInstance = null;
|
|
22
|
+
let transportInstance = null;
|
|
23
|
+
/**
|
|
24
|
+
* Start the MCP server with the specified transport mode
|
|
25
|
+
*/
|
|
26
|
+
async function startServer(mode = 'stdio') {
|
|
27
|
+
logger.info(`Starting MCP server in ${mode} mode with ${constants_util_js_1.PACKAGE_NAME} v${constants_util_js_1.VERSION}`);
|
|
28
|
+
const serverLogger = logger_util_js_1.Logger.forContext('index.ts', 'startServer');
|
|
29
|
+
// Load configuration
|
|
30
|
+
serverLogger.info('Starting MCP server initialization...');
|
|
31
|
+
config_util_js_1.config.load();
|
|
32
|
+
if (config_util_js_1.config.getBoolean('DEBUG')) {
|
|
33
|
+
serverLogger.debug('Debug mode enabled');
|
|
34
|
+
}
|
|
35
|
+
serverLogger.info(`Initializing Latitude MCP server v${constants_util_js_1.VERSION}`);
|
|
36
|
+
serverInstance = new mcp_js_1.McpServer({
|
|
37
|
+
name: constants_util_js_1.PACKAGE_NAME,
|
|
38
|
+
version: constants_util_js_1.VERSION,
|
|
39
|
+
});
|
|
40
|
+
// Register tools and resources
|
|
41
|
+
serverLogger.info('Registering MCP tools and resources...');
|
|
42
|
+
latitude_tool_js_1.default.registerTools(serverInstance);
|
|
43
|
+
latitude_resource_js_1.default.registerResources(serverInstance);
|
|
44
|
+
serverLogger.debug('All Latitude tools and resources registered');
|
|
45
|
+
if (mode === 'stdio') {
|
|
46
|
+
serverLogger.info('Using STDIO transport');
|
|
47
|
+
transportInstance = new stdio_js_1.StdioServerTransport();
|
|
48
|
+
try {
|
|
49
|
+
await serverInstance.connect(transportInstance);
|
|
50
|
+
serverLogger.info('MCP server started successfully on STDIO transport');
|
|
51
|
+
setupGracefulShutdown();
|
|
52
|
+
return serverInstance;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
serverLogger.error('Failed to start server on STDIO transport', err);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// HTTP transport with Express
|
|
61
|
+
serverLogger.info('Using Streamable HTTP transport');
|
|
62
|
+
const app = (0, express_1.default)();
|
|
63
|
+
app.use((0, cors_1.default)());
|
|
64
|
+
app.use(express_1.default.json());
|
|
65
|
+
const mcpEndpoint = '/mcp';
|
|
66
|
+
serverLogger.debug(`MCP endpoint: ${mcpEndpoint}`);
|
|
67
|
+
// Create transport instance
|
|
68
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
69
|
+
// sessionIdGenerator is optional
|
|
70
|
+
sessionIdGenerator: undefined,
|
|
71
|
+
});
|
|
72
|
+
// Connect server to transport
|
|
73
|
+
await serverInstance.connect(transport);
|
|
74
|
+
transportInstance = transport;
|
|
75
|
+
// Handle all MCP requests
|
|
76
|
+
app.all(mcpEndpoint, (req, res) => {
|
|
77
|
+
transport
|
|
78
|
+
.handleRequest(req, res, req.body)
|
|
79
|
+
.catch((err) => {
|
|
80
|
+
serverLogger.error('Error in transport.handleRequest', err);
|
|
81
|
+
if (!res.headersSent) {
|
|
82
|
+
res.status(500).json({
|
|
83
|
+
error: 'Internal Server Error',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
// Health check endpoint
|
|
89
|
+
app.get('/', (_req, res) => {
|
|
90
|
+
res.send(`Latitude MCP Server v${constants_util_js_1.VERSION} is running`);
|
|
91
|
+
});
|
|
92
|
+
// Start HTTP server
|
|
93
|
+
const PORT = Number(process.env.PORT ?? 3000);
|
|
94
|
+
await new Promise((resolve) => {
|
|
95
|
+
app.listen(PORT, () => {
|
|
96
|
+
serverLogger.info(`HTTP transport listening on http://localhost:${PORT}${mcpEndpoint}`);
|
|
97
|
+
resolve();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
setupGracefulShutdown();
|
|
101
|
+
return serverInstance;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Main entry point
|
|
106
|
+
*/
|
|
107
|
+
async function main() {
|
|
108
|
+
const mainLogger = logger_util_js_1.Logger.forContext('index.ts', 'main');
|
|
109
|
+
// Load configuration
|
|
110
|
+
config_util_js_1.config.load();
|
|
111
|
+
// CLI mode - if any arguments are provided
|
|
112
|
+
if (process.argv.length > 2) {
|
|
113
|
+
mainLogger.info('CLI mode detected');
|
|
114
|
+
await (0, index_js_1.runCli)(process.argv.slice(2));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Server mode - determine transport
|
|
118
|
+
const transportMode = (process.env.TRANSPORT_MODE || 'stdio').toLowerCase();
|
|
119
|
+
let mode;
|
|
120
|
+
if (transportMode === 'stdio') {
|
|
121
|
+
mode = 'stdio';
|
|
122
|
+
}
|
|
123
|
+
else if (transportMode === 'http') {
|
|
124
|
+
mode = 'http';
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
mainLogger.warn(`Unknown TRANSPORT_MODE "${transportMode}", defaulting to stdio`);
|
|
128
|
+
mode = 'stdio';
|
|
129
|
+
}
|
|
130
|
+
mainLogger.info(`Starting server with ${mode.toUpperCase()} transport`);
|
|
131
|
+
await startServer(mode);
|
|
132
|
+
}
|
|
133
|
+
// Run main if executed directly
|
|
134
|
+
if (require.main === module) {
|
|
135
|
+
main().catch((err) => {
|
|
136
|
+
logger.error('Unhandled error in main process', err);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Graceful shutdown handler
|
|
142
|
+
*/
|
|
143
|
+
function setupGracefulShutdown() {
|
|
144
|
+
const shutdownLogger = logger_util_js_1.Logger.forContext('index.ts', 'shutdown');
|
|
145
|
+
const shutdown = async () => {
|
|
146
|
+
try {
|
|
147
|
+
shutdownLogger.info('Shutting down gracefully...');
|
|
148
|
+
if (transportInstance &&
|
|
149
|
+
'close' in transportInstance &&
|
|
150
|
+
typeof transportInstance.close === 'function') {
|
|
151
|
+
await transportInstance.close();
|
|
152
|
+
}
|
|
153
|
+
if (serverInstance && typeof serverInstance.close === 'function') {
|
|
154
|
+
await serverInstance.close();
|
|
155
|
+
}
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
shutdownLogger.error('Error during shutdown', err);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
['SIGINT', 'SIGTERM'].forEach((signal) => {
|
|
164
|
+
process.on(signal, shutdown);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Register Latitude resources with the MCP server
|
|
4
|
+
* Resources provide read-only access to Latitude data
|
|
5
|
+
*
|
|
6
|
+
* @param server The MCP server instance
|
|
7
|
+
*/
|
|
8
|
+
declare function registerResources(server: McpServer): void;
|
|
9
|
+
declare const _default: {
|
|
10
|
+
registerResources: typeof registerResources;
|
|
11
|
+
};
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
7
|
+
const logger_util_js_1 = require("../utils/logger.util.js");
|
|
8
|
+
const latitude_controller_js_1 = __importDefault(require("../controllers/latitude.controller.js"));
|
|
9
|
+
const error_util_js_1 = require("../utils/error.util.js");
|
|
10
|
+
const logger = logger_util_js_1.Logger.forContext('resources/latitude.resource.ts');
|
|
11
|
+
/**
|
|
12
|
+
* Register Latitude resources with the MCP server
|
|
13
|
+
* Resources provide read-only access to Latitude data
|
|
14
|
+
*
|
|
15
|
+
* @param server The MCP server instance
|
|
16
|
+
*/
|
|
17
|
+
function registerResources(server) {
|
|
18
|
+
const registerLogger = logger.forMethod('registerResources');
|
|
19
|
+
registerLogger.debug('Registering Latitude resources...');
|
|
20
|
+
// Projects resource - list all projects
|
|
21
|
+
server.registerResource('latitude-projects', new mcp_js_1.ResourceTemplate('latitude://projects', { list: undefined }), {
|
|
22
|
+
title: 'Latitude Projects',
|
|
23
|
+
description: 'List all projects in your Latitude workspace',
|
|
24
|
+
}, async (uri) => {
|
|
25
|
+
const methodLogger = logger.forMethod('projectsResource');
|
|
26
|
+
try {
|
|
27
|
+
methodLogger.debug('Projects resource called', { uri: uri.href });
|
|
28
|
+
const result = await latitude_controller_js_1.default.listProjects();
|
|
29
|
+
return {
|
|
30
|
+
contents: [
|
|
31
|
+
{
|
|
32
|
+
uri: uri.href,
|
|
33
|
+
text: result.content,
|
|
34
|
+
mimeType: 'application/json',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
methodLogger.error('Resource error', error);
|
|
41
|
+
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.href);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// Versions resource - list versions for a project
|
|
45
|
+
server.registerResource('latitude-versions', new mcp_js_1.ResourceTemplate('latitude://projects/{projectId}/versions', {
|
|
46
|
+
list: undefined,
|
|
47
|
+
}), {
|
|
48
|
+
title: 'Project Versions',
|
|
49
|
+
description: 'List all versions (commits) for a Latitude project',
|
|
50
|
+
}, async (uri, variables) => {
|
|
51
|
+
const methodLogger = logger.forMethod('versionsResource');
|
|
52
|
+
try {
|
|
53
|
+
const projectId = variables.projectId;
|
|
54
|
+
methodLogger.debug('Versions resource called', {
|
|
55
|
+
uri: uri.href,
|
|
56
|
+
projectId,
|
|
57
|
+
});
|
|
58
|
+
const result = await latitude_controller_js_1.default.listVersions({ projectId });
|
|
59
|
+
return {
|
|
60
|
+
contents: [
|
|
61
|
+
{
|
|
62
|
+
uri: uri.href,
|
|
63
|
+
text: result.content,
|
|
64
|
+
mimeType: 'application/json',
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
methodLogger.error('Resource error', error);
|
|
71
|
+
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.href);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// Prompts resource - list prompts for a version
|
|
75
|
+
server.registerResource('latitude-prompts', new mcp_js_1.ResourceTemplate('latitude://projects/{projectId}/versions/{versionUuid}/prompts', { list: undefined }), {
|
|
76
|
+
title: 'Version Prompts',
|
|
77
|
+
description: 'List all prompts/documents in a Latitude project version',
|
|
78
|
+
}, async (uri, variables) => {
|
|
79
|
+
const methodLogger = logger.forMethod('promptsResource');
|
|
80
|
+
try {
|
|
81
|
+
const projectId = variables.projectId;
|
|
82
|
+
const versionUuid = variables.versionUuid || 'live';
|
|
83
|
+
methodLogger.debug('Prompts resource called', {
|
|
84
|
+
uri: uri.href,
|
|
85
|
+
projectId,
|
|
86
|
+
versionUuid,
|
|
87
|
+
});
|
|
88
|
+
const result = await latitude_controller_js_1.default.listPrompts({
|
|
89
|
+
projectId,
|
|
90
|
+
versionUuid,
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
contents: [
|
|
94
|
+
{
|
|
95
|
+
uri: uri.href,
|
|
96
|
+
text: result.content,
|
|
97
|
+
mimeType: 'application/json',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
methodLogger.error('Resource error', error);
|
|
104
|
+
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.href);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// Single prompt resource - get a specific prompt
|
|
108
|
+
server.registerResource('latitude-prompt', new mcp_js_1.ResourceTemplate('latitude://projects/{projectId}/versions/{versionUuid}/prompts/{path}', { list: undefined }), {
|
|
109
|
+
title: 'Prompt Content',
|
|
110
|
+
description: 'Get a specific prompt by path from a Latitude project',
|
|
111
|
+
}, async (uri, variables) => {
|
|
112
|
+
const methodLogger = logger.forMethod('promptResource');
|
|
113
|
+
try {
|
|
114
|
+
const projectId = variables.projectId;
|
|
115
|
+
const versionUuid = variables.versionUuid || 'live';
|
|
116
|
+
const path = variables.path;
|
|
117
|
+
methodLogger.debug('Prompt resource called', {
|
|
118
|
+
uri: uri.href,
|
|
119
|
+
projectId,
|
|
120
|
+
versionUuid,
|
|
121
|
+
path,
|
|
122
|
+
});
|
|
123
|
+
const result = await latitude_controller_js_1.default.getPrompt({
|
|
124
|
+
projectId,
|
|
125
|
+
versionUuid,
|
|
126
|
+
path,
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
contents: [
|
|
130
|
+
{
|
|
131
|
+
uri: uri.href,
|
|
132
|
+
text: result.content,
|
|
133
|
+
mimeType: 'application/json',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
methodLogger.error('Resource error', error);
|
|
140
|
+
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.href);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
registerLogger.debug('Latitude resources registered successfully');
|
|
144
|
+
}
|
|
145
|
+
exports.default = { registerResources };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Project, Version, Document, Conversation, PushChanges } from '../types/latitude.types.js';
|
|
2
|
+
declare function listProjects(): Promise<Project[]>;
|
|
3
|
+
declare function createProject(name: string): Promise<Project>;
|
|
4
|
+
declare function listVersions(projectId: string): Promise<Version[]>;
|
|
5
|
+
declare function getVersion(projectId: string, versionUuid: string): Promise<Version>;
|
|
6
|
+
declare function createVersion(projectId: string, name: string): Promise<Version>;
|
|
7
|
+
declare function publishVersion(projectId: string, versionUuid: string, options?: {
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}): Promise<Version>;
|
|
11
|
+
declare function pushChanges(projectId: string, versionUuid: string, changes: PushChanges): Promise<unknown>;
|
|
12
|
+
declare function listDocuments(projectId: string, versionUuid: string): Promise<Document[]>;
|
|
13
|
+
declare function getDocument(projectId: string, versionUuid: string, path: string): Promise<Document>;
|
|
14
|
+
declare function createOrUpdateDocument(projectId: string, versionUuid: string, path: string, prompt: string, force?: boolean): Promise<Document>;
|
|
15
|
+
declare function runDocument(projectId: string, versionUuid: string, options: {
|
|
16
|
+
path: string;
|
|
17
|
+
parameters?: Record<string, unknown>;
|
|
18
|
+
stream?: boolean;
|
|
19
|
+
tools?: string[];
|
|
20
|
+
userMessage?: string;
|
|
21
|
+
}): Promise<unknown>;
|
|
22
|
+
declare function createDocumentLog(projectId: string, versionUuid: string, path: string, messages: Array<{
|
|
23
|
+
role: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>): Promise<unknown>;
|
|
26
|
+
declare function getConversation(conversationUuid: string): Promise<Conversation>;
|
|
27
|
+
declare function chatConversation(conversationUuid: string, messages: Array<{
|
|
28
|
+
role: string;
|
|
29
|
+
content: string;
|
|
30
|
+
}>, stream?: boolean): Promise<unknown>;
|
|
31
|
+
declare function stopConversation(conversationUuid: string): Promise<unknown>;
|
|
32
|
+
declare const _default: {
|
|
33
|
+
listProjects: typeof listProjects;
|
|
34
|
+
createProject: typeof createProject;
|
|
35
|
+
listVersions: typeof listVersions;
|
|
36
|
+
getVersion: typeof getVersion;
|
|
37
|
+
createVersion: typeof createVersion;
|
|
38
|
+
publishVersion: typeof publishVersion;
|
|
39
|
+
pushChanges: typeof pushChanges;
|
|
40
|
+
listDocuments: typeof listDocuments;
|
|
41
|
+
getDocument: typeof getDocument;
|
|
42
|
+
createOrUpdateDocument: typeof createOrUpdateDocument;
|
|
43
|
+
runDocument: typeof runDocument;
|
|
44
|
+
createDocumentLog: typeof createDocumentLog;
|
|
45
|
+
getConversation: typeof getConversation;
|
|
46
|
+
chatConversation: typeof chatConversation;
|
|
47
|
+
stopConversation: typeof stopConversation;
|
|
48
|
+
};
|
|
49
|
+
export default _default;
|