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,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
+ };
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ /**
4
+ * Start the MCP server with the specified transport mode
5
+ */
6
+ export declare function startServer(mode?: 'stdio' | 'http'): Promise<McpServer>;
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;