@proofofprotocol/inscribe-mcp 0.3.4 → 0.3.6
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/package.json +1 -1
- package/src/cli/commands/show.js +109 -37
- package/src/lib/logger.js +65 -4
- package/src/server.js +51 -10
package/package.json
CHANGED
package/src/cli/commands/show.js
CHANGED
|
@@ -317,75 +317,147 @@ export const showCommand = new Command('show')
|
|
|
317
317
|
// Debug trace section
|
|
318
318
|
if (options.debug) {
|
|
319
319
|
console.log('');
|
|
320
|
-
console.log(colors.bold('MCP Sequence Debug Traces'));
|
|
320
|
+
console.log(colors.bold('MCP Sequence Debug Traces (LAN Analyzer View)'));
|
|
321
321
|
console.log(line);
|
|
322
322
|
|
|
323
|
-
const traces = getDebugTraces(logsDir,
|
|
323
|
+
const traces = getDebugTraces(logsDir, 100);
|
|
324
324
|
|
|
325
325
|
if (traces.length === 0) {
|
|
326
326
|
console.log(colors.dim('No debug traces found.'));
|
|
327
327
|
console.log('');
|
|
328
|
-
console.log('To enable debug logging
|
|
329
|
-
console.log(colors.cyan('
|
|
328
|
+
console.log('To enable debug logging:');
|
|
329
|
+
console.log(colors.cyan(' inscribe-mcp debug on'));
|
|
330
330
|
console.log('');
|
|
331
|
-
console.log('
|
|
331
|
+
console.log('Or set environment variable:');
|
|
332
|
+
console.log(colors.cyan(' export INSCRIBE_MCP_DEBUG=1'));
|
|
332
333
|
} else {
|
|
333
334
|
const sequences = formatSequenceTrace(traces);
|
|
334
335
|
|
|
335
336
|
if (sequences.length === 0) {
|
|
336
337
|
console.log(colors.dim('No complete sequences found.'));
|
|
337
338
|
} else {
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
339
|
+
// LAN Analyzer style header
|
|
340
|
+
console.log('');
|
|
341
|
+
console.log(colors.dim('┌──────────────┬───────┬────────────────────┬───────────────────────────────────────┐'));
|
|
342
|
+
console.log(colors.dim('│ Timestamp │ Dir │ Phase │ Details │'));
|
|
343
|
+
console.log(colors.dim('├──────────────┼───────┼────────────────────┼───────────────────────────────────────┤'));
|
|
344
|
+
|
|
345
|
+
// Direction symbols
|
|
346
|
+
const dirSymbols = {
|
|
347
|
+
'IN': colors.green('←IN '),
|
|
348
|
+
'OUT': colors.cyan('→OUT'),
|
|
349
|
+
'ERR': colors.red('✗ERR')
|
|
344
350
|
};
|
|
345
351
|
|
|
346
352
|
const phaseLabels = {
|
|
347
353
|
'agent_to_mcp': 'Agent → MCP',
|
|
348
354
|
'mcp_to_chain': 'MCP → Chain',
|
|
349
355
|
'chain_to_mcp': 'Chain → MCP',
|
|
350
|
-
'mcp_to_agent': 'MCP → Agent'
|
|
356
|
+
'mcp_to_agent': 'MCP → Agent',
|
|
357
|
+
'mcp_error': 'MCP Error'
|
|
351
358
|
};
|
|
352
359
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
console.log('');
|
|
360
|
+
for (const seq of sequences.slice(-8)) { // Last 8 sequences
|
|
361
|
+
// Sequence header
|
|
362
|
+
const seqTime = new Date(seq.timestamp);
|
|
363
|
+
const timeStr = seqTime.toLocaleTimeString('en-US', { hour12: false });
|
|
364
|
+
const msStr = String(seqTime.getMilliseconds()).padStart(3, '0');
|
|
359
365
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
366
|
+
console.log(colors.dim('│') + colors.bold(` ${timeStr}.${msStr}`) + colors.dim(' │ │ ') +
|
|
367
|
+
colors.cyan(colors.bold(`[${seq.tool}]`)).padEnd(28) + colors.dim(' │') +
|
|
368
|
+
colors.dim(' ─────────────────────────────────────── │'));
|
|
363
369
|
|
|
364
370
|
for (const phase of seq.phases) {
|
|
365
|
-
const
|
|
366
|
-
const
|
|
367
|
-
|
|
371
|
+
const phaseTime = new Date(phase.timestamp);
|
|
372
|
+
const pTimeStr = phaseTime.toLocaleTimeString('en-US', { hour12: false });
|
|
373
|
+
const pMsStr = String(phaseTime.getMilliseconds()).padStart(3, '0');
|
|
374
|
+
|
|
375
|
+
const dir = dirSymbols[phase.direction] || colors.dim('─── ');
|
|
376
|
+
const phaseLabel = (phaseLabels[phase.phase] || phase.phase).padEnd(18);
|
|
377
|
+
|
|
378
|
+
// Build details string based on phase type
|
|
379
|
+
let details = [];
|
|
380
|
+
|
|
381
|
+
// Agent → MCP phase: show method, requestId, args
|
|
382
|
+
if (phase.phase === 'agent_to_mcp') {
|
|
383
|
+
if (phase.method) {
|
|
384
|
+
details.push(colors.cyan(phase.method));
|
|
385
|
+
}
|
|
386
|
+
if (phase.requestId) {
|
|
387
|
+
const shortId = String(phase.requestId).slice(-8);
|
|
388
|
+
details.push(`id:${shortId}`);
|
|
389
|
+
}
|
|
390
|
+
if (phase.argsKeys && phase.argsKeys.length > 0) {
|
|
391
|
+
details.push(`[${phase.argsKeys.join(',')}]`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
368
394
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
395
|
+
// MCP → Chain phase: show action
|
|
396
|
+
if (phase.phase === 'mcp_to_chain') {
|
|
397
|
+
if (phase.action) {
|
|
398
|
+
details.push(colors.yellow(phase.action));
|
|
399
|
+
}
|
|
400
|
+
if (phase.requestId) {
|
|
401
|
+
const shortId = String(phase.requestId).slice(-8);
|
|
402
|
+
details.push(`id:${shortId}`);
|
|
403
|
+
}
|
|
372
404
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
405
|
+
|
|
406
|
+
// Chain → MCP phase: show status, duration, txId
|
|
407
|
+
if (phase.phase === 'chain_to_mcp') {
|
|
408
|
+
if (phase.status) {
|
|
409
|
+
const statusColor = phase.status === 'SUCCESS' ? colors.green : colors.red;
|
|
410
|
+
details.push(statusColor(phase.status));
|
|
411
|
+
}
|
|
412
|
+
if (phase.duration !== undefined) {
|
|
413
|
+
details.push(colors.yellow(`${phase.duration}ms`));
|
|
414
|
+
}
|
|
415
|
+
if (phase.resultPreview && phase.resultPreview.txId) {
|
|
416
|
+
const shortTx = String(phase.resultPreview.txId).slice(0, 16);
|
|
417
|
+
details.push(`tx:${shortTx}...`);
|
|
418
|
+
}
|
|
419
|
+
if (phase.error) {
|
|
420
|
+
details.push(colors.red(phase.error.slice(0, 20)));
|
|
421
|
+
}
|
|
377
422
|
}
|
|
378
|
-
|
|
379
|
-
|
|
423
|
+
|
|
424
|
+
// MCP → Agent phase: show status, duration, size
|
|
425
|
+
if (phase.phase === 'mcp_to_agent') {
|
|
426
|
+
if (phase.status) {
|
|
427
|
+
const statusColor = phase.status === 'SUCCESS' ? colors.green : colors.red;
|
|
428
|
+
details.push(statusColor(phase.status));
|
|
429
|
+
}
|
|
430
|
+
if (phase.duration !== undefined) {
|
|
431
|
+
details.push(colors.yellow(`${phase.duration}ms`));
|
|
432
|
+
}
|
|
433
|
+
if (phase.responseSize) {
|
|
434
|
+
details.push(`${phase.responseSize}b`);
|
|
435
|
+
}
|
|
436
|
+
if (phase.error) {
|
|
437
|
+
details.push(colors.red(phase.error.slice(0, 20)));
|
|
438
|
+
}
|
|
380
439
|
}
|
|
381
|
-
|
|
382
|
-
|
|
440
|
+
|
|
441
|
+
// MCP Error phase
|
|
442
|
+
if (phase.phase === 'mcp_error') {
|
|
443
|
+
if (phase.error) {
|
|
444
|
+
details.push(colors.red(phase.error));
|
|
445
|
+
}
|
|
446
|
+
if (phase.duration !== undefined) {
|
|
447
|
+
details.push(colors.yellow(`${phase.duration}ms`));
|
|
448
|
+
}
|
|
383
449
|
}
|
|
384
450
|
|
|
385
|
-
|
|
451
|
+
const detailStr = details.join(' ').slice(0, 37).padEnd(37);
|
|
452
|
+
|
|
453
|
+
console.log(colors.dim('│ ') + `${pTimeStr}.${pMsStr}` + colors.dim(' │ ') +
|
|
454
|
+
dir + colors.dim(' │ ') + phaseLabel + colors.dim(' │ ') + detailStr + colors.dim(' │'));
|
|
386
455
|
}
|
|
387
|
-
console.log('');
|
|
388
456
|
}
|
|
457
|
+
|
|
458
|
+
console.log(colors.dim('└──────────────┴───────┴────────────────────┴───────────────────────────────────────┘'));
|
|
459
|
+
console.log('');
|
|
460
|
+
console.log(colors.dim(`Showing last ${Math.min(8, sequences.length)} of ${sequences.length} sequences`));
|
|
389
461
|
}
|
|
390
462
|
}
|
|
391
463
|
}
|
package/src/lib/logger.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Used by MCP Server to record all tool executions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { existsSync, mkdirSync, appendFileSync } from 'fs';
|
|
8
|
+
import { existsSync, mkdirSync, appendFileSync, readFileSync } from 'fs';
|
|
9
9
|
import { homedir } from 'os';
|
|
10
10
|
import { join } from 'path';
|
|
11
11
|
|
|
@@ -80,6 +80,41 @@ export function logToolExecution({
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Check if debug mode is enabled (config or env)
|
|
85
|
+
*/
|
|
86
|
+
function isDebugEnabled() {
|
|
87
|
+
// Environment variable takes precedence
|
|
88
|
+
if (process.env.INSCRIBE_MCP_DEBUG === '1' || process.env.INSCRIBE_MCP_DEBUG === 'true') {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check config file
|
|
93
|
+
const configPath = join(homedir(), '.inscribe-mcp', 'config.json');
|
|
94
|
+
if (!existsSync(configPath)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
100
|
+
if (!config.debug || !config.debug.enabled) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check expiry
|
|
105
|
+
if (config.debug.expiresAt) {
|
|
106
|
+
const expiry = new Date(config.debug.expiresAt);
|
|
107
|
+
if (Date.now() > expiry.getTime()) {
|
|
108
|
+
return false; // Expired
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return true;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
83
118
|
/**
|
|
84
119
|
* Log a debug sequence trace
|
|
85
120
|
* @param {Object} options - Debug trace options
|
|
@@ -90,10 +125,23 @@ export function logDebugTrace({
|
|
|
90
125
|
payload = null,
|
|
91
126
|
status = null,
|
|
92
127
|
txId = null,
|
|
93
|
-
result = null
|
|
128
|
+
result = null,
|
|
129
|
+
duration = null,
|
|
130
|
+
args = null,
|
|
131
|
+
error = null,
|
|
132
|
+
// LAN analyzer style additional fields
|
|
133
|
+
method = null,
|
|
134
|
+
requestId = null,
|
|
135
|
+
argsKeys = null,
|
|
136
|
+
argsPreview = null,
|
|
137
|
+
action = null,
|
|
138
|
+
direction = null,
|
|
139
|
+
resultPreview = null,
|
|
140
|
+
responseSize = null,
|
|
141
|
+
errorType = null
|
|
94
142
|
}) {
|
|
95
143
|
// Only log if debug mode is enabled
|
|
96
|
-
if (!
|
|
144
|
+
if (!isDebugEnabled()) return;
|
|
97
145
|
|
|
98
146
|
writeLog({
|
|
99
147
|
level: 'debug',
|
|
@@ -102,7 +150,20 @@ export function logDebugTrace({
|
|
|
102
150
|
payload,
|
|
103
151
|
status,
|
|
104
152
|
txId,
|
|
105
|
-
result
|
|
153
|
+
result,
|
|
154
|
+
duration,
|
|
155
|
+
args,
|
|
156
|
+
error,
|
|
157
|
+
// LAN analyzer style additional fields
|
|
158
|
+
method,
|
|
159
|
+
requestId,
|
|
160
|
+
argsKeys,
|
|
161
|
+
argsPreview,
|
|
162
|
+
action,
|
|
163
|
+
direction,
|
|
164
|
+
resultPreview,
|
|
165
|
+
responseSize,
|
|
166
|
+
errorType
|
|
106
167
|
});
|
|
107
168
|
}
|
|
108
169
|
|
package/src/server.js
CHANGED
|
@@ -20,6 +20,9 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
20
20
|
import { homedir } from 'os';
|
|
21
21
|
import { join } from 'path';
|
|
22
22
|
|
|
23
|
+
// Logger for file-based debug traces (import early for use in debugLog)
|
|
24
|
+
import { logDebugTrace } from './lib/logger.js';
|
|
25
|
+
|
|
23
26
|
/**
|
|
24
27
|
* Check if debug mode is enabled (config or env)
|
|
25
28
|
*/
|
|
@@ -56,7 +59,7 @@ function isDebugEnabled() {
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
/**
|
|
59
|
-
* Debug log to stderr (safe for MCP stdio transport)
|
|
62
|
+
* Debug log to stderr AND file (safe for MCP stdio transport)
|
|
60
63
|
* Checks config on each call for hot-reload support
|
|
61
64
|
*/
|
|
62
65
|
function debugLog(phase, data = {}) {
|
|
@@ -71,6 +74,16 @@ function debugLog(phase, data = {}) {
|
|
|
71
74
|
|
|
72
75
|
// Output to stderr to avoid interfering with MCP JSON-RPC over stdout
|
|
73
76
|
console.error(`[DEBUG] ${JSON.stringify(message)}`);
|
|
77
|
+
|
|
78
|
+
// Also write to file for `inscribe-mcp show --debug`
|
|
79
|
+
logDebugTrace({
|
|
80
|
+
phase,
|
|
81
|
+
tool: data.tool,
|
|
82
|
+
args: data.args,
|
|
83
|
+
status: data.status,
|
|
84
|
+
duration: data.duration,
|
|
85
|
+
error: data.error
|
|
86
|
+
});
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
// Layer 1 Tools (Primary)
|
|
@@ -136,19 +149,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
136
149
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
137
150
|
const { name, arguments: args } = request.params;
|
|
138
151
|
const startTime = Date.now();
|
|
152
|
+
const requestId = request.id || `req_${Date.now()}`;
|
|
139
153
|
|
|
140
|
-
// Debug: Agent → MCP (request received)
|
|
154
|
+
// Debug: Agent → MCP (request received) - LAN analyzer style
|
|
141
155
|
debugLog('agent_to_mcp', {
|
|
142
156
|
tool: name,
|
|
143
|
-
|
|
157
|
+
method: 'tools/call',
|
|
158
|
+
requestId,
|
|
159
|
+
argsKeys: args ? Object.keys(args) : [],
|
|
160
|
+
argsPreview: args ? JSON.stringify(args).slice(0, 100) : null,
|
|
161
|
+
direction: 'IN'
|
|
144
162
|
});
|
|
145
163
|
|
|
146
164
|
const tool = allTools.find(t => t.name === name);
|
|
147
165
|
|
|
148
166
|
if (!tool) {
|
|
167
|
+
const duration = Date.now() - startTime;
|
|
149
168
|
debugLog('mcp_error', {
|
|
150
169
|
tool: name,
|
|
151
|
-
|
|
170
|
+
requestId,
|
|
171
|
+
error: 'Unknown tool',
|
|
172
|
+
duration,
|
|
173
|
+
direction: 'ERR'
|
|
152
174
|
});
|
|
153
175
|
|
|
154
176
|
return {
|
|
@@ -161,25 +183,39 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
161
183
|
// Debug: MCP → Chain (processing)
|
|
162
184
|
debugLog('mcp_to_chain', {
|
|
163
185
|
tool: name,
|
|
164
|
-
|
|
186
|
+
requestId,
|
|
187
|
+
action: 'CALL',
|
|
188
|
+
direction: 'OUT'
|
|
165
189
|
});
|
|
166
190
|
|
|
167
191
|
const result = await tool.handler(args || {});
|
|
168
192
|
const duration = Date.now() - startTime;
|
|
169
193
|
|
|
194
|
+
// Extract key info from result for debug
|
|
195
|
+
const resultPreview = result ? {
|
|
196
|
+
success: result.success,
|
|
197
|
+
txId: result.txId || result.inscription_id || result.topic_id,
|
|
198
|
+
type: result.type
|
|
199
|
+
} : null;
|
|
200
|
+
|
|
170
201
|
// Debug: Chain → MCP (response)
|
|
171
202
|
debugLog('chain_to_mcp', {
|
|
172
203
|
tool: name,
|
|
204
|
+
requestId,
|
|
173
205
|
status: 'SUCCESS',
|
|
174
206
|
duration,
|
|
175
|
-
|
|
207
|
+
resultPreview,
|
|
208
|
+
direction: 'IN'
|
|
176
209
|
});
|
|
177
210
|
|
|
178
211
|
// Debug: MCP → Agent (returning result)
|
|
179
212
|
debugLog('mcp_to_agent', {
|
|
180
213
|
tool: name,
|
|
214
|
+
requestId,
|
|
181
215
|
status: 'SUCCESS',
|
|
182
|
-
duration
|
|
216
|
+
duration,
|
|
217
|
+
responseSize: JSON.stringify(result).length,
|
|
218
|
+
direction: 'OUT'
|
|
183
219
|
});
|
|
184
220
|
|
|
185
221
|
return {
|
|
@@ -191,17 +227,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
191
227
|
// Debug: Chain → MCP (error)
|
|
192
228
|
debugLog('chain_to_mcp', {
|
|
193
229
|
tool: name,
|
|
230
|
+
requestId,
|
|
194
231
|
status: 'FAILED',
|
|
195
232
|
duration,
|
|
196
|
-
error: error.message
|
|
233
|
+
error: error.message,
|
|
234
|
+
errorType: error.constructor.name,
|
|
235
|
+
direction: 'IN'
|
|
197
236
|
});
|
|
198
237
|
|
|
199
238
|
// Debug: MCP → Agent (returning error)
|
|
200
239
|
debugLog('mcp_to_agent', {
|
|
201
240
|
tool: name,
|
|
241
|
+
requestId,
|
|
202
242
|
status: 'ERROR',
|
|
203
243
|
duration,
|
|
204
|
-
error: error.message
|
|
244
|
+
error: error.message,
|
|
245
|
+
direction: 'OUT'
|
|
205
246
|
});
|
|
206
247
|
|
|
207
248
|
return {
|
|
@@ -223,7 +264,7 @@ async function main() {
|
|
|
223
264
|
if (isDebugEnabled()) {
|
|
224
265
|
console.error('Debug mode is currently ON (hot-reloadable)');
|
|
225
266
|
debugLog('server_start', {
|
|
226
|
-
version: '0.3.
|
|
267
|
+
version: '0.3.6',
|
|
227
268
|
tools: allTools.map(t => t.name)
|
|
228
269
|
});
|
|
229
270
|
}
|