@synth-coder/memhub 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/contracts/mcp.d.ts +2 -112
- package/dist/src/contracts/mcp.d.ts.map +1 -1
- package/dist/src/contracts/mcp.js +8 -30
- package/dist/src/contracts/mcp.js.map +1 -1
- package/dist/src/server/mcp-server.d.ts +4 -74
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/mcp-server.js +55 -209
- package/dist/src/server/mcp-server.js.map +1 -1
- package/docs/proposals/mcp-typescript-sdk-refactor.md +568 -0
- package/package.json +4 -3
- package/src/contracts/mcp.ts +10 -145
- package/src/server/mcp-server.ts +64 -274
- package/test/server/mcp-server.test.ts +78 -8
- package/test/server/mcp-server-internals.test.ts +0 -257
package/src/contracts/mcp.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP (Model Context Protocol) specific types and constants
|
|
3
|
-
*
|
|
3
|
+
* Tool definitions and business-level types (protocol types provided by SDK)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { Memory } from './types.js';
|
|
@@ -19,86 +19,7 @@ export const SERVER_INFO = {
|
|
|
19
19
|
} as const;
|
|
20
20
|
|
|
21
21
|
// ============================================================================
|
|
22
|
-
// MCP
|
|
23
|
-
// ============================================================================
|
|
24
|
-
|
|
25
|
-
/** JSON-RPC request ID */
|
|
26
|
-
export type RequestId = string | number;
|
|
27
|
-
|
|
28
|
-
/** Base JSON-RPC request structure */
|
|
29
|
-
export interface JsonRpcRequest<T = unknown> {
|
|
30
|
-
jsonrpc: '2.0';
|
|
31
|
-
id?: RequestId;
|
|
32
|
-
method: string;
|
|
33
|
-
params?: T;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Base JSON-RPC response structure */
|
|
37
|
-
export interface JsonRpcResponse<T = unknown> {
|
|
38
|
-
jsonrpc: '2.0';
|
|
39
|
-
id: RequestId | null;
|
|
40
|
-
result?: T;
|
|
41
|
-
error?: JsonRpcError;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** JSON-RPC error structure */
|
|
45
|
-
export interface JsonRpcError {
|
|
46
|
-
code: number;
|
|
47
|
-
message: string;
|
|
48
|
-
data?: unknown;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** JSON-RPC notification (no response expected) */
|
|
52
|
-
export interface JsonRpcNotification<T = unknown> {
|
|
53
|
-
jsonrpc: '2.0';
|
|
54
|
-
method: string;
|
|
55
|
-
params?: T;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ============================================================================
|
|
59
|
-
// MCP Lifecycle Messages
|
|
60
|
-
// ============================================================================
|
|
61
|
-
|
|
62
|
-
/** Initialize request parameters */
|
|
63
|
-
export interface InitializeParams {
|
|
64
|
-
protocolVersion: string;
|
|
65
|
-
capabilities: ClientCapabilities;
|
|
66
|
-
clientInfo: Implementation;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Initialize result */
|
|
70
|
-
export interface InitializeResult {
|
|
71
|
-
protocolVersion: string;
|
|
72
|
-
capabilities: ServerCapabilities;
|
|
73
|
-
serverInfo: Implementation;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Implementation information */
|
|
77
|
-
export interface Implementation {
|
|
78
|
-
name: string;
|
|
79
|
-
version: string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Client capabilities */
|
|
83
|
-
export interface ClientCapabilities {
|
|
84
|
-
// Client can handle these features
|
|
85
|
-
readonly experimental?: Record<string, unknown>;
|
|
86
|
-
readonly roots?: { listChanged?: boolean };
|
|
87
|
-
readonly sampling?: Record<string, unknown>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** Server capabilities */
|
|
91
|
-
export interface ServerCapabilities {
|
|
92
|
-
// Server provides these features
|
|
93
|
-
readonly experimental?: Record<string, unknown>;
|
|
94
|
-
readonly logging?: Record<string, unknown>;
|
|
95
|
-
readonly prompts?: { listChanged?: boolean };
|
|
96
|
-
readonly resources?: { subscribe?: boolean; listChanged?: boolean };
|
|
97
|
-
readonly tools?: { listChanged?: boolean };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ============================================================================
|
|
101
|
-
// MCP Tool Definitions
|
|
22
|
+
// MCP Tool Definitions (kept for SDK use)
|
|
102
23
|
// ============================================================================
|
|
103
24
|
|
|
104
25
|
/** Tool definition for tool/list */
|
|
@@ -116,34 +37,6 @@ export interface ToolInputSchema {
|
|
|
116
37
|
additionalProperties?: boolean;
|
|
117
38
|
}
|
|
118
39
|
|
|
119
|
-
/** Tool call request */
|
|
120
|
-
export interface ToolCallRequest {
|
|
121
|
-
name: string;
|
|
122
|
-
arguments?: Record<string, unknown>;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** Tool call result */
|
|
126
|
-
export interface ToolCallResult {
|
|
127
|
-
content: ToolContent[];
|
|
128
|
-
isError?: boolean;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Tool content types */
|
|
132
|
-
export type ToolContent = TextContent | ImageContent;
|
|
133
|
-
|
|
134
|
-
/** Text content */
|
|
135
|
-
export interface TextContent {
|
|
136
|
-
type: 'text';
|
|
137
|
-
text: string;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Image content */
|
|
141
|
-
export interface ImageContent {
|
|
142
|
-
type: 'image';
|
|
143
|
-
data: string; // base64 encoded
|
|
144
|
-
mimeType: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
40
|
// ============================================================================
|
|
148
41
|
// MCP Tool List
|
|
149
42
|
// ============================================================================
|
|
@@ -209,41 +102,9 @@ export const TOOL_DEFINITIONS: readonly Tool[] = [
|
|
|
209
102
|
] as const;
|
|
210
103
|
|
|
211
104
|
// ============================================================================
|
|
212
|
-
//
|
|
213
|
-
// ============================================================================
|
|
214
|
-
|
|
215
|
-
/** All MCP method names */
|
|
216
|
-
export const MCP_METHODS = {
|
|
217
|
-
// Lifecycle
|
|
218
|
-
INITIALIZE: 'initialize',
|
|
219
|
-
INITIALIZED: 'notifications/initialized',
|
|
220
|
-
SHUTDOWN: 'shutdown',
|
|
221
|
-
EXIT: 'exit',
|
|
222
|
-
|
|
223
|
-
// Tools
|
|
224
|
-
TOOLS_LIST: 'tools/list',
|
|
225
|
-
TOOLS_CALL: 'tools/call',
|
|
226
|
-
|
|
227
|
-
// Logging
|
|
228
|
-
LOGGING_MESSAGE: 'notifications/message',
|
|
229
|
-
|
|
230
|
-
// Progress
|
|
231
|
-
PROGRESS: 'notifications/progress',
|
|
232
|
-
} as const;
|
|
233
|
-
|
|
234
|
-
// ============================================================================
|
|
235
|
-
// Error Codes (Standard MCP + Custom)
|
|
105
|
+
// Error Codes (MemHub Custom)
|
|
236
106
|
// ============================================================================
|
|
237
107
|
|
|
238
|
-
/** Standard JSON-RPC error codes */
|
|
239
|
-
export const JSONRPC_ERROR_CODES = {
|
|
240
|
-
PARSE_ERROR: -32700,
|
|
241
|
-
INVALID_REQUEST: -32600,
|
|
242
|
-
METHOD_NOT_FOUND: -32601,
|
|
243
|
-
INVALID_PARAMS: -32602,
|
|
244
|
-
INTERNAL_ERROR: -32603,
|
|
245
|
-
} as const;
|
|
246
|
-
|
|
247
108
|
/** MemHub custom error codes */
|
|
248
109
|
export const MEMHUB_ERROR_CODES = {
|
|
249
110
|
NOT_FOUND: -32001,
|
|
@@ -252,9 +113,13 @@ export const MEMHUB_ERROR_CODES = {
|
|
|
252
113
|
DUPLICATE_ERROR: -32004,
|
|
253
114
|
} as const;
|
|
254
115
|
|
|
255
|
-
/** Combined error codes */
|
|
116
|
+
/** Combined error codes (includes JSON-RPC standard codes) */
|
|
256
117
|
export const ERROR_CODES = {
|
|
257
|
-
|
|
118
|
+
PARSE_ERROR: -32700,
|
|
119
|
+
INVALID_REQUEST: -32600,
|
|
120
|
+
METHOD_NOT_FOUND: -32601,
|
|
121
|
+
INVALID_PARAMS: -32602,
|
|
122
|
+
INTERNAL_ERROR: -32603,
|
|
258
123
|
...MEMHUB_ERROR_CODES,
|
|
259
124
|
} as const;
|
|
260
125
|
|
|
@@ -300,4 +165,4 @@ export type ToolInput<T extends ToolName> = T extends 'memory_load'
|
|
|
300
165
|
category?: string;
|
|
301
166
|
importance?: number;
|
|
302
167
|
}
|
|
303
|
-
: never;
|
|
168
|
+
: never;
|
package/src/server/mcp-server.ts
CHANGED
|
@@ -1,36 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* MCP Server - Model Context Protocol server implementation
|
|
4
|
-
*
|
|
4
|
+
* Uses @modelcontextprotocol/sdk for protocol handling
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { readFileSync } from 'fs';
|
|
8
8
|
import { join, dirname } from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
JsonRpcResponse,
|
|
13
|
-
JsonRpcError,
|
|
14
|
-
RequestId,
|
|
15
|
-
InitializeParams,
|
|
16
|
-
InitializeResult,
|
|
17
|
-
ToolCallRequest,
|
|
18
|
-
ToolCallResult,
|
|
19
|
-
TextContent,
|
|
20
|
-
} from '../contracts/mcp.js';
|
|
10
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
21
12
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
MCP_METHODS,
|
|
26
|
-
ERROR_CODES,
|
|
27
|
-
} from '../contracts/mcp.js';
|
|
28
|
-
import { ErrorCode } from '../contracts/types.js';
|
|
13
|
+
CallToolRequestSchema,
|
|
14
|
+
ListToolsRequestSchema,
|
|
15
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
29
16
|
import { MemoryService, ServiceError } from '../services/memory-service.js';
|
|
30
17
|
import {
|
|
31
18
|
MemoryLoadInputSchema,
|
|
32
19
|
MemoryUpdateInputV2Schema,
|
|
33
20
|
} from '../contracts/schemas.js';
|
|
21
|
+
import { TOOL_DEFINITIONS, SERVER_INFO } from '../contracts/mcp.js';
|
|
22
|
+
import { ErrorCode } from '../contracts/types.js';
|
|
34
23
|
|
|
35
24
|
// Get package version
|
|
36
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -45,164 +34,34 @@ const packageJsonPath = join(__dirname, '../../../package.json');
|
|
|
45
34
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as PackageJson;
|
|
46
35
|
|
|
47
36
|
/**
|
|
48
|
-
*
|
|
37
|
+
* Create McpServer instance using SDK
|
|
49
38
|
*/
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
start(): void {
|
|
62
|
-
this.log('info', 'MemHub MCP Server starting...');
|
|
63
|
-
|
|
64
|
-
process.stdin.setEncoding('utf-8');
|
|
65
|
-
|
|
66
|
-
let buffer = '';
|
|
67
|
-
|
|
68
|
-
process.stdin.on('data', (chunk: string) => {
|
|
69
|
-
buffer += chunk;
|
|
70
|
-
|
|
71
|
-
// Process complete lines (JSON-RPC messages)
|
|
72
|
-
const lines = buffer.split('\n');
|
|
73
|
-
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
74
|
-
|
|
75
|
-
for (const line of lines) {
|
|
76
|
-
if (line.trim()) {
|
|
77
|
-
void this.handleMessage(line.trim());
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
process.stdin.on('end', () => {
|
|
83
|
-
this.log('info', 'Stdin closed, shutting down...');
|
|
84
|
-
process.exit(0);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
process.on('SIGINT', () => {
|
|
88
|
-
this.log('info', 'Received SIGINT, shutting down...');
|
|
89
|
-
process.exit(0);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
process.on('SIGTERM', () => {
|
|
93
|
-
this.log('info', 'Received SIGTERM, shutting down...');
|
|
94
|
-
process.exit(0);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Handles an incoming JSON-RPC message
|
|
100
|
-
*
|
|
101
|
-
* @param message - The JSON-RPC message string
|
|
102
|
-
*/
|
|
103
|
-
private async handleMessage(message: string): Promise<void> {
|
|
104
|
-
let request: JsonRpcRequest | null = null;
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
request = JSON.parse(message) as JsonRpcRequest;
|
|
108
|
-
} catch {
|
|
109
|
-
this.sendError(null, ERROR_CODES.PARSE_ERROR, 'Parse error: Invalid JSON');
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Validate JSON-RPC request
|
|
114
|
-
if (request.jsonrpc !== '2.0' || !request.method) {
|
|
115
|
-
this.sendError(
|
|
116
|
-
request.id ?? null,
|
|
117
|
-
ERROR_CODES.INVALID_REQUEST,
|
|
118
|
-
'Invalid Request'
|
|
119
|
-
);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const result = await this.handleMethod(request.method, request.params);
|
|
125
|
-
|
|
126
|
-
// Send response (only for requests with id, not notifications)
|
|
127
|
-
if (request.id !== undefined) {
|
|
128
|
-
this.sendResponse(request.id, result);
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
this.handleError(request.id ?? null, error);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Handles a specific method call
|
|
137
|
-
*
|
|
138
|
-
* @param method - The method name
|
|
139
|
-
* @param params - The method parameters
|
|
140
|
-
* @returns The method result
|
|
141
|
-
*/
|
|
142
|
-
private async handleMethod(
|
|
143
|
-
method: string,
|
|
144
|
-
params: unknown
|
|
145
|
-
): Promise<unknown> {
|
|
146
|
-
switch (method) {
|
|
147
|
-
case MCP_METHODS.INITIALIZE:
|
|
148
|
-
return this.handleInitialize(params as InitializeParams);
|
|
149
|
-
|
|
150
|
-
case MCP_METHODS.INITIALIZED:
|
|
151
|
-
// Notification, no response needed
|
|
152
|
-
this.log('info', 'Client initialized');
|
|
153
|
-
return null;
|
|
154
|
-
|
|
155
|
-
case MCP_METHODS.SHUTDOWN:
|
|
156
|
-
return null;
|
|
157
|
-
|
|
158
|
-
case MCP_METHODS.EXIT:
|
|
159
|
-
process.exit(0);
|
|
160
|
-
return null;
|
|
161
|
-
|
|
162
|
-
case MCP_METHODS.TOOLS_LIST:
|
|
163
|
-
return { tools: TOOL_DEFINITIONS };
|
|
164
|
-
|
|
165
|
-
case MCP_METHODS.TOOLS_CALL:
|
|
166
|
-
return this.handleToolCall(params as ToolCallRequest);
|
|
167
|
-
|
|
168
|
-
default:
|
|
169
|
-
throw new ServiceError(
|
|
170
|
-
`Method not found: ${method}`,
|
|
171
|
-
ErrorCode.METHOD_NOT_FOUND
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Handles the initialize method
|
|
178
|
-
*
|
|
179
|
-
* @param params - Initialize parameters
|
|
180
|
-
* @returns Initialize result
|
|
181
|
-
*/
|
|
182
|
-
private handleInitialize(params: InitializeParams): InitializeResult {
|
|
183
|
-
this.log('info', `Client initializing: ${params.clientInfo.name} v${params.clientInfo.version}`);
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
39
|
+
export function createMcpServer(): Server {
|
|
40
|
+
const storagePath = process.env.MEMHUB_STORAGE_PATH || './memories';
|
|
41
|
+
const memoryService = new MemoryService({ storagePath });
|
|
42
|
+
|
|
43
|
+
// Create server using SDK
|
|
44
|
+
const server = new Server(
|
|
45
|
+
{
|
|
46
|
+
name: SERVER_INFO.name,
|
|
47
|
+
version: packageJson.version || SERVER_INFO.version,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
187
50
|
capabilities: {
|
|
188
51
|
tools: { listChanged: false },
|
|
189
52
|
logging: {},
|
|
190
53
|
},
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Handle tools/list request
|
|
58
|
+
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
59
|
+
return { tools: TOOL_DEFINITIONS };
|
|
60
|
+
});
|
|
197
61
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
* @param request - Tool call request
|
|
202
|
-
* @returns Tool call result
|
|
203
|
-
*/
|
|
204
|
-
private async handleToolCall(request: ToolCallRequest): Promise<ToolCallResult> {
|
|
205
|
-
const { name, arguments: args } = request;
|
|
62
|
+
// Handle tools/call request
|
|
63
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
64
|
+
const { name, arguments: args } = request.params;
|
|
206
65
|
|
|
207
66
|
try {
|
|
208
67
|
let result: unknown;
|
|
@@ -210,13 +69,13 @@ export class McpServer {
|
|
|
210
69
|
switch (name) {
|
|
211
70
|
case 'memory_load': {
|
|
212
71
|
const input = MemoryLoadInputSchema.parse(args ?? {});
|
|
213
|
-
result = await
|
|
72
|
+
result = await memoryService.memoryLoad(input);
|
|
214
73
|
break;
|
|
215
74
|
}
|
|
216
75
|
|
|
217
76
|
case 'memory_update': {
|
|
218
77
|
const input = MemoryUpdateInputV2Schema.parse(args ?? {});
|
|
219
|
-
result = await
|
|
78
|
+
result = await memoryService.memoryUpdate(input);
|
|
220
79
|
break;
|
|
221
80
|
}
|
|
222
81
|
|
|
@@ -230,9 +89,9 @@ export class McpServer {
|
|
|
230
89
|
return {
|
|
231
90
|
content: [
|
|
232
91
|
{
|
|
233
|
-
type: 'text',
|
|
92
|
+
type: 'text' as const,
|
|
234
93
|
text: JSON.stringify(result, null, 2),
|
|
235
|
-
}
|
|
94
|
+
},
|
|
236
95
|
],
|
|
237
96
|
};
|
|
238
97
|
} catch (error) {
|
|
@@ -240,115 +99,46 @@ export class McpServer {
|
|
|
240
99
|
return {
|
|
241
100
|
content: [
|
|
242
101
|
{
|
|
243
|
-
type: 'text',
|
|
102
|
+
type: 'text' as const,
|
|
244
103
|
text: JSON.stringify({ error: error.message }, null, 2),
|
|
245
|
-
}
|
|
104
|
+
},
|
|
246
105
|
],
|
|
247
106
|
isError: true,
|
|
248
107
|
};
|
|
249
108
|
}
|
|
250
109
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
110
|
+
if (error instanceof Error && error.name === 'ZodError') {
|
|
111
|
+
return {
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: 'text' as const,
|
|
115
|
+
text: JSON.stringify({ error: `Invalid parameters: ${error.message}` }, null, 2),
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
255
121
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
*
|
|
259
|
-
* @param id - Request ID
|
|
260
|
-
* @param error - The error that occurred
|
|
261
|
-
*/
|
|
262
|
-
private handleError(id: RequestId | null, error: unknown): void {
|
|
263
|
-
if (error instanceof ServiceError) {
|
|
264
|
-
this.sendError(id, error.code, error.message, error.data);
|
|
265
|
-
} else if (error instanceof Error && error.name === 'ZodError') {
|
|
266
|
-
this.sendError(
|
|
267
|
-
id,
|
|
268
|
-
ERROR_CODES.INVALID_PARAMS,
|
|
269
|
-
`Invalid parameters: ${error.message}`
|
|
270
|
-
);
|
|
271
|
-
} else {
|
|
272
|
-
this.sendError(
|
|
273
|
-
id,
|
|
274
|
-
ERROR_CODES.INTERNAL_ERROR,
|
|
275
|
-
`Internal error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
276
|
-
);
|
|
122
|
+
// Re-throw for SDK error handling
|
|
123
|
+
throw error;
|
|
277
124
|
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Sends a JSON-RPC response
|
|
282
|
-
*
|
|
283
|
-
* @param id - Request ID
|
|
284
|
-
* @param result - Response result
|
|
285
|
-
*/
|
|
286
|
-
private sendResponse(id: RequestId, result: unknown): void {
|
|
287
|
-
const response: JsonRpcResponse = {
|
|
288
|
-
jsonrpc: '2.0',
|
|
289
|
-
id,
|
|
290
|
-
result,
|
|
291
|
-
};
|
|
292
|
-
this.sendMessage(response);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Sends a JSON-RPC error
|
|
297
|
-
*
|
|
298
|
-
* @param id - Request ID
|
|
299
|
-
* @param code - Error code
|
|
300
|
-
* @param message - Error message
|
|
301
|
-
* @param data - Additional error data
|
|
302
|
-
*/
|
|
303
|
-
private sendError(
|
|
304
|
-
id: RequestId | null,
|
|
305
|
-
code: number,
|
|
306
|
-
message: string,
|
|
307
|
-
data?: Record<string, unknown>
|
|
308
|
-
): void {
|
|
309
|
-
const error: JsonRpcError = {
|
|
310
|
-
code,
|
|
311
|
-
message,
|
|
312
|
-
data,
|
|
313
|
-
};
|
|
125
|
+
});
|
|
314
126
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
id: id ?? null,
|
|
318
|
-
error,
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
this.sendMessage(response);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Sends a message to stdout
|
|
326
|
-
*
|
|
327
|
-
* @param message - The message to send
|
|
328
|
-
*/
|
|
329
|
-
private sendMessage(message: JsonRpcResponse | JsonRpcRequest): void {
|
|
330
|
-
const json = JSON.stringify(message);
|
|
331
|
-
process.stdout.write(json + '\n');
|
|
332
|
-
}
|
|
127
|
+
return server;
|
|
128
|
+
}
|
|
333
129
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
private log(level: 'debug' | 'info' | 'warn' | 'error', message: string): void {
|
|
341
|
-
const logLevel = process.env.MEMHUB_LOG_LEVEL || 'info';
|
|
342
|
-
const levels = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
130
|
+
/**
|
|
131
|
+
* Start the MCP server
|
|
132
|
+
*/
|
|
133
|
+
async function main(): Promise<void> {
|
|
134
|
+
const server = createMcpServer();
|
|
135
|
+
const transport = new StdioServerTransport();
|
|
343
136
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
}
|
|
137
|
+
await server.connect(transport);
|
|
138
|
+
console.error('MemHub MCP Server running on stdio');
|
|
348
139
|
}
|
|
349
140
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
141
|
+
main().catch((error) => {
|
|
142
|
+
console.error('Fatal error:', error);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
});
|