chain-insights 0.2.32 → 0.3.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.
Files changed (66) hide show
  1. package/README.md +43 -14
  2. package/dist/cases-Cp9DUbEV.mjs +6 -0
  3. package/dist/{cases-c0iV-XLI.cjs → cases-sTY5aXav.cjs} +3 -3
  4. package/dist/cli.cjs +122 -66
  5. package/dist/cli.mjs +122 -66
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/{viz-Da9YWN_I.cjs → data-extractor-Cavd7wHk.cjs} +11 -34
  8. package/dist/{viz-DkJyqlUu.mjs → data-extractor-DZUJu1Bz.mjs} +3 -32
  9. package/dist/data-extractor-DZUJu1Bz.mjs.map +1 -0
  10. package/dist/{dossier-Br62hCG7.cjs → dossier-BXy57V4-.cjs} +13 -1
  11. package/dist/{dossier-Bl0NkJKC.mjs → dossier-Bjpcbcxa.mjs} +4 -2
  12. package/dist/{dossier-Bl0NkJKC.mjs.map → dossier-Bjpcbcxa.mjs.map} +1 -1
  13. package/dist/export-BqTCO9lP.mjs +591 -0
  14. package/dist/export-BqTCO9lP.mjs.map +1 -0
  15. package/dist/export-DsXgtCwO.cjs +592 -0
  16. package/dist/index.cjs +1 -1
  17. package/dist/index.mjs +1 -1
  18. package/dist/{init-DBC9Ml33.mjs → init-DLBL_nVG.mjs} +27 -1
  19. package/dist/{init-DBC9Ml33.mjs.map → init-DLBL_nVG.mjs.map} +1 -1
  20. package/dist/{init-CFaUWgjK.cjs → init-zqbd7i-_.cjs} +26 -0
  21. package/dist/mcp-proxy.cjs +215 -77
  22. package/dist/mcp-proxy.d.cts.map +1 -1
  23. package/dist/mcp-proxy.d.mts.map +1 -1
  24. package/dist/mcp-proxy.mjs +215 -77
  25. package/dist/mcp-proxy.mjs.map +1 -1
  26. package/dist/{public-tools-BwguvIsf.cjs → public-tools-BvMb3H2P.cjs} +701 -1479
  27. package/dist/{public-tools-DoRNhMn9.mjs → public-tools-wJoAFDFa.mjs} +700 -1479
  28. package/dist/public-tools-wJoAFDFa.mjs.map +1 -0
  29. package/dist/{resolver-D7VBb0uB.mjs → resolver-2jXNtWQO.mjs} +12 -29
  30. package/dist/resolver-2jXNtWQO.mjs.map +1 -0
  31. package/dist/{resolver-BUU7ZgW-.cjs → resolver-CZdQwKvh.cjs} +11 -28
  32. package/dist/{runner-BCDeBYsR.cjs → runner-BhZ4lnF1.cjs} +2 -2
  33. package/dist/{runner-CTFK0Qcg.mjs → runner-DIJSbkjc.mjs} +3 -3
  34. package/dist/{runner-CTFK0Qcg.mjs.map → runner-DIJSbkjc.mjs.map} +1 -1
  35. package/dist/{selector-CTUiQrzI.mjs → selector-CF2o5gxN.mjs} +2 -2
  36. package/dist/{selector-CTUiQrzI.mjs.map → selector-CF2o5gxN.mjs.map} +1 -1
  37. package/dist/{selector-DBS2jYH4.cjs → selector-DfAMZEC9.cjs} +1 -1
  38. package/dist/{session-DwyikazY.cjs → session-BT7VpbAd.cjs} +13 -1
  39. package/dist/{session-Bha3zFrx.mjs → session-DROyhebe.mjs} +4 -2
  40. package/dist/{session-Bha3zFrx.mjs.map → session-DROyhebe.mjs.map} +1 -1
  41. package/dist/{store-BT2SCcQr.mjs → store-CTtqQtaE.mjs} +10 -4
  42. package/dist/{store-BT2SCcQr.mjs.map → store-CTtqQtaE.mjs.map} +1 -1
  43. package/dist/{store-DogLawSj.cjs → store-CqPfs47P.cjs} +37 -7
  44. package/dist/{tool-visibility-BHRFLXuU.mjs → tool-visibility-BpyZHRBi.mjs} +4 -2
  45. package/dist/tool-visibility-BpyZHRBi.mjs.map +1 -0
  46. package/dist/{tool-visibility-iAVQV3t0.cjs → tool-visibility-Buq7YdUZ.cjs} +3 -1
  47. package/dist/viz-5y24S5X1.mjs +35 -0
  48. package/dist/viz-5y24S5X1.mjs.map +1 -0
  49. package/dist/viz-Dqp3C5kb.cjs +44 -0
  50. package/docs/contributing.md +3 -2
  51. package/docs/graph-tools.md +126 -117
  52. package/docs/investigation-workspaces.md +17 -0
  53. package/docs/knowledge-exports.md +200 -0
  54. package/docs/mcp-proxy.md +16 -2
  55. package/package.json +1 -1
  56. package/skills/chain-insights-cypher/SKILL.md +6 -0
  57. package/skills/chain-insights-developer-experience/SKILL.md +26 -6
  58. package/skills/chain-insights-investigation/SKILL.md +64 -48
  59. package/skills/chain-insights-trace-funds/SKILL.md +80 -197
  60. package/skills/test-chain-insights-graphrag-mcp/SKILL.md +1 -1
  61. package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +4 -4
  62. package/dist/cases-qjPtbnUd.mjs +0 -6
  63. package/dist/public-tools-DoRNhMn9.mjs.map +0 -1
  64. package/dist/resolver-D7VBb0uB.mjs.map +0 -1
  65. package/dist/tool-visibility-BHRFLXuU.mjs.map +0 -1
  66. package/dist/viz-DkJyqlUu.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-proxy.mjs","names":[],"sources":["../src/mcp/proxy.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport type { ContentBlock, GetPromptResult, Prompt } from '@modelcontextprotocol/sdk/types.js'\nimport { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server'\nimport * as z from 'zod'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { McpTool } from './schema-cache.js'\nimport { HIDDEN_REMOTE_TOOL_NAMES } from './tool-visibility.js'\nimport { PaymentRequiredError } from './client.js'\n\nconst LOCAL_TOOL_NAMES = new Set([\n 'balance',\n 'help',\n 'case_open',\n 'case_list',\n 'case_resume',\n 'case_add_evidence',\n 'case_verify_evidence',\n 'case_update_dossier',\n 'case_start_session',\n 'case_end_session',\n])\nconst PUBLIC_GRAPHRAG_PROMPT_NAMES = new Set(['address-risk', 'track-funds'])\nconst GRAPH_RESOURCE_URI = 'ui://chain-insights/graph'\nconst GRAPH_APP_TOOL_NAMES = new Set([\n 'address_risk',\n 'scam_topology',\n 'stake_insights',\n 'track_funds',\n])\nconst GRAPH_ARRAY_KEYS = ['nodes', 'edges', 'flows', 'edge_anchors'] as const\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst COMMA_SEPARATED_ADDRESS_FIELDS = new Set([\n 'trusted_addresses',\n 'untrusted_addresses',\n])\n\nconst KNOWN_PUBLIC_TOOL_REQUIRED_ARGS: Record<string, string[]> = {\n address_risk: ['address', 'network'],\n scam_topology: ['victim_address', 'incident_timestamp_ms', 'network'],\n stake_insights: ['network'],\n track_funds: ['trusted_addresses', 'network'],\n graph_query: ['query', 'network'],\n graph_query_batch: ['network', 'queries'],\n}\n\nconst KNOWN_PUBLIC_TOOL_DESCRIPTIONS: Record<string, string> = {\n network_capabilities: 'Return supported Chain Insights networks, capability layers, tool availability, data retention windows, and freshness. Use this before choosing network-specific tools.',\n address_risk: 'Screen one full blockchain address for AML risk, behavior patterns, neighborhood context, exchange exposure, and optional comparison with compare_address. This includes the exchange-behavior analysis formerly covered by money_flows_between_exchanges. Use this as the first tool for a single-address investigation. The tool returns an investigator-ready summary; preserve full addresses exactly.',\n scam_topology: 'Build victim-incident laundering topology from one victim/source address and the earliest known incident timestamp. Traversal uses one explicit activity policy: node_relative_only by default, or global_incident_only when requested. Repeated targets are kept as non-expanding convergence edges. Returns ML-ready scam_labels plus review context and a track_funds-compatible graph report: primary flows, deposits, reverse_leads. Victims, exchange endpoints, and generic labeled context nodes are not automatic scam labels; preserve full addresses exactly.',\n stake_insights: 'Explain Bittensor staking behavior around one full address, coldkey, or hotkey. Requires network plus exactly one of address, coldkey, or hotkey. Returns net staked/unstaked amounts, active coldkey-hotkey-netuid relationships, aggregate stake movement amounts, top counterparties, first/last activity, source backend, query evidence, and optional graph report metadata.',\n track_funds: 'Trace funds from trusted victim/source addresses through intermediaries to exchange deposit addresses. Use this when the user has a victim/source address or known untrusted/scammer addresses. The tool returns an investigator-ready fund-flow report and recommended next actions.',\n graph_query: 'Run a read-only GQL/Cypher query through the Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Cross-layer correlated joins may be limited by the active graph endpoint; preserve full addresses exactly.',\n graph_query_batch: 'Run multiple read-only GQL/Cypher queries through the Chain Insights graph endpoint in one paid batch. Prefer this for related topology/facts reads.',\n}\nconst FALLBACK_GRAPH_PRIMITIVE_TOOL_NAMES = ['network_capabilities', 'graph_query', 'graph_query_batch'] as const\n\ntype ToolInputShape = Record<string, z.ZodTypeAny>\ntype ToolHandler = (args: unknown, extra?: unknown) => Promise<unknown> | unknown\ntype ToolRegistrationConfig = Parameters<McpServer['registerTool']>[1]\ntype ToolCallInput = { name: string; arguments?: Record<string, unknown> }\ntype RemoteToolCaller = {\n callTool: Client['callTool']\n}\n\nconst NETWORK_DESCRIPTION = 'Required network to query. Do not guess; use network_capabilities or ask the user if missing.'\nconst REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS = 15 * 60 * 1000\n\nconst CHAIN_INSIGHTS_WORKFLOW = [\n 'Workflow:',\n '1. If the user is starting or continuing an investigation, use case_open or case_list/case_resume first.',\n '2. Do not call investigation tools until required arguments are known. Network is required; use network_capabilities to check supported networks, data layers, retention, and freshness, or ask the user if missing.',\n '3. Use address_risk first for a single address when facts and topology are available. Use stake_insights for Bittensor coldkey/hotkey staking behavior. Use track_funds for victim/source fund tracing when topology is available. Use scam_topology when known victim incident ground truth should become ML-ready scam labels. Use graph_query(_batch) for the universal graph-language path over topology and facts.',\n '4. After a material result, preserve it with case_add_evidence when a case is active or ask whether to create/select a case.',\n '5. Use case_update_dossier for durable address/entity findings and case_start_session/case_end_session for session notes.',\n].join('\\n')\n\nconst GRAPH_SCHEMA_HINTS = [\n 'Graph query hints for network=bittensor:',\n '- Common live topology node labels include Address and may include legacy enrichment labels. Do not depend on Exchange/Miner graph labels for correctness; use address properties such as labels and is_exchange when available.',\n '- Address nodes are identity plus traversal hints. Lifetime/global address metrics live in USE facts as AddressFeature, not as topology semantics.',\n '- Facts graph labels include Address, AddressLabel, AddressFeature, RiskScore, and Asset.',\n '- Facts graph relationships include (:Address)-[:HAS_FEATURE]->(:AddressFeature), (:Address)-[:HAS_LABEL]->(:AddressLabel), and (:Address)-[:HAS_RISK_SCORE]->(:RiskScore).',\n '- Risk and ML properties may appear as live hints, but source-of-truth risk rows are RiskScore facts.',\n '- Common relationships include FLOWS_TO, OPERATED_FROM, SERVED_FROM, REGISTERED_NEURON, BELONGS_TO, SYBIL_CLUSTER, LAYERING_HOP, BURST_ACTIVITY, CYCLE_PARTICIPANT, SMURFING_CLUSTER.',\n '- FLOWS_TO properties are scoped to the selected topology graph and commonly carry amount_sum, amount_usd_sum, tx_count, first_seen_timestamp, last_seen_timestamp, first_tx_id, last_tx_id. Confirm available fields through runtime schema before relying on them.',\n '- Start schema discovery with endpoint-safe property reads: MATCH (n:Address) WHERE n.address IS NOT NULL RETURN n.labels AS labels, n.address AS address LIMIT 20',\n '- Relationship discovery: MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN r.amount_sum AS amount_sum, r.amount_usd_sum AS amount_usd_sum LIMIT 20',\n '- graph_query uses the active Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment.',\n '- Archive topology labels include Address and TopologySnapshot. Archived money-flow topology is represented as (:Address)-[:FLOWS_TO]->(:Address) relationships with period_granularity, period_start_date, and period_end_date.',\n '- All graph_query calls are read-only. Never use CREATE, INSERT, MERGE, SET, DELETE, REMOVE, DROP, DETACH, ADD, CONNECT, DISCONNECT, ALTER, TRUNCATE, GRANT, or REVOKE.',\n '- Use USE facts graph patterns for fact and enrichment reads. Do not query internal table namespaces directly.',\n].join('\\n')\n\nconst GRAPH_REPORT_HINTS = [\n 'Graph visualization behavior:',\n '- Graph-backed tools return the investigator report as text content and keep raw graph data out of LLM-visible structuredContent.',\n '- Raw graph data is stored locally under Chain Insights reports/graphs and exposed to the graph app as _meta.chainInsights.graph.url.',\n '- The local graph report server is started automatically by the MCP server when a graph-backed tool returns a report URL; do not ask the user to run chain-insights serve for Claude Desktop graph iframes.',\n '- If an iframe reports that a graph report fetch failed, retry the graph-backed tool call so Chain Insights can recreate the report URL and ensure the local report server is running.',\n].join('\\n')\n\nconst SERVER_INSTRUCTIONS = [\n 'Chain Insights is a local AML investigation workspace for AI agents.',\n CHAIN_INSIGHTS_WORKFLOW,\n GRAPH_REPORT_HINTS,\n GRAPH_SCHEMA_HINTS,\n 'Presentation rules: preserve tool summaries as returned; never truncate blockchain addresses; use case tools to preserve evidence when a case exists.',\n].join('\\n\\n')\n\nfunction readGraphAppHtml(): string {\n const candidates = [\n path.resolve(__dirname, 'templates', 'graph.html'),\n path.resolve(__dirname, '..', 'templates', 'graph.html'),\n path.resolve(__dirname, '..', 'viz', 'templates', 'graph.html'),\n ]\n\n for (const candidate of candidates) {\n try {\n return readFileSync(candidate, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n }\n\n throw new Error(`Graph MCP app template not found. Tried: ${candidates.join(', ')}`)\n}\n\nfunction graphArtifactOrigins(config: Pick<InvestigatorConfig, 'serverPort'>): string[] {\n return [\n `http://127.0.0.1:${config.serverPort}`,\n `http://localhost:${config.serverPort}`,\n ]\n}\n\nfunction hasGraphApp(tool: McpTool): boolean {\n const configuredUri = tool._meta?.ui\n if (\n configuredUri &&\n typeof configuredUri === 'object' &&\n 'resourceUri' in configuredUri &&\n configuredUri.resourceUri === GRAPH_RESOURCE_URI\n ) {\n return true\n }\n\n if (tool._meta?.['ui/resourceUri'] === GRAPH_RESOURCE_URI) return true\n if (GRAPH_APP_TOOL_NAMES.has(tool.name)) return true\n return JSON.stringify(tool.outputSchema ?? {}).includes('\"app_data\"')\n}\n\nfunction graphToolMeta(tool: McpTool): Record<string, unknown> & { ui: { resourceUri: string } } {\n const meta = { ...(tool._meta ?? {}) }\n const ui =\n meta.ui && typeof meta.ui === 'object' && !Array.isArray(meta.ui)\n ? { ...(meta.ui as Record<string, unknown>) }\n : {}\n\n return {\n ...meta,\n ui: {\n ...ui,\n resourceUri: GRAPH_RESOURCE_URI,\n },\n }\n}\n\nfunction knownPublicToolInputSchema(toolName: string): ToolInputShape | null {\n switch (toolName) {\n case 'address_risk':\n return {\n address: z.string().min(1).describe('Full blockchain address to screen'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n compare_address: z.string().optional().describe('Optional second full address for comparison'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'track_funds':\n return {\n trusted_addresses: z.string().min(1).describe('Comma-separated full trusted victim addresses. Min 1, max 5.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n untrusted_addresses: z.string().optional().describe('Comma-separated full untrusted/scammer addresses. Max 5.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'scam_topology':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n victim_address: z.string().min(1).describe('Full victim/source address that anchors the scam incident. Victims are not risky labels.'),\n incident_timestamp_ms: z.number().min(0).describe('Earliest known incident transfer timestamp in milliseconds. Primary traversal uses node-relative wave-arrival filtering.'),\n max_hops: z.number().int().min(1).max(64).optional().describe('Maximum forward expansion depth. Default 16.'),\n activity_policy: z.enum(['node_relative_only', 'global_incident_only']).optional().describe('Traversal activity policy. Default node_relative_only.'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n }\n case 'stake_insights':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n address: z.string().optional().describe('Full Bittensor address to inspect as either coldkey or hotkey. Provide exactly one of address, coldkey, or hotkey.'),\n coldkey: z.string().optional().describe('Full Bittensor coldkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n hotkey: z.string().optional().describe('Full Bittensor hotkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n netuid: z.number().int().min(0).optional().describe('Optional subnet netuid filter.'),\n start_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive lower activity timestamp bound in milliseconds.'),\n end_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive upper activity timestamp bound in milliseconds.'),\n start_block: z.number().int().min(0).optional().describe('Optional start block. Current stake graph parity may require timestamp windows instead.'),\n end_block: z.number().int().min(0).optional().describe('Optional end block. Current stake graph parity may require timestamp windows instead.'),\n depth: z.number().int().min(1).max(3).optional().describe('Optional expansion depth limit. First release returns direct STAKES_IN relationships; default 1, max 3.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'graph_query':\n return {\n query: z.string().min(1).describe('Read-only GQL/Cypher query. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n }\n case 'graph_query_batch':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n queries: z.array(z.object({\n id: z.string().optional(),\n query: z.string().min(1).describe('Read-only GQL/Cypher query'),\n })).min(1).max(20),\n per_query_timeout_seconds: z.number().int().min(1).max(600).optional(),\n }\n default:\n return null\n }\n}\n\nfunction fallbackGraphPrimitiveTools(): McpTool[] {\n return FALLBACK_GRAPH_PRIMITIVE_TOOL_NAMES.map((name) => ({\n name,\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS[name],\n }))\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction redactLogValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(redactLogValue)\n if (!isRecord(value)) return value\n return Object.fromEntries(Object.entries(value).map(([key, entry]) => {\n if (/token|secret|password|private.?key|authorization/i.test(key)) return [key, '[redacted]']\n return [key, redactLogValue(entry)]\n }))\n}\n\nfunction errorForLog(err: unknown): Record<string, unknown> {\n const error = err as Error\n return {\n name: error.name ?? 'Error',\n message: error.message ?? String(err),\n }\n}\n\nfunction sanitizeCypher(query: string): string {\n return query.replace(/\\s+/g, ' ').trim()\n}\n\nfunction cypherLogPayload(tool: string, args: unknown): Record<string, unknown> | null {\n if (!isRecord(args)) return null\n if (tool === 'graph_query') {\n return {\n network: args.network,\n queries: [{\n id: tool,\n query: typeof args.query === 'string' ? sanitizeCypher(args.query) : args.query,\n }],\n }\n }\n if (tool === 'graph_query_batch') {\n const queries = Array.isArray(args.queries) ? args.queries : []\n return {\n network: args.network,\n per_query_timeout_seconds: args.per_query_timeout_seconds,\n query_count: queries.length,\n queries: queries.map((entry, index) => isRecord(entry)\n ? {\n id: typeof entry.id === 'string' ? entry.id : `q${index + 1}`,\n query: typeof entry.query === 'string' ? sanitizeCypher(entry.query) : entry.query,\n }\n : { id: `q${index + 1}`, query: entry }),\n }\n }\n return null\n}\n\nfunction createMcpLogger(config: Pick<InvestigatorConfig, 'dataDir'>) {\n const disabled = process.env.CHAIN_INSIGHTS_MCP_LOG === '0'\n const filePath = process.env.CHAIN_INSIGHTS_MCP_LOG_PATH?.trim() || path.join(config.dataDir, '.chain-insights', 'runtime', 'logs', 'mcp-proxy.jsonl')\n\n async function write(level: 'info' | 'error', event: string, fields: Record<string, unknown> = {}): Promise<void> {\n if (disabled) return\n try {\n await mkdir(path.dirname(filePath), { recursive: true })\n await appendFile(filePath, JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event,\n pid: process.pid,\n ...fields,\n }) + '\\n', { mode: 0o600 })\n } catch {\n // Logging must never break the stdio MCP server.\n }\n }\n\n return {\n filePath,\n info: (event: string, fields?: Record<string, unknown>) => write('info', event, fields),\n error: (event: string, fields?: Record<string, unknown>) => write('error', event, fields),\n }\n}\n\nfunction installToolLogging(server: McpServer, logger: ReturnType<typeof createMcpLogger>): void {\n const existingRegisterTool = server.registerTool\n const originalRegisterTool = existingRegisterTool.bind(server)\n const wrappedRegisterTool = ((name: string, config: ToolRegistrationConfig, handler: ToolHandler) => {\n const wrapped: ToolHandler = async (args, extra) => {\n const startedAt = Date.now()\n await logger.info('tool.start', {\n tool: name,\n args: redactLogValue(args),\n })\n try {\n const result = await handler(args, extra)\n const isError = isRecord(result) && result.isError === true\n await logger.info('tool.end', {\n tool: name,\n duration_ms: Date.now() - startedAt,\n is_error: isError,\n })\n return result\n } catch (err) {\n await logger.error('tool.throw', {\n tool: name,\n duration_ms: Date.now() - startedAt,\n error: errorForLog(err),\n })\n throw err\n }\n }\n return originalRegisterTool(name, config, wrapped as never)\n }) as typeof server.registerTool\n Object.assign(wrappedRegisterTool, existingRegisterTool)\n server.registerTool = wrappedRegisterTool\n}\n\nfunction installRemoteCypherLogging(remoteClient: RemoteToolCaller, logger: ReturnType<typeof createMcpLogger>): void {\n const existingCallTool = remoteClient.callTool\n const originalCallTool = existingCallTool.bind(remoteClient)\n const wrappedCallTool = (async (...args: Parameters<Client['callTool']>) => {\n const input = args[0] as ToolCallInput\n const queryPayload = cypherLogPayload(input.name, input.arguments)\n const startedAt = Date.now()\n if (queryPayload) {\n await logger.info('topology.start', {\n tool: input.name,\n ...queryPayload,\n })\n }\n try {\n const result = await originalCallTool(...args)\n if (queryPayload) {\n await logger.info('topology.end', {\n tool: input.name,\n duration_ms: Date.now() - startedAt,\n is_error: isRecord(result) && result.isError === true,\n })\n }\n return result\n } catch (err) {\n if (queryPayload) {\n await logger.error('cypher.throw', {\n tool: input.name,\n duration_ms: Date.now() - startedAt,\n error: errorForLog(err),\n })\n }\n throw err\n }\n }) as typeof remoteClient.callTool\n Object.assign(wrappedCallTool, existingCallTool)\n remoteClient.callTool = wrappedCallTool\n}\n\nfunction remoteToolRequestOptions(toolName: string): Parameters<Client['callTool']>[2] | undefined {\n if (toolName === 'graph_query' || toolName === 'graph_query_batch') {\n return {\n timeout: REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS,\n }\n }\n return undefined\n}\n\nfunction isBlankArgument(value: unknown): boolean {\n if (value === undefined || value === null) return true\n if (typeof value === 'string') return value.trim() === ''\n if (Array.isArray(value)) return value.length === 0 || value.every(isBlankArgument)\n return false\n}\n\nfunction normalizeRemoteToolArguments(toolName: string, args: unknown): Record<string, unknown> {\n const normalized = isRecord(args) ? { ...args } : {}\n if (!(toolName in KNOWN_PUBLIC_TOOL_REQUIRED_ARGS)) return normalized\n\n for (const fieldName of COMMA_SEPARATED_ADDRESS_FIELDS) {\n const value = normalized[fieldName]\n if (Array.isArray(value)) {\n normalized[fieldName] = value\n .map((entry) => String(entry).trim())\n .filter(Boolean)\n .join(',')\n }\n }\n\n return normalized\n}\n\nfunction validateKnownPublicToolArguments(\n toolName: string,\n args: Record<string, unknown>,\n): string | null {\n const requiredArgs = KNOWN_PUBLIC_TOOL_REQUIRED_ARGS[toolName]\n if (!requiredArgs) return null\n\n for (const argName of requiredArgs) {\n if (isBlankArgument(args[argName])) {\n return `Missing required argument: ${argName}`\n }\n }\n\n return null\n}\n\nfunction claudeFacingToolDescription(tool: McpTool): string {\n const baseDescription = KNOWN_PUBLIC_TOOL_DESCRIPTIONS[tool.name] ?? tool.description ?? tool.name\n const requiredArgs = KNOWN_PUBLIC_TOOL_REQUIRED_ARGS[tool.name]\n if (!requiredArgs) return baseDescription\n return [\n baseDescription,\n '',\n `Required arguments: ${requiredArgs.join(', ')}.`,\n 'If the user did not provide the network, ask for it before calling this tool. Do not guess a default network.',\n ].join('\\n')\n}\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n structuredContent?: Record<string, unknown>\n _meta?: Record<string, unknown>\n isError?: boolean\n}\n\ntype PromptArgs = Record<string, string | undefined>\n\nfunction promptResult(text: string, description?: string): GetPromptResult {\n return {\n description,\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text,\n },\n },\n ],\n }\n}\n\nfunction compactPromptArguments(args: PromptArgs): Record<string, string> {\n const compact: Record<string, string> = {}\n for (const [key, value] of Object.entries(args)) {\n if (typeof value === 'string' && value.trim() !== '') {\n compact[key] = value\n }\n }\n return compact\n}\n\nfunction promptArgumentSchema(promptName: string, argument: NonNullable<Prompt['arguments']>[number]) {\n const description = PUBLIC_GRAPHRAG_PROMPT_NAMES.has(promptName) && argument.name === 'network'\n ? NETWORK_DESCRIPTION\n : argument.description ?? argument.name\n const schema = z.string().describe(description)\n if (PUBLIC_GRAPHRAG_PROMPT_NAMES.has(promptName) && argument.name === 'network') {\n return schema\n }\n return argument.required === false ? schema.optional() : schema\n}\n\nfunction registerRemotePrompt(server: McpServer, remoteClient: Client, prompt: Prompt): void {\n const argsSchema: Record<string, z.ZodTypeAny> = {}\n for (const argument of prompt.arguments ?? []) {\n argsSchema[argument.name] = promptArgumentSchema(prompt.name, argument)\n }\n\n server.registerPrompt(\n prompt.name,\n {\n title: prompt.title,\n description: prompt.description,\n argsSchema,\n },\n async (args) => remoteClient.getPrompt({\n name: prompt.name,\n arguments: compactPromptArguments(args as PromptArgs),\n }),\n )\n}\n\nfunction registerLocalPrompts(server: McpServer, remotePromptNames: Set<string>): void {\n if (!remotePromptNames.has('address-risk')) {\n server.registerPrompt(\n 'address-risk',\n {\n title: 'Address Risk',\n description: 'Screen an address for AML risk, behavioral patterns, neighborhood profile, and exchange links.',\n argsSchema: {\n address: z.string().describe('Full blockchain address to screen'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ address, network }) => promptResult(\n [\n `Use Chain Insights address_risk on ${network} for:`,\n '',\n `\\`${address}\\``,\n '',\n 'Present the summary as-is. Do not add analysis, verdicts, or risk assessments; the tool output already contains the risk assessment.',\n ].join('\\n'),\n 'Address risk screening',\n ),\n )\n }\n\n if (!remotePromptNames.has('track-funds')) {\n server.registerPrompt(\n 'track-funds',\n {\n title: 'Track Funds',\n description: 'Trace stolen funds from victim addresses through intermediaries to exchange deposit addresses.',\n argsSchema: {\n trusted_addresses: z.string().describe('Victim/trusted addresses, comma-separated full addresses'),\n untrusted_addresses: z.string().optional().describe('Known scammer/untrusted addresses, comma-separated full addresses'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ trusted_addresses, untrusted_addresses, network }) => {\n const untrusted = untrusted_addresses?.trim()\n ? `\\nKnown untrusted addresses:\\n${untrusted_addresses}\\n`\n : ''\n return promptResult(\n [\n `Use Chain Insights track_funds on ${network}.`,\n '',\n 'Trusted victim addresses:',\n trusted_addresses,\n untrusted,\n 'Present the summary as-is and include recommended next actions exactly as returned.',\n ].join('\\n'),\n 'Trace stolen funds',\n )\n },\n )\n }\n\n server.registerPrompt(\n 'graph-query',\n {\n title: 'Federated Graph Query',\n description: 'Run a read-only GQL/Cypher query through the Chain Insights graph endpoint.',\n argsSchema: {\n query: z.string().describe('Read-only GQL/Cypher query'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ query, network }) => promptResult(\n [\n `Use Chain Insights graph_query on ${network} with this read-only GQL/Cypher query:`,\n '',\n '```gql',\n query,\n '```',\n '',\n 'Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Return full address properties; never shorten addresses with ellipses.',\n ].join('\\n'),\n 'Federated graph query',\n ),\n )\n\n server.registerPrompt(\n 'graph-query-batch',\n {\n title: 'Federated Graph Query Batch',\n description: 'Run related read-only GQL/Cypher queries through the Chain Insights graph endpoint in one paid batch.',\n argsSchema: {\n queries: z.string().describe('JSON array of query objects with optional id and required query fields'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n per_query_timeout_seconds: z.string().optional().describe('Optional integer timeout per query, 1-600 seconds'),\n },\n },\n async ({ queries, network, per_query_timeout_seconds }) => promptResult(\n [\n `Use Chain Insights graph_query_batch on ${network} with these read-only GQL/Cypher queries:`,\n '',\n '```json',\n queries,\n '```',\n per_query_timeout_seconds ? `per_query_timeout_seconds: ${per_query_timeout_seconds}` : '',\n '',\n 'Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Return full address properties; never shorten addresses with ellipses.',\n ].filter(Boolean).join('\\n'),\n 'Federated graph batch query',\n ),\n )\n\n server.registerPrompt(\n 'balance',\n {\n title: 'Wallet Balance',\n description: 'Show the local Chain Insights payment wallet address and Base USDC balance.',\n argsSchema: {},\n },\n async () => promptResult(\n 'Use Chain Insights balance. Show the wallet address, network, token, and balance exactly as returned.',\n 'Wallet balance',\n ),\n )\n\n server.registerPrompt(\n 'help',\n {\n title: 'Chain Insights Help',\n description: 'Show available Chain Insights tools and investigation case workflow.',\n argsSchema: {},\n },\n async () => promptResult(\n 'Use Chain Insights help. Summarize the available tools and investigation case workflow without inventing capabilities.',\n 'Chain Insights help',\n ),\n )\n\n server.registerPrompt(\n 'open-investigation-case',\n {\n title: 'Open Investigation Case',\n description: 'Create a local Chain Insights case for an investigation.',\n argsSchema: {\n name: z.string().describe('Case name'),\n tags: z.string().optional().describe('Comma-separated tags'),\n description: z.string().optional().describe('Brief investigation description'),\n },\n },\n async ({ name, tags, description }) => promptResult(\n [\n 'Use Chain Insights case_open to create a local investigation case.',\n '',\n `name: \\`${name}\\``,\n tags ? `tags: \\`${tags}\\`` : '',\n description ? `description: ${description}` : '',\n ].filter(Boolean).join('\\n'),\n 'Open investigation case',\n ),\n )\n\n server.registerPrompt(\n 'resume-investigation-case',\n {\n title: 'Resume Investigation Case',\n description: 'Load local Chain Insights case context, evidence count, dossiers, and latest session.',\n argsSchema: {\n case_id: z.string().describe('Chain Insights case ID'),\n },\n },\n async ({ case_id }) => promptResult(\n `Use Chain Insights case_resume for case_id: \\`${case_id}\\`. Continue from the returned context.`,\n 'Resume investigation case',\n ),\n )\n\n server.registerPrompt(\n 'save-investigation-evidence',\n {\n title: 'Save Investigation Evidence',\n description: 'Append a tool result or analyst note to a local Chain Insights case evidence manifest.',\n argsSchema: {\n case_id: z.string().describe('Chain Insights case ID'),\n source: z.string().describe('Tool or source name'),\n },\n },\n async ({ case_id, source }) => promptResult(\n [\n 'Use Chain Insights case_add_evidence after the next relevant tool result.',\n '',\n `case_id: \\`${case_id}\\``,\n `source: \\`${source}\\``,\n 'content: use the exact report or note that should become evidence.',\n ].join('\\n'),\n 'Save investigation evidence',\n ),\n )\n}\n\nfunction hasGraphArrayFields(value: unknown): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n return GRAPH_ARRAY_KEYS.some((key) => Array.isArray(record[key]))\n}\n\nfunction sanitizeStructuredContentForGraphPayload(\n structuredContent: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!structuredContent) return undefined\n return sanitizeStructuredValue(structuredContent) as Record<string, unknown>\n}\n\nfunction sanitizeStructuredValue(value: unknown): unknown {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return value\n\n const sanitized: Record<string, unknown> = {}\n for (const [key, childValue] of Object.entries(value)) {\n if (key === 'app_data') continue\n if (GRAPH_ARRAY_KEYS.includes(key as (typeof GRAPH_ARRAY_KEYS)[number]) && Array.isArray(childValue)) {\n continue\n }\n sanitized[key] = sanitizeStructuredValue(childValue)\n }\n\n return sanitized\n}\n\nfunction getRemoteGraphPayload(result: RemoteToolResult): Record<string, unknown> | null {\n const chainInsights = result._meta?.chainInsights\n if (!chainInsights || typeof chainInsights !== 'object' || Array.isArray(chainInsights)) return null\n const graph = (chainInsights as Record<string, unknown>).graph\n if (graph === undefined) return null\n if (!graph || typeof graph !== 'object' || Array.isArray(graph)) {\n throw new Error('Invalid remote graph payload')\n }\n\n const graphRecord = graph as Record<string, unknown>\n if (!('data' in graphRecord)) {\n if ('url' in graphRecord || hasGraphArrayFields(graphRecord)) {\n throw new Error('Invalid remote graph payload')\n }\n return null\n }\n\n const data = graphRecord.data\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new Error('Invalid remote graph payload')\n }\n\n return data as Record<string, unknown>\n}\n\nasync function normalizeRemoteToolResult(\n result: RemoteToolResult,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n toolName = 'remote-graph',\n) {\n const graphPayload = getRemoteGraphPayload(result)\n const meta = { ...(result._meta ?? {}) }\n\n if (graphPayload) {\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const report = await writeGraphReport(graphPayload as never, {\n serverPort: config.serverPort,\n slug: toolName || 'remote-graph',\n })\n await ensureArtifactServer(config.serverPort)\n meta.chainInsights = {\n ...((meta.chainInsights as Record<string, unknown>) ?? {}),\n graph: {\n schema: report.schema,\n url: report.url,\n },\n }\n }\n\n return {\n content: result.content ?? [],\n structuredContent: sanitizeStructuredContentForGraphPayload(result.structuredContent),\n _meta: Object.keys(meta).length > 0 ? meta : undefined,\n isError: result.isError,\n }\n}\n\n/**\n * Core proxy logic — exported so tests can inject dependencies directly.\n * The IIFE at the bottom calls this with real dependencies.\n *\n * stdout purity: NEVER write to stdout in this file. Use console.error() or process.stderr.write() only.\n * All diagnostic output goes to console.error() or process.stderr.write().\n */\nexport async function createProxy(): Promise<void> {\n // Lazy imports to avoid module-load side effects (critical for stdio proxy)\n const { loadConfig } = await import('../config/index.js')\n const { activeDataDir, findActiveWorkspace } = await import('../workspace/active.js')\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./client.js')\n const { loadSchema, saveSchema } = await import('./schema-cache.js')\n\n const loadedConfig = await loadConfig()\n const activeWorkspace = findActiveWorkspace()\n const config = {\n ...loadedConfig,\n dataDir: activeDataDir(loadedConfig.dataDir),\n }\n const logger = createMcpLogger(config)\n await logger.info('proxy.start', {\n data_dir: config.dataDir,\n workspace_root: activeWorkspace?.root,\n graph_mcp_mode: config.graphMcpMode,\n graph_mcp_endpoint: resolveGraphMcpEndpoint(config),\n log_path: logger.filePath,\n })\n const graphMcpEndpoint = resolveGraphMcpEndpoint(config)\n\n // Build remote MCP client. The local Chain Insights MCP surface must still\n // start when the graph endpoint is temporarily unavailable so agents can use\n // help, wallet, and case workflow tools.\n const remoteClient = new Client({ name: 'chain-insights-proxy-client', version: PACKAGE_VERSION })\n let remoteConnected = false\n let remoteUnavailableMessage: string | undefined\n let mcpFetch: typeof fetch | undefined\n\n try {\n mcpFetch = await createConfiguredGraphMcpFetch(config)\n } catch (err) {\n await logger.error('remote.fetch_setup_failed', {\n endpoint: graphMcpEndpoint,\n error: errorForLog(err),\n })\n remoteUnavailableMessage = `Graph MCP setup unavailable at ${graphMcpEndpoint}: ${(err as Error).message}`\n process.stderr.write(\n `Chain Insights MCP graph tools unavailable: ${remoteUnavailableMessage}. Local Chain Insights tools are still available.\\n`,\n )\n }\n\n if (mcpFetch) {\n try {\n await remoteClient.connect(\n new StreamableHTTPClientTransport(new URL(graphMcpEndpoint), { fetch: mcpFetch }),\n )\n remoteConnected = true\n await logger.info('remote.connect', {\n transport: 'streamable_http',\n endpoint: graphMcpEndpoint,\n })\n } catch {\n await logger.error('remote.connect_failed', {\n transport: 'streamable_http',\n endpoint: graphMcpEndpoint,\n })\n // StreamableHTTP failed — try SSE fallback (assumption A1 from RESEARCH.md)\n try {\n const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js')\n await remoteClient.connect(\n new SSEClientTransport(new URL(graphMcpEndpoint), { fetch: mcpFetch }),\n )\n remoteConnected = true\n await logger.info('remote.connect', {\n transport: 'sse',\n endpoint: graphMcpEndpoint,\n })\n } catch (err2) {\n await logger.error('remote.connect_failed', {\n transport: 'sse',\n endpoint: graphMcpEndpoint,\n error: errorForLog(err2),\n })\n remoteUnavailableMessage = `Graph MCP unreachable at ${graphMcpEndpoint}: ${(err2 as Error).message}`\n process.stderr.write(\n `Chain Insights MCP graph tools unavailable: ${remoteUnavailableMessage}. Local Chain Insights tools are still available.\\n`,\n )\n }\n }\n }\n if (remoteConnected) installRemoteCypherLogging(remoteClient as unknown as RemoteToolCaller, logger)\n\n // Schema cache check — skip remote listTools call on cache hit\n let tools: McpTool[] | null = await loadSchema(graphMcpEndpoint)\n\n if (!tools && remoteConnected) {\n // Cache miss — fetch tools from remote (client is already connected above)\n const result = await remoteClient.listTools()\n tools = result.tools as McpTool[]\n await saveSchema(tools, graphMcpEndpoint)\n await logger.info('schema.tools_loaded', {\n source: 'remote',\n count: tools.length,\n })\n } else if (tools) {\n await logger.info('schema.tools_loaded', {\n source: 'cache',\n count: tools.length,\n })\n } else {\n tools = fallbackGraphPrimitiveTools()\n await logger.info('schema.tools_loaded', {\n source: 'unavailable',\n count: tools.length,\n })\n }\n const remoteToolNames = new Set((tools ?? []).map((tool) => tool.name))\n\n // Build local stdio proxy server\n const server = new McpServer(\n { name: 'chain-insights', version: PACKAGE_VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n )\n installToolLogging(server, logger)\n\n const remotePrompts: Prompt[] = []\n if (remoteConnected) {\n try {\n const promptResult = await remoteClient.listPrompts()\n for (const prompt of promptResult.prompts as Prompt[]) {\n if (PUBLIC_GRAPHRAG_PROMPT_NAMES.has(prompt.name)) {\n remotePrompts.push(prompt)\n }\n }\n } catch (err) {\n await logger.error('remote.prompts_failed', {\n endpoint: graphMcpEndpoint,\n error: errorForLog(err),\n })\n process.stderr.write(\n `Chain Insights MCP prompt passthrough unavailable at ${graphMcpEndpoint}: ${(err as Error).message}\\n`,\n )\n }\n }\n\n const remotePromptNames = new Set(remotePrompts.map((prompt) => prompt.name))\n for (const prompt of remotePrompts) {\n registerRemotePrompt(server, remoteClient, prompt)\n }\n registerLocalPrompts(server, remotePromptNames)\n\n const caseToolError = (label: string, err: unknown) => ({\n content: [{ type: 'text' as const, text: `${label} failed: ${(err as Error).message}` }],\n isError: true,\n })\n\n const parseTags = (tags: string | string[] | undefined): string[] => {\n if (Array.isArray(tags)) return tags.map((tag) => tag.trim()).filter(Boolean)\n if (typeof tags === 'string') return tags.split(',').map((tag) => tag.trim()).filter(Boolean)\n return []\n }\n\n server.registerTool(\n 'balance',\n {\n description: 'Show the local Chain Insights payment wallet address and Base USDC balance.',\n inputSchema: z.object({}).passthrough(),\n },\n async () => {\n try {\n const { getWalletAccount, getWalletBalanceText } = await import('../wallet/tools.js')\n const account = await getWalletAccount()\n return {\n content: [{ type: 'text' as const, text: await getWalletBalanceText(account) }],\n isError: false,\n }\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Balance failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n\n registerAppResource(\n server,\n 'Fund Flow Graph',\n GRAPH_RESOURCE_URI,\n {\n description: 'Interactive D3 force-directed graph for fund flow and pattern visualization. It loads local graph report URLs returned in _meta.chainInsights.graph.url.',\n _meta: {\n ui: {\n csp: {\n resourceDomains: graphArtifactOrigins(config),\n connectDomains: graphArtifactOrigins(config),\n },\n },\n },\n },\n async () => ({\n contents: [\n {\n uri: GRAPH_RESOURCE_URI,\n mimeType: RESOURCE_MIME_TYPE,\n text: readGraphAppHtml(),\n _meta: {\n ui: {\n csp: {\n resourceDomains: graphArtifactOrigins(config),\n connectDomains: graphArtifactOrigins(config),\n },\n },\n },\n },\n ],\n }),\n )\n\n server.registerTool(\n 'case_open',\n {\n description: 'Create a local Chain Insights investigation case. Use this before saving evidence, dossiers, or session notes for a new investigation.',\n inputSchema: {\n name: z.string().min(1).describe('Case name'),\n tags: z.union([z.string(), z.array(z.string())]).optional().describe('Comma-separated tags or string array'),\n description: z.string().optional().describe('Brief investigation description'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ name, tags, description }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const created = await CaseStore.create({\n name,\n tags: parseTags(tags),\n description: description ?? '',\n })\n const { casesRoot } = await import('../cases/store.js')\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n case_id: created.id,\n name: created.name,\n status: created.status,\n tags: created.tags,\n directory: `${path.join(casesRoot(), created.id)}/`,\n }, null, 2),\n }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case open', err)\n }\n },\n )\n\n server.registerTool(\n 'case_list',\n {\n description: 'List local Chain Insights investigation cases. Use before resuming when the user does not provide a case ID.',\n inputSchema: {\n status: z.enum(['open', 'active', 'suspended', 'closed']).optional().describe('Optional status filter'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ status }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const cases = await CaseStore.list()\n const filtered = status ? cases.filter((entry) => entry.status === status) : cases\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ cases: filtered }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case list', err)\n }\n },\n )\n\n server.registerTool(\n 'case_resume',\n {\n description: 'Load local Chain Insights case context: metadata, evidence count, dossier summaries, and latest session notes.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const context = await CaseStore.loadContext(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(context, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case resume', err)\n }\n },\n )\n\n server.registerTool(\n 'case_add_evidence',\n {\n description: 'Append a tool result or analyst note to a local case evidence manifest. Use after address_risk, track_funds, graph_query, or manual findings that should be preserved.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n source: z.string().min(1).describe('Source tool or evidence origin'),\n content: z.string().min(1).describe('Evidence markdown/text to store'),\n query_params: z.string().optional().describe('Original query parameters, for example \"network=bittensor address=...\"'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, source, content, query_params }) => {\n try {\n const { EvidenceStore } = await import('../cases/index.js')\n const saved = await EvidenceStore.append(case_id, {\n source,\n content,\n queryParams: query_params ?? '',\n })\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(saved, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Evidence append', err)\n }\n },\n )\n\n server.registerTool(\n 'case_verify_evidence',\n {\n description: 'Verify a local case evidence manifest and report tampered or missing evidence files.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { EvidenceStore } = await import('../cases/index.js')\n const result = await EvidenceStore.verifyManifest(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Evidence verify', err)\n }\n },\n )\n\n server.registerTool(\n 'case_update_dossier',\n {\n description: 'Append a finding to an address/entity dossier inside a local Chain Insights case.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n address: z.string().min(1).describe('Full address or entity identifier'),\n finding: z.string().min(1).describe('Finding to append'),\n entity_type: z.enum(['eoa', 'contract', 'exchange', 'mixer', 'unknown']).optional().describe('Entity type'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, address, finding, entity_type }) => {\n try {\n const { DossierStore } = await import('../cases/index.js')\n await DossierStore.appendFinding(case_id, address, finding, entity_type ?? 'unknown')\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ case_id, address, updated: true }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Dossier update', err)\n }\n },\n )\n\n server.registerTool(\n 'case_start_session',\n {\n description: 'Start a local investigation session file for a Chain Insights case.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { SessionStore } = await import('../cases/index.js')\n const session = await SessionStore.start(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(session, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Session start', err)\n }\n },\n )\n\n server.registerTool(\n 'case_end_session',\n {\n description: 'End the latest local investigation session for a Chain Insights case with findings and next steps.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n findings: z.string().optional().describe('Key findings from this session'),\n next_steps: z.string().optional().describe('Next investigation steps'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, findings, next_steps }) => {\n try {\n const { SessionStore } = await import('../cases/index.js')\n await SessionStore.end(case_id, {\n findings: findings ?? '',\n nextSteps: next_steps ?? '',\n })\n await SessionStore.archiveOldSessions(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ case_id, ended: true }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Session end', err)\n }\n },\n )\n\n if (!remoteToolNames.has('address_risk')) {\n registerAppTool(\n server,\n 'address_risk',\n {\n title: 'Address Risk',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.address_risk,\n inputSchema: {\n address: z.string().min(1).describe('Full blockchain address to screen'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n compare_address: z.string().optional().describe('Optional second full address for comparison'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ address, network, compare_address }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { addressRisk } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await addressRisk(remoteClient, {\n address,\n network,\n compareAddress: compare_address,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `address-risk-${network}-${address}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Address risk failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('track_funds')) {\n registerAppTool(\n server,\n 'track_funds',\n {\n title: 'Track Funds',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.track_funds,\n inputSchema: {\n trusted_addresses: z.union([z.string().min(1), z.array(z.string().min(1))]).describe('Comma-separated full trusted victim addresses, or an array. Min 1, max 5.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n untrusted_addresses: z.union([z.string(), z.array(z.string())]).optional().describe('Known scammer/untrusted addresses. Max 5.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n max_hops: z.number().int().min(1).max(5).optional(),\n per_address_limit: z.number().int().min(1).max(10).optional(),\n min_amount_sum: z.number().min(0).optional(),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ trusted_addresses, untrusted_addresses, network, case_id, max_hops, per_address_limit, min_amount_sum }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { trackFunds } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await trackFunds(remoteClient, config, {\n trustedAddresses: trusted_addresses,\n untrustedAddresses: untrusted_addresses,\n network,\n caseId: case_id,\n maxHops: max_hops,\n perAddressLimit: per_address_limit,\n minAmountSum: min_amount_sum,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `track-funds-${network}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Track funds failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('scam_topology')) {\n registerAppTool(\n server,\n 'scam_topology',\n {\n title: 'Scam Topology',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.scam_topology,\n inputSchema: {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n victim_address: z.string().min(1).describe('Full victim/source address that anchors the scam incident. Victims are not risky labels.'),\n incident_timestamp_ms: z.number().min(0).describe('Earliest known incident transfer timestamp in milliseconds. Primary traversal uses node-relative wave-arrival filtering.'),\n max_hops: z.number().int().min(1).max(64).optional().describe('Maximum forward expansion depth. Default 16.'),\n activity_policy: z.enum(['node_relative_only', 'global_incident_only']).optional().describe('Traversal activity policy. Default node_relative_only.'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ victim_address, incident_timestamp_ms, network, max_hops, activity_policy, case_id }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { scamTopology } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await scamTopology(remoteClient, config, {\n victimAddress: victim_address,\n network,\n maxHops: max_hops,\n incidentTimestampMs: incident_timestamp_ms,\n activityPolicyMode: activity_policy,\n caseId: case_id,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `scam-topology-${network}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Scam topology failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('stake_insights')) {\n registerAppTool(\n server,\n 'stake_insights',\n {\n title: 'Stake Insights',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.stake_insights,\n inputSchema: {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n address: z.string().optional().describe('Full Bittensor address to inspect as either coldkey or hotkey. Provide exactly one of address, coldkey, or hotkey.'),\n coldkey: z.string().optional().describe('Full Bittensor coldkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n hotkey: z.string().optional().describe('Full Bittensor hotkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n netuid: z.number().int().min(0).optional().describe('Optional subnet netuid filter.'),\n start_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive lower activity timestamp bound in milliseconds.'),\n end_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive upper activity timestamp bound in milliseconds.'),\n start_block: z.number().int().min(0).optional().describe('Optional start block. Current stake graph parity may require timestamp windows instead.'),\n end_block: z.number().int().min(0).optional().describe('Optional end block. Current stake graph parity may require timestamp windows instead.'),\n depth: z.number().int().min(1).max(3).optional().describe('Optional expansion depth limit. First release returns direct STAKES_IN relationships; default 1, max 3.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ network, address, coldkey, hotkey, netuid, start_timestamp_ms, end_timestamp_ms, start_block, end_block, depth }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { stakeInsights } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await stakeInsights(remoteClient, {\n network,\n address,\n coldkey,\n hotkey,\n netuid,\n startTimestampMs: start_timestamp_ms,\n endTimestampMs: end_timestamp_ms,\n startBlock: start_block,\n endBlock: end_block,\n depth,\n })\n const subject = address ?? coldkey ?? hotkey ?? 'subject'\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `stake-insights-${network}-${subject}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Stake insights failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n server.registerTool(\n 'help',\n {\n description: 'Show Chain Insights overview, available tools, and investigation workflow.',\n inputSchema: z.object({}).passthrough(),\n },\n async () => ({\n content: [\n {\n type: 'text' as const,\n text: [\n 'Chain Insights AML investigation workspace for AI agents.',\n '',\n CHAIN_INSIGHTS_WORKFLOW,\n '',\n 'Investigation tools:',\n '- network_capabilities: inspect supported networks, data layers, tool availability, retention windows, and freshness.',\n '- address_risk: screen a full address for AML risk, behavior, neighborhood, exchange exposure, and optional compare_address connection checks.',\n '- stake_insights: explain Bittensor staking around one address, coldkey, or hotkey with net stake, movement amounts, counterparties, backend, and query evidence.',\n '- track_funds: trace up to five trusted/victim addresses plus up to five known untrusted/scammer addresses through intermediaries to exchange deposit addresses.',\n '- scam_topology: derive ML-ready scam_labels from one victim incident address and incident_timestamp_ms.',\n '- graph_query: run read-only GQL/Cypher through the universal graph endpoint. Use USE live_topology, USE archive_topology, or USE facts.',\n '- graph_query_batch: run related read-only graph-language queries through one paid graph call.',\n '',\n 'Case workflow tools:',\n '- case_open: create a local case before preserving evidence.',\n '- case_list: list local cases.',\n '- case_resume: load case context, evidence count, dossiers, and latest session.',\n '- case_add_evidence: append a report or note to the case evidence manifest.',\n '- case_verify_evidence: verify saved evidence integrity.',\n '- case_update_dossier: add a finding to an address/entity dossier.',\n '- case_start_session and case_end_session: record session notes.',\n '',\n 'Wallet tools:',\n '- balance: show the local payment wallet address and Base USDC balance.',\n '- help: show this overview.',\n '',\n GRAPH_REPORT_HINTS,\n '',\n GRAPH_SCHEMA_HINTS,\n ].join('\\n'),\n },\n ],\n isError: false,\n }),\n )\n\n // Register each remote tool locally — passthrough proxy pattern\n for (const tool of tools ?? []) {\n if (HIDDEN_REMOTE_TOOL_NAMES.has(tool.name)) continue\n if (LOCAL_TOOL_NAMES.has(tool.name)) continue\n const inputSchema = knownPublicToolInputSchema(tool.name) ?? z.object({}).passthrough()\n const handler = async (args: unknown) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const normalizedArgs = normalizeRemoteToolArguments(tool.name, args)\n const validationError = validateKnownPublicToolArguments(tool.name, normalizedArgs)\n if (validationError) {\n return {\n content: [{ type: 'text' as const, text: validationError }],\n isError: true,\n }\n }\n const request = {\n name: tool.name,\n arguments: normalizedArgs,\n }\n const requestOptions = remoteToolRequestOptions(tool.name)\n const result = requestOptions\n ? await remoteClient.callTool(request, undefined, requestOptions)\n : await remoteClient.callTool(request)\n return await normalizeRemoteToolResult(result as RemoteToolResult, config, tool.name)\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return {\n content: [{ type: 'text' as const, text: err.message }],\n isError: true,\n }\n }\n const msg = (err as Error).message ?? String(err)\n const isTransport402 = /\\b402\\b/.test(msg) || msg.toLowerCase().includes('payment')\n if (isTransport402) {\n return {\n content: [{\n type: 'text' as const,\n text: `Payment required for ${tool.name}. This tool costs USDC on Base via x402 micropayments. ` +\n 'Next steps: run `chain-insights wallet ready` to check funding and finish one-time payment setup, ' +\n 'run `chain-insights wallet topup` if it says the wallet needs USDC, ' +\n 'or `chain-insights access-key set <key>` if you have been given test access.',\n }],\n isError: true,\n }\n }\n return {\n content: [{ type: 'text' as const, text: `MCP call failed: ${msg}` }],\n isError: true,\n }\n }\n }\n const toolConfig = {\n title: tool.title,\n description: claudeFacingToolDescription(tool),\n inputSchema,\n }\n\n if (hasGraphApp(tool)) {\n registerAppTool(\n server,\n tool.name,\n {\n ...toolConfig,\n _meta: graphToolMeta(tool),\n },\n handler,\n )\n } else {\n server.registerTool(tool.name, toolConfig, handler)\n }\n }\n\n // Connect to stdio transport — after this line, stdout belongs to MCP\n const transport = new StdioServerTransport()\n await server.connect(transport)\n await logger.info('proxy.ready', {\n tools: [\n ...LOCAL_TOOL_NAMES,\n ...(tools ?? []).map((tool) => tool.name).filter((name) => !HIDDEN_REMOTE_TOOL_NAMES.has(name) && !LOCAL_TOOL_NAMES.has(name)),\n ].length,\n })\n\n // Signal handling — clean shutdown\n const shutdown = async () => {\n await logger.info('proxy.shutdown')\n transport.close()\n process.exit(0)\n }\n process.on('SIGINT', () => { void shutdown() })\n process.on('SIGTERM', () => { void shutdown() })\n}\n\n// Entry point — only execute when run as the main module (not when imported by tests)\n// Using process.argv check to detect direct execution vs import\nif (process.argv[1] && import.meta.url.includes(process.argv[1].replace(/\\\\/g, '/'))) {\n createProxy().catch((err) => {\n process.stderr.write(`Chain Insights MCP proxy startup failed: ${(err as Error).message}\\n`)\n process.exit(1)\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-proxy.mjs","names":[],"sources":["../src/mcp/proxy.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport type { ContentBlock, GetPromptResult, Prompt } from '@modelcontextprotocol/sdk/types.js'\nimport { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server'\nimport * as z from 'zod'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { McpTool } from './schema-cache.js'\nimport { HIDDEN_REMOTE_TOOL_NAMES } from './tool-visibility.js'\nimport { PaymentRequiredError } from './client.js'\n\nconst LOCAL_TOOL_NAMES = new Set([\n 'balance',\n 'help',\n 'case_open',\n 'case_list',\n 'case_resume',\n 'case_add_evidence',\n 'case_verify_evidence',\n 'case_export',\n 'case_update_dossier',\n 'case_start_session',\n 'case_end_session',\n])\nconst PUBLIC_GRAPHRAG_PROMPT_NAMES = new Set(['address-risk', 'trace-tools'])\nconst GRAPH_RESOURCE_URI = 'ui://chain-insights/graph'\nconst GRAPH_APP_TOOL_NAMES = new Set([\n 'address_risk',\n 'stake_insights',\n 'trace_victim_funds',\n 'trace_suspect_funds',\n 'trace_deposit_sources',\n])\nconst GRAPH_ARRAY_KEYS = ['nodes', 'edges', 'flows', 'edge_anchors'] as const\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst COMMA_SEPARATED_ADDRESS_FIELDS = new Set([\n 'victim_addresses',\n 'known_suspect_addresses',\n 'suspect_addresses',\n 'deposit_addresses',\n])\n\nconst KNOWN_PUBLIC_TOOL_REQUIRED_ARGS: Record<string, string[]> = {\n address_risk: ['address', 'network'],\n stake_insights: ['network'],\n trace_victim_funds: ['victim_addresses', 'network'],\n trace_suspect_funds: ['suspect_addresses', 'network'],\n trace_deposit_sources: ['deposit_addresses', 'network'],\n graph_query: ['query', 'network'],\n graph_query_batch: ['network', 'queries'],\n}\n\nconst KNOWN_PUBLIC_TOOL_DESCRIPTIONS: Record<string, string> = {\n network_capabilities: 'Return supported Chain Insights networks, capability layers, tool availability, data retention windows, and freshness. Use this before choosing network-specific tools.',\n address_risk: 'Screen one full blockchain address for AML risk, behavior patterns, neighborhood context, exchange exposure, and optional comparison with compare_address. This includes the exchange-behavior analysis formerly covered by money_flows_between_exchanges. Use this as the first tool for a single-address investigation. The tool returns an investigator-ready summary; preserve full addresses exactly.',\n stake_insights: 'Explain Bittensor staking behavior around one full address, coldkey, or hotkey. Requires network plus exactly one of address, coldkey, or hotkey. Returns net staked/unstaked amounts, active coldkey-hotkey-netuid relationships, aggregate stake movement amounts, top counterparties, first/last activity, source backend, query evidence, and optional graph report metadata.',\n trace_victim_funds: 'Trace victim/source funds forward through intermediaries to exchange deposit candidates. Use only when the input addresses are victims or trusted stolen-source addresses; do not use for suspected deposit addresses because traceback belongs to trace_deposit_sources. Exchange hot wallets are terminal only, never candidate deposits. Returns chain-insights.trace.v1 and preserves full addresses exactly.',\n trace_suspect_funds: 'Trace suspected scammer, mule, operator, or laundering-ring funds forward to cashout topology. Use when the input addresses are suspect-controlled seeds; incident_timestamp_ms is optional. Do not use for victim/source addresses or suspected deposit endpoints. Exchange hot wallets are terminal only, never candidate suspects or intermediates. Returns chain-insights.trace.v1 and preserves full addresses exactly.',\n trace_deposit_sources: 'Trace backward from suspected deposit/cashout addresses to upstream sources, shared funders, and convergence. Use only when the input addresses are suspected non-exchange deposit endpoints; do not treat these seeds as scammers and do not continue forward from discovered suspects here. Exchange hot wallets are excluded as seeds and upstream sources. Returns chain-insights.trace.v1 and preserves full addresses exactly.',\n graph_query: 'Run a read-only GQL/Cypher query through the Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Cross-layer correlated joins may be limited by the active graph endpoint; preserve full addresses exactly.',\n graph_query_batch: 'Run multiple read-only GQL/Cypher queries through the Chain Insights graph endpoint in one paid batch. Prefer this for related topology/facts reads.',\n}\nconst FALLBACK_GRAPH_PRIMITIVE_TOOL_NAMES = ['network_capabilities', 'graph_query', 'graph_query_batch'] as const\n\ntype ToolInputShape = Record<string, z.ZodTypeAny>\ntype ToolHandler = (args: unknown, extra?: unknown) => Promise<unknown> | unknown\ntype ToolRegistrationConfig = Parameters<McpServer['registerTool']>[1]\ntype ToolCallInput = { name: string; arguments?: Record<string, unknown> }\ntype RemoteToolCaller = {\n callTool: Client['callTool']\n}\n\nconst NETWORK_DESCRIPTION = 'Required network to query. Do not guess; use network_capabilities or ask the user if missing.'\nconst REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS = 15 * 60 * 1000\n\nconst CHAIN_INSIGHTS_WORKFLOW = [\n 'Workflow:',\n '1. If the user is starting or continuing an investigation, use case_open or case_list/case_resume first.',\n '2. Do not call investigation tools until required arguments are known. Network is required; use network_capabilities to check supported networks, data layers, retention, and freshness, or ask the user if missing.',\n '3. Use address_risk for single-address enrichment. Use trace_victim_funds for victim/source forward tracing, trace_deposit_sources for reverse traceback from suspected deposit endpoints, and trace_suspect_funds for suspect-controlled outbound laundering/cashout topology. Use stake_insights for Bittensor staking behavior. Use graph_query(_batch) only when the high-level trace tools do not answer the exact question.',\n '4. After a material result, preserve it with case_add_evidence when a case is active or ask whether to create/select a case.',\n '5. Use case_update_dossier for durable address/entity findings and case_start_session/case_end_session for session notes.',\n '6. When a case reaches a useful checkpoint, use case_verify_evidence and case_export to produce Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT-ready files.',\n].join('\\n')\n\nconst GRAPH_SCHEMA_HINTS = [\n 'Graph query hints for network=bittensor:',\n '- Common live topology node labels include Address and may include legacy enrichment labels. Do not depend on Exchange/Miner graph labels for correctness; use address properties such as labels and is_exchange when available.',\n '- Address nodes are identity plus traversal hints. Lifetime/global address metrics live in USE facts as AddressFeature, not as topology semantics.',\n '- Facts graph labels include Address, AddressLabel, AddressFeature, RiskScore, and Asset.',\n '- Facts graph relationships include (:Address)-[:HAS_FEATURE]->(:AddressFeature), (:Address)-[:HAS_LABEL]->(:AddressLabel), and (:Address)-[:HAS_RISK_SCORE]->(:RiskScore).',\n '- Risk and ML properties may appear as live hints, but source-of-truth risk rows are RiskScore facts.',\n '- Common relationships include FLOWS_TO, OPERATED_FROM, SERVED_FROM, REGISTERED_NEURON, BELONGS_TO, SYBIL_CLUSTER, LAYERING_HOP, BURST_ACTIVITY, CYCLE_PARTICIPANT, SMURFING_CLUSTER.',\n '- FLOWS_TO properties are scoped to the selected topology graph and commonly carry amount_sum, amount_usd_sum, tx_count, first_seen_timestamp, last_seen_timestamp, first_tx_id, last_tx_id. Confirm available fields through runtime schema before relying on them.',\n '- Traversal rule: for BFS, fixed-hop fallback, shortest-path, or manual FLOWS_TO traversal, exchange hot wallets are terminal endpoints only. Do not expand from, through, or classify exchange nodes as deposit, suspect, or intermediate candidates; filter every non-terminal node with is_exchange IS NULL.',\n '- Start schema discovery with endpoint-safe property reads: MATCH (n:Address) WHERE n.address IS NOT NULL RETURN n.labels AS labels, n.address AS address LIMIT 20',\n '- Relationship discovery: MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN r.amount_sum AS amount_sum, r.amount_usd_sum AS amount_usd_sum LIMIT 20',\n '- graph_query uses the active Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment.',\n '- Archive topology labels include Address and TopologySnapshot. Archived money-flow topology is represented as (:Address)-[:FLOWS_TO]->(:Address) relationships with period_granularity, period_start_date, and period_end_date.',\n '- All graph_query calls are read-only. Never use CREATE, INSERT, MERGE, SET, DELETE, REMOVE, DROP, DETACH, ADD, CONNECT, DISCONNECT, ALTER, TRUNCATE, GRANT, or REVOKE.',\n '- Use USE facts graph patterns for fact and enrichment reads. Do not query internal table namespaces directly.',\n].join('\\n')\n\nconst GRAPH_REPORT_HINTS = [\n 'Graph visualization behavior:',\n '- Graph-backed tools return the investigator report as text content and keep raw graph data out of LLM-visible structuredContent.',\n '- Raw graph data is stored locally under Chain Insights reports/graphs and exposed to the graph app as _meta.chainInsights.graph.url.',\n '- The local graph report server is started automatically by the MCP server when a graph-backed tool returns a report URL; do not ask the user to run chain-insights serve for Claude Desktop graph iframes.',\n '- If an iframe reports that a graph report fetch failed, retry the graph-backed tool call so Chain Insights can recreate the report URL and ensure the local report server is running.',\n].join('\\n')\n\nconst SERVER_INSTRUCTIONS = [\n 'Chain Insights is a local AML investigation workspace for AI agents.',\n CHAIN_INSIGHTS_WORKFLOW,\n GRAPH_REPORT_HINTS,\n GRAPH_SCHEMA_HINTS,\n 'Presentation rules: preserve tool summaries as returned; never truncate blockchain addresses; use case tools to preserve evidence when a case exists.',\n].join('\\n\\n')\n\nfunction readGraphAppHtml(): string {\n const candidates = [\n path.resolve(__dirname, 'templates', 'graph.html'),\n path.resolve(__dirname, '..', 'templates', 'graph.html'),\n path.resolve(__dirname, '..', 'viz', 'templates', 'graph.html'),\n ]\n\n for (const candidate of candidates) {\n try {\n return readFileSync(candidate, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n }\n\n throw new Error(`Graph MCP app template not found. Tried: ${candidates.join(', ')}`)\n}\n\nfunction graphArtifactOrigins(config: Pick<InvestigatorConfig, 'serverPort'>): string[] {\n return [\n `http://127.0.0.1:${config.serverPort}`,\n `http://localhost:${config.serverPort}`,\n ]\n}\n\nfunction hasGraphApp(tool: McpTool): boolean {\n const configuredUri = tool._meta?.ui\n if (\n configuredUri &&\n typeof configuredUri === 'object' &&\n 'resourceUri' in configuredUri &&\n configuredUri.resourceUri === GRAPH_RESOURCE_URI\n ) {\n return true\n }\n\n if (tool._meta?.['ui/resourceUri'] === GRAPH_RESOURCE_URI) return true\n if (GRAPH_APP_TOOL_NAMES.has(tool.name)) return true\n return JSON.stringify(tool.outputSchema ?? {}).includes('\"app_data\"')\n}\n\nfunction graphToolMeta(tool: McpTool): Record<string, unknown> & { ui: { resourceUri: string } } {\n const meta = { ...(tool._meta ?? {}) }\n const ui =\n meta.ui && typeof meta.ui === 'object' && !Array.isArray(meta.ui)\n ? { ...(meta.ui as Record<string, unknown>) }\n : {}\n\n return {\n ...meta,\n ui: {\n ...ui,\n resourceUri: GRAPH_RESOURCE_URI,\n },\n }\n}\n\nfunction knownPublicToolInputSchema(toolName: string): ToolInputShape | null {\n switch (toolName) {\n case 'address_risk':\n return {\n address: z.string().min(1).describe('Full blockchain address to screen'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n compare_address: z.string().optional().describe('Optional second full address for comparison'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'trace_victim_funds':\n return {\n victim_addresses: z.string().min(1).describe('Comma-separated full victim/source addresses. Min 1, max 5.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n known_suspect_addresses: z.string().optional().describe('Optional known suspect addresses for context only. They are not reverse-traced by this tool. Max 5.'),\n incident_timestamp_ms: z.number().min(0).optional().describe('Optional incident timestamp in milliseconds.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'trace_suspect_funds':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n suspect_addresses: z.string().min(1).describe('Comma-separated full suspected scammer, mule, operator, or laundering-ring addresses. Min 1, max 5.'),\n incident_timestamp_ms: z.number().min(0).optional().describe('Optional incident timestamp in milliseconds. This tool also works without a timestamp.'),\n max_hops: z.number().int().min(1).max(5).optional().describe('Maximum forward trace hops. Default 3.'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n }\n case 'trace_deposit_sources':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n deposit_addresses: z.string().min(1).describe('Comma-separated full suspected deposit/cashout addresses. Min 1, max 5.'),\n max_hops: z.number().int().min(1).max(5).optional().describe('Maximum reverse traceback hops. Default 2.'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'stake_insights':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n address: z.string().optional().describe('Full Bittensor address to inspect as either coldkey or hotkey. Provide exactly one of address, coldkey, or hotkey.'),\n coldkey: z.string().optional().describe('Full Bittensor coldkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n hotkey: z.string().optional().describe('Full Bittensor hotkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n netuid: z.number().int().min(0).optional().describe('Optional subnet netuid filter.'),\n start_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive lower activity timestamp bound in milliseconds.'),\n end_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive upper activity timestamp bound in milliseconds.'),\n start_block: z.number().int().min(0).optional().describe('Optional start block. Current stake graph parity may require timestamp windows instead.'),\n end_block: z.number().int().min(0).optional().describe('Optional end block. Current stake graph parity may require timestamp windows instead.'),\n depth: z.number().int().min(1).max(3).optional().describe('Optional expansion depth limit. First release returns direct STAKES_IN relationships; default 1, max 3.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n }\n case 'graph_query':\n return {\n query: z.string().min(1).describe('Read-only GQL/Cypher query. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n }\n case 'graph_query_batch':\n return {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n queries: z.array(z.object({\n id: z.string().optional(),\n query: z.string().min(1).describe('Read-only GQL/Cypher query'),\n })).min(1).max(20),\n per_query_timeout_seconds: z.number().int().min(1).max(600).optional(),\n }\n default:\n return null\n }\n}\n\nfunction fallbackGraphPrimitiveTools(): McpTool[] {\n return FALLBACK_GRAPH_PRIMITIVE_TOOL_NAMES.map((name) => ({\n name,\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS[name],\n }))\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction redactLogValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(redactLogValue)\n if (!isRecord(value)) return value\n return Object.fromEntries(Object.entries(value).map(([key, entry]) => {\n if (/token|secret|password|private.?key|authorization/i.test(key)) return [key, '[redacted]']\n return [key, redactLogValue(entry)]\n }))\n}\n\nfunction errorForLog(err: unknown): Record<string, unknown> {\n const error = err as Error\n return {\n name: error.name ?? 'Error',\n message: error.message ?? String(err),\n }\n}\n\nfunction sanitizeCypher(query: string): string {\n return query.replace(/\\s+/g, ' ').trim()\n}\n\nfunction cypherLogPayload(tool: string, args: unknown): Record<string, unknown> | null {\n if (!isRecord(args)) return null\n if (tool === 'graph_query') {\n return {\n network: args.network,\n queries: [{\n id: tool,\n query: typeof args.query === 'string' ? sanitizeCypher(args.query) : args.query,\n }],\n }\n }\n if (tool === 'graph_query_batch') {\n const queries = Array.isArray(args.queries) ? args.queries : []\n return {\n network: args.network,\n per_query_timeout_seconds: args.per_query_timeout_seconds,\n query_count: queries.length,\n queries: queries.map((entry, index) => isRecord(entry)\n ? {\n id: typeof entry.id === 'string' ? entry.id : `q${index + 1}`,\n query: typeof entry.query === 'string' ? sanitizeCypher(entry.query) : entry.query,\n }\n : { id: `q${index + 1}`, query: entry }),\n }\n }\n return null\n}\n\nfunction createMcpLogger(config: Pick<InvestigatorConfig, 'dataDir'>) {\n const disabled = process.env.CHAIN_INSIGHTS_MCP_LOG === '0'\n const filePath = process.env.CHAIN_INSIGHTS_MCP_LOG_PATH?.trim() || path.join(config.dataDir, '.chain-insights', 'runtime', 'logs', 'mcp-proxy.jsonl')\n\n async function write(level: 'info' | 'error', event: string, fields: Record<string, unknown> = {}): Promise<void> {\n if (disabled) return\n try {\n await mkdir(path.dirname(filePath), { recursive: true })\n await appendFile(filePath, JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event,\n pid: process.pid,\n ...fields,\n }) + '\\n', { mode: 0o600 })\n } catch {\n // Logging must never break the stdio MCP server.\n }\n }\n\n return {\n filePath,\n info: (event: string, fields?: Record<string, unknown>) => write('info', event, fields),\n error: (event: string, fields?: Record<string, unknown>) => write('error', event, fields),\n }\n}\n\nfunction installToolLogging(server: McpServer, logger: ReturnType<typeof createMcpLogger>): void {\n const existingRegisterTool = server.registerTool\n const originalRegisterTool = existingRegisterTool.bind(server)\n const wrappedRegisterTool = ((name: string, config: ToolRegistrationConfig, handler: ToolHandler) => {\n const wrapped: ToolHandler = async (args, extra) => {\n const startedAt = Date.now()\n await logger.info('tool.start', {\n tool: name,\n args: redactLogValue(args),\n })\n try {\n const result = await handler(args, extra)\n const isError = isRecord(result) && result.isError === true\n await logger.info('tool.end', {\n tool: name,\n duration_ms: Date.now() - startedAt,\n is_error: isError,\n })\n return result\n } catch (err) {\n await logger.error('tool.throw', {\n tool: name,\n duration_ms: Date.now() - startedAt,\n error: errorForLog(err),\n })\n throw err\n }\n }\n return originalRegisterTool(name, config, wrapped as never)\n }) as typeof server.registerTool\n Object.assign(wrappedRegisterTool, existingRegisterTool)\n server.registerTool = wrappedRegisterTool\n}\n\nfunction installRemoteCypherLogging(remoteClient: RemoteToolCaller, logger: ReturnType<typeof createMcpLogger>): void {\n const existingCallTool = remoteClient.callTool\n const originalCallTool = existingCallTool.bind(remoteClient)\n const wrappedCallTool = (async (...args: Parameters<Client['callTool']>) => {\n const input = args[0] as ToolCallInput\n const queryPayload = cypherLogPayload(input.name, input.arguments)\n const startedAt = Date.now()\n if (queryPayload) {\n await logger.info('topology.start', {\n tool: input.name,\n ...queryPayload,\n })\n }\n try {\n const result = await originalCallTool(...args)\n if (queryPayload) {\n await logger.info('topology.end', {\n tool: input.name,\n duration_ms: Date.now() - startedAt,\n is_error: isRecord(result) && result.isError === true,\n })\n }\n return result\n } catch (err) {\n if (queryPayload) {\n await logger.error('cypher.throw', {\n tool: input.name,\n duration_ms: Date.now() - startedAt,\n error: errorForLog(err),\n })\n }\n throw err\n }\n }) as typeof remoteClient.callTool\n Object.assign(wrappedCallTool, existingCallTool)\n remoteClient.callTool = wrappedCallTool\n}\n\nfunction remoteToolRequestOptions(toolName: string): Parameters<Client['callTool']>[2] | undefined {\n if (toolName === 'graph_query' || toolName === 'graph_query_batch') {\n return {\n timeout: REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS,\n maxTotalTimeout: REMOTE_GRAPH_TOOL_REQUEST_TIMEOUT_MS,\n }\n }\n return undefined\n}\n\nfunction isBlankArgument(value: unknown): boolean {\n if (value === undefined || value === null) return true\n if (typeof value === 'string') return value.trim() === ''\n if (Array.isArray(value)) return value.length === 0 || value.every(isBlankArgument)\n return false\n}\n\nfunction normalizeRemoteToolArguments(toolName: string, args: unknown): Record<string, unknown> {\n const normalized = isRecord(args) ? { ...args } : {}\n if (!(toolName in KNOWN_PUBLIC_TOOL_REQUIRED_ARGS)) return normalized\n\n for (const fieldName of COMMA_SEPARATED_ADDRESS_FIELDS) {\n const value = normalized[fieldName]\n if (Array.isArray(value)) {\n normalized[fieldName] = value\n .map((entry) => String(entry).trim())\n .filter(Boolean)\n .join(',')\n }\n }\n\n return normalized\n}\n\nfunction validateKnownPublicToolArguments(\n toolName: string,\n args: Record<string, unknown>,\n): string | null {\n const requiredArgs = KNOWN_PUBLIC_TOOL_REQUIRED_ARGS[toolName]\n if (!requiredArgs) return null\n\n for (const argName of requiredArgs) {\n if (isBlankArgument(args[argName])) {\n return `Missing required argument: ${argName}`\n }\n }\n\n return null\n}\n\nfunction claudeFacingToolDescription(tool: McpTool): string {\n const baseDescription = KNOWN_PUBLIC_TOOL_DESCRIPTIONS[tool.name] ?? tool.description ?? tool.name\n const requiredArgs = KNOWN_PUBLIC_TOOL_REQUIRED_ARGS[tool.name]\n if (!requiredArgs) return baseDescription\n return [\n baseDescription,\n '',\n `Required arguments: ${requiredArgs.join(', ')}.`,\n 'If the user did not provide the network, ask for it before calling this tool. Do not guess a default network.',\n ].join('\\n')\n}\n\ntype RemoteToolResult = {\n content?: ContentBlock[]\n structuredContent?: Record<string, unknown>\n _meta?: Record<string, unknown>\n isError?: boolean\n}\n\ntype PromptArgs = Record<string, string | undefined>\n\nfunction promptResult(text: string, description?: string): GetPromptResult {\n return {\n description,\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text,\n },\n },\n ],\n }\n}\n\nfunction compactPromptArguments(args: PromptArgs): Record<string, string> {\n const compact: Record<string, string> = {}\n for (const [key, value] of Object.entries(args)) {\n if (typeof value === 'string' && value.trim() !== '') {\n compact[key] = value\n }\n }\n return compact\n}\n\nfunction promptArgumentSchema(promptName: string, argument: NonNullable<Prompt['arguments']>[number]) {\n const description = PUBLIC_GRAPHRAG_PROMPT_NAMES.has(promptName) && argument.name === 'network'\n ? NETWORK_DESCRIPTION\n : argument.description ?? argument.name\n const schema = z.string().describe(description)\n if (PUBLIC_GRAPHRAG_PROMPT_NAMES.has(promptName) && argument.name === 'network') {\n return schema\n }\n return argument.required === false ? schema.optional() : schema\n}\n\nfunction registerRemotePrompt(server: McpServer, remoteClient: Client, prompt: Prompt): void {\n const argsSchema: Record<string, z.ZodTypeAny> = {}\n for (const argument of prompt.arguments ?? []) {\n argsSchema[argument.name] = promptArgumentSchema(prompt.name, argument)\n }\n\n server.registerPrompt(\n prompt.name,\n {\n title: prompt.title,\n description: prompt.description,\n argsSchema,\n },\n async (args) => remoteClient.getPrompt({\n name: prompt.name,\n arguments: compactPromptArguments(args as PromptArgs),\n }),\n )\n}\n\nfunction registerLocalPrompts(server: McpServer, remotePromptNames: Set<string>): void {\n if (!remotePromptNames.has('address-risk')) {\n server.registerPrompt(\n 'address-risk',\n {\n title: 'Address Risk',\n description: 'Screen an address for AML risk, behavioral patterns, neighborhood profile, and exchange links.',\n argsSchema: {\n address: z.string().describe('Full blockchain address to screen'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ address, network }) => promptResult(\n [\n `Use Chain Insights address_risk on ${network} for:`,\n '',\n `\\`${address}\\``,\n '',\n 'Present the summary as-is. Do not add analysis, verdicts, or risk assessments; the tool output already contains the risk assessment.',\n ].join('\\n'),\n 'Address risk screening',\n ),\n )\n }\n\n if (!remotePromptNames.has('trace-tools')) {\n server.registerPrompt(\n 'trace-tools',\n {\n title: 'Trace Tools',\n description: 'Choose trace_victim_funds, trace_deposit_sources, or trace_suspect_funds based on the evidence role.',\n argsSchema: {\n addresses: z.string().describe('Input addresses, comma-separated full addresses'),\n role: z.enum(['victim', 'suspect', 'deposit']).describe('Role of the supplied addresses'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ addresses, role, network }) => {\n const toolName = role === 'deposit' ? 'trace_deposit_sources' : `trace_${role}_funds`\n return promptResult([\n `Use Chain Insights ${toolName} on ${network}.`,\n '',\n 'Full addresses:',\n addresses,\n '',\n role === 'deposit'\n ? 'For deposit role, use trace_deposit_sources rather than trace_deposit_funds.'\n : 'Present the summary as-is and use continuation.recommended_next_tools for follow-up.',\n ].join('\\n'), 'Trace role-specific funds')\n },\n )\n }\n\n server.registerPrompt(\n 'graph-query',\n {\n title: 'Federated Graph Query',\n description: 'Run a read-only GQL/Cypher query through the Chain Insights graph endpoint.',\n argsSchema: {\n query: z.string().describe('Read-only GQL/Cypher query'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n },\n },\n async ({ query, network }) => promptResult(\n [\n `Use Chain Insights graph_query on ${network} with this read-only GQL/Cypher query:`,\n '',\n '```gql',\n query,\n '```',\n '',\n 'Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Return full address properties; never shorten addresses with ellipses.',\n ].join('\\n'),\n 'Federated graph query',\n ),\n )\n\n server.registerPrompt(\n 'graph-query-batch',\n {\n title: 'Federated Graph Query Batch',\n description: 'Run related read-only GQL/Cypher queries through the Chain Insights graph endpoint in one paid batch.',\n argsSchema: {\n queries: z.string().describe('JSON array of query objects with optional id and required query fields'),\n network: z.string().describe(NETWORK_DESCRIPTION),\n per_query_timeout_seconds: z.string().optional().describe('Optional integer timeout per query, 1-600 seconds'),\n },\n },\n async ({ queries, network, per_query_timeout_seconds }) => promptResult(\n [\n `Use Chain Insights graph_query_batch on ${network} with these read-only GQL/Cypher queries:`,\n '',\n '```json',\n queries,\n '```',\n per_query_timeout_seconds ? `per_query_timeout_seconds: ${per_query_timeout_seconds}` : '',\n '',\n 'Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Return full address properties; never shorten addresses with ellipses.',\n ].filter(Boolean).join('\\n'),\n 'Federated graph batch query',\n ),\n )\n\n server.registerPrompt(\n 'balance',\n {\n title: 'Wallet Balance',\n description: 'Show the local Chain Insights payment wallet address and Base USDC balance.',\n argsSchema: {},\n },\n async () => promptResult(\n 'Use Chain Insights balance. Show the wallet address, network, token, and balance exactly as returned.',\n 'Wallet balance',\n ),\n )\n\n server.registerPrompt(\n 'help',\n {\n title: 'Chain Insights Help',\n description: 'Show available Chain Insights tools and investigation case workflow.',\n argsSchema: {},\n },\n async () => promptResult(\n 'Use Chain Insights help. Summarize the available tools and investigation case workflow without inventing capabilities.',\n 'Chain Insights help',\n ),\n )\n\n server.registerPrompt(\n 'open-investigation-case',\n {\n title: 'Open Investigation Case',\n description: 'Create a local Chain Insights case for an investigation.',\n argsSchema: {\n name: z.string().describe('Case name'),\n tags: z.string().optional().describe('Comma-separated tags'),\n description: z.string().optional().describe('Brief investigation description'),\n },\n },\n async ({ name, tags, description }) => promptResult(\n [\n 'Use Chain Insights case_open to create a local investigation case.',\n '',\n `name: \\`${name}\\``,\n tags ? `tags: \\`${tags}\\`` : '',\n description ? `description: ${description}` : '',\n ].filter(Boolean).join('\\n'),\n 'Open investigation case',\n ),\n )\n\n server.registerPrompt(\n 'resume-investigation-case',\n {\n title: 'Resume Investigation Case',\n description: 'Load local Chain Insights case context, evidence count, dossiers, and latest session.',\n argsSchema: {\n case_id: z.string().describe('Chain Insights case ID'),\n },\n },\n async ({ case_id }) => promptResult(\n `Use Chain Insights case_resume for case_id: \\`${case_id}\\`. Continue from the returned context.`,\n 'Resume investigation case',\n ),\n )\n\n server.registerPrompt(\n 'save-investigation-evidence',\n {\n title: 'Save Investigation Evidence',\n description: 'Append a tool result or analyst note to a local Chain Insights case evidence manifest.',\n argsSchema: {\n case_id: z.string().describe('Chain Insights case ID'),\n source: z.string().describe('Tool or source name'),\n },\n },\n async ({ case_id, source }) => promptResult(\n [\n 'Use Chain Insights case_add_evidence after the next relevant tool result.',\n '',\n `case_id: \\`${case_id}\\``,\n `source: \\`${source}\\``,\n 'content: use the exact report or note that should become evidence.',\n ].join('\\n'),\n 'Save investigation evidence',\n ),\n )\n}\n\nfunction hasGraphArrayFields(value: unknown): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n return GRAPH_ARRAY_KEYS.some((key) => Array.isArray(record[key]))\n}\n\nfunction sanitizeStructuredContentForGraphPayload(\n structuredContent: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!structuredContent) return undefined\n return sanitizeStructuredValue(structuredContent) as Record<string, unknown>\n}\n\nfunction sanitizeStructuredValue(value: unknown): unknown {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return value\n\n const sanitized: Record<string, unknown> = {}\n for (const [key, childValue] of Object.entries(value)) {\n if (key === 'app_data') continue\n if (GRAPH_ARRAY_KEYS.includes(key as (typeof GRAPH_ARRAY_KEYS)[number]) && Array.isArray(childValue)) {\n continue\n }\n sanitized[key] = sanitizeStructuredValue(childValue)\n }\n\n return sanitized\n}\n\nfunction getRemoteGraphPayload(result: RemoteToolResult): Record<string, unknown> | null {\n const chainInsights = result._meta?.chainInsights\n if (!chainInsights || typeof chainInsights !== 'object' || Array.isArray(chainInsights)) return null\n const graph = (chainInsights as Record<string, unknown>).graph\n if (graph === undefined) return null\n if (!graph || typeof graph !== 'object' || Array.isArray(graph)) {\n throw new Error('Invalid remote graph payload')\n }\n\n const graphRecord = graph as Record<string, unknown>\n if (!('data' in graphRecord)) {\n if ('url' in graphRecord || hasGraphArrayFields(graphRecord)) {\n throw new Error('Invalid remote graph payload')\n }\n return null\n }\n\n const data = graphRecord.data\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new Error('Invalid remote graph payload')\n }\n\n return data as Record<string, unknown>\n}\n\nasync function normalizeRemoteToolResult(\n result: RemoteToolResult,\n config: Pick<InvestigatorConfig, 'dataDir' | 'serverPort'>,\n toolName = 'remote-graph',\n) {\n const graphPayload = getRemoteGraphPayload(result)\n const meta = { ...(result._meta ?? {}) }\n\n if (graphPayload) {\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const report = await writeGraphReport(graphPayload as never, {\n serverPort: config.serverPort,\n slug: toolName || 'remote-graph',\n })\n await ensureArtifactServer(config.serverPort)\n meta.chainInsights = {\n ...((meta.chainInsights as Record<string, unknown>) ?? {}),\n graph: {\n schema: report.schema,\n url: report.url,\n },\n }\n }\n\n return {\n content: result.content ?? [],\n structuredContent: sanitizeStructuredContentForGraphPayload(result.structuredContent),\n _meta: Object.keys(meta).length > 0 ? meta : undefined,\n isError: result.isError,\n }\n}\n\n/**\n * Core proxy logic — exported so tests can inject dependencies directly.\n * The IIFE at the bottom calls this with real dependencies.\n *\n * stdout purity: NEVER write to stdout in this file. Use console.error() or process.stderr.write() only.\n * All diagnostic output goes to console.error() or process.stderr.write().\n */\nexport async function createProxy(): Promise<void> {\n // Lazy imports to avoid module-load side effects (critical for stdio proxy)\n const { loadConfig } = await import('../config/index.js')\n const { activeDataDir, findActiveWorkspace } = await import('../workspace/active.js')\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./client.js')\n const { loadSchema, saveSchema } = await import('./schema-cache.js')\n\n const loadedConfig = await loadConfig()\n const activeWorkspace = findActiveWorkspace()\n const config = {\n ...loadedConfig,\n dataDir: activeDataDir(loadedConfig.dataDir),\n }\n const logger = createMcpLogger(config)\n await logger.info('proxy.start', {\n data_dir: config.dataDir,\n workspace_root: activeWorkspace?.root,\n graph_mcp_mode: config.graphMcpMode,\n graph_mcp_endpoint: resolveGraphMcpEndpoint(config),\n log_path: logger.filePath,\n })\n const graphMcpEndpoint = resolveGraphMcpEndpoint(config)\n\n // Build remote MCP client. The local Chain Insights MCP surface must still\n // start when the graph endpoint is temporarily unavailable so agents can use\n // help, wallet, and case workflow tools.\n const remoteClient = new Client({ name: 'chain-insights-proxy-client', version: PACKAGE_VERSION })\n let remoteConnected = false\n let remoteUnavailableMessage: string | undefined\n let mcpFetch: typeof fetch | undefined\n\n try {\n mcpFetch = await createConfiguredGraphMcpFetch(config)\n } catch (err) {\n await logger.error('remote.fetch_setup_failed', {\n endpoint: graphMcpEndpoint,\n error: errorForLog(err),\n })\n remoteUnavailableMessage = `Graph MCP setup unavailable at ${graphMcpEndpoint}: ${(err as Error).message}`\n process.stderr.write(\n `Chain Insights MCP graph tools unavailable: ${remoteUnavailableMessage}. Local Chain Insights tools are still available.\\n`,\n )\n }\n\n if (mcpFetch) {\n try {\n await remoteClient.connect(\n new StreamableHTTPClientTransport(new URL(graphMcpEndpoint), { fetch: mcpFetch }),\n )\n remoteConnected = true\n await logger.info('remote.connect', {\n transport: 'streamable_http',\n endpoint: graphMcpEndpoint,\n })\n } catch {\n await logger.error('remote.connect_failed', {\n transport: 'streamable_http',\n endpoint: graphMcpEndpoint,\n })\n // StreamableHTTP failed — try SSE fallback (assumption A1 from RESEARCH.md)\n try {\n const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js')\n await remoteClient.connect(\n new SSEClientTransport(new URL(graphMcpEndpoint), { fetch: mcpFetch }),\n )\n remoteConnected = true\n await logger.info('remote.connect', {\n transport: 'sse',\n endpoint: graphMcpEndpoint,\n })\n } catch (err2) {\n await logger.error('remote.connect_failed', {\n transport: 'sse',\n endpoint: graphMcpEndpoint,\n error: errorForLog(err2),\n })\n remoteUnavailableMessage = `Graph MCP unreachable at ${graphMcpEndpoint}: ${(err2 as Error).message}`\n process.stderr.write(\n `Chain Insights MCP graph tools unavailable: ${remoteUnavailableMessage}. Local Chain Insights tools are still available.\\n`,\n )\n }\n }\n }\n if (remoteConnected) installRemoteCypherLogging(remoteClient as unknown as RemoteToolCaller, logger)\n\n // Schema cache check — skip remote listTools call on cache hit\n let tools: McpTool[] | null = await loadSchema(graphMcpEndpoint)\n\n if (!tools && remoteConnected) {\n // Cache miss — fetch tools from remote (client is already connected above)\n const result = await remoteClient.listTools()\n tools = result.tools as McpTool[]\n await saveSchema(tools, graphMcpEndpoint)\n await logger.info('schema.tools_loaded', {\n source: 'remote',\n count: tools.length,\n })\n } else if (tools) {\n await logger.info('schema.tools_loaded', {\n source: 'cache',\n count: tools.length,\n })\n } else {\n tools = fallbackGraphPrimitiveTools()\n await logger.info('schema.tools_loaded', {\n source: 'unavailable',\n count: tools.length,\n })\n }\n const remoteToolNames = new Set((tools ?? []).map((tool) => tool.name))\n\n // Build local stdio proxy server\n const server = new McpServer(\n { name: 'chain-insights', version: PACKAGE_VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n )\n installToolLogging(server, logger)\n\n const remotePrompts: Prompt[] = []\n if (remoteConnected) {\n try {\n const promptResult = await remoteClient.listPrompts()\n for (const prompt of promptResult.prompts as Prompt[]) {\n if (PUBLIC_GRAPHRAG_PROMPT_NAMES.has(prompt.name)) {\n remotePrompts.push(prompt)\n }\n }\n } catch (err) {\n await logger.error('remote.prompts_failed', {\n endpoint: graphMcpEndpoint,\n error: errorForLog(err),\n })\n process.stderr.write(\n `Chain Insights MCP prompt passthrough unavailable at ${graphMcpEndpoint}: ${(err as Error).message}\\n`,\n )\n }\n }\n\n const remotePromptNames = new Set(remotePrompts.map((prompt) => prompt.name))\n for (const prompt of remotePrompts) {\n registerRemotePrompt(server, remoteClient, prompt)\n }\n registerLocalPrompts(server, remotePromptNames)\n\n const caseToolError = (label: string, err: unknown) => ({\n content: [{ type: 'text' as const, text: `${label} failed: ${(err as Error).message}` }],\n isError: true,\n })\n\n const parseTags = (tags: string | string[] | undefined): string[] => {\n if (Array.isArray(tags)) return tags.map((tag) => tag.trim()).filter(Boolean)\n if (typeof tags === 'string') return tags.split(',').map((tag) => tag.trim()).filter(Boolean)\n return []\n }\n\n server.registerTool(\n 'balance',\n {\n description: 'Show the local Chain Insights payment wallet address and Base USDC balance.',\n inputSchema: z.object({}).passthrough(),\n },\n async () => {\n try {\n const { getWalletAccount, getWalletBalanceText } = await import('../wallet/tools.js')\n const account = await getWalletAccount()\n return {\n content: [{ type: 'text' as const, text: await getWalletBalanceText(account) }],\n isError: false,\n }\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Balance failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n\n registerAppResource(\n server,\n 'Fund Flow Graph',\n GRAPH_RESOURCE_URI,\n {\n description: 'Interactive D3 force-directed graph for fund flow and pattern visualization. It loads local graph report URLs returned in _meta.chainInsights.graph.url.',\n _meta: {\n ui: {\n csp: {\n resourceDomains: graphArtifactOrigins(config),\n connectDomains: graphArtifactOrigins(config),\n },\n },\n },\n },\n async () => ({\n contents: [\n {\n uri: GRAPH_RESOURCE_URI,\n mimeType: RESOURCE_MIME_TYPE,\n text: readGraphAppHtml(),\n _meta: {\n ui: {\n csp: {\n resourceDomains: graphArtifactOrigins(config),\n connectDomains: graphArtifactOrigins(config),\n },\n },\n },\n },\n ],\n }),\n )\n\n server.registerTool(\n 'case_open',\n {\n description: 'Create a local Chain Insights investigation case. Use this before saving evidence, dossiers, or session notes for a new investigation.',\n inputSchema: {\n name: z.string().min(1).describe('Case name'),\n tags: z.union([z.string(), z.array(z.string())]).optional().describe('Comma-separated tags or string array'),\n description: z.string().optional().describe('Brief investigation description'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ name, tags, description }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const created = await CaseStore.create({\n name,\n tags: parseTags(tags),\n description: description ?? '',\n })\n const { casesRoot } = await import('../cases/store.js')\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n case_id: created.id,\n name: created.name,\n status: created.status,\n tags: created.tags,\n directory: `${path.join(casesRoot(), created.id)}/`,\n }, null, 2),\n }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case open', err)\n }\n },\n )\n\n server.registerTool(\n 'case_list',\n {\n description: 'List local Chain Insights investigation cases. Use before resuming when the user does not provide a case ID.',\n inputSchema: {\n status: z.enum(['open', 'active', 'suspended', 'closed']).optional().describe('Optional status filter'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ status }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const cases = await CaseStore.list()\n const filtered = status ? cases.filter((entry) => entry.status === status) : cases\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ cases: filtered }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case list', err)\n }\n },\n )\n\n server.registerTool(\n 'case_resume',\n {\n description: 'Load local Chain Insights case context: metadata, evidence count, dossier summaries, and latest session notes.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { CaseStore } = await import('../cases/index.js')\n const context = await CaseStore.loadContext(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(context, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case resume', err)\n }\n },\n )\n\n server.registerTool(\n 'case_add_evidence',\n {\n description: 'Append a tool result or analyst note to a local case evidence manifest. Use after address_risk, trace_victim_funds, trace_suspect_funds, trace_deposit_sources, graph_query, or manual findings that should be preserved.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n source: z.string().min(1).describe('Source tool or evidence origin'),\n content: z.string().min(1).describe('Evidence markdown/text to store'),\n query_params: z.string().optional().describe('Original query parameters, for example \"network=bittensor address=...\"'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, source, content, query_params }) => {\n try {\n const { EvidenceStore } = await import('../cases/index.js')\n const saved = await EvidenceStore.append(case_id, {\n source,\n content,\n queryParams: query_params ?? '',\n })\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(saved, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Evidence append', err)\n }\n },\n )\n\n server.registerTool(\n 'case_verify_evidence',\n {\n description: 'Verify a local case evidence manifest and report tampered or missing evidence files.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { EvidenceStore } = await import('../cases/index.js')\n const result = await EvidenceStore.verifyManifest(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Evidence verify', err)\n }\n },\n )\n\n server.registerTool(\n 'case_export',\n {\n description: 'Export a Chain Insights case to an Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT-friendly local bundle.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID to export'),\n target: z.enum(['obsidian-llmwiki']).optional().describe('Export target. Default obsidian-llmwiki.'),\n mode: z.enum(['private', 'partner', 'public']).optional().describe('Redaction mode. Default private.'),\n output_dir: z.string().optional().describe('Optional output directory. Defaults to published/<case-slug>.'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, target, mode, output_dir }) => {\n try {\n const { exportCase } = await import('../export/index.js')\n const result = await exportCase({\n caseId: case_id,\n target: target ?? 'obsidian-llmwiki',\n mode: mode ?? 'private',\n outputDir: output_dir,\n })\n return {\n content: [{\n type: 'text' as const,\n text: [\n `Case exported: ${result.outputDir}`,\n `Manifest: ${result.manifestPath}`,\n `Files: ${result.fileCount}`,\n `Open first: ${result.nextFile}`,\n ...result.warnings.map((warning) => `Warning: ${warning}`),\n ].join('\\n'),\n }],\n structuredContent: result,\n isError: false,\n }\n } catch (err) {\n return caseToolError('Case export', err)\n }\n },\n )\n\n server.registerTool(\n 'case_update_dossier',\n {\n description: 'Append a finding to an address/entity dossier inside a local Chain Insights case.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n address: z.string().min(1).describe('Full address or entity identifier'),\n finding: z.string().min(1).describe('Finding to append'),\n entity_type: z.enum(['eoa', 'contract', 'exchange', 'mixer', 'unknown']).optional().describe('Entity type'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, address, finding, entity_type }) => {\n try {\n const { DossierStore } = await import('../cases/index.js')\n await DossierStore.appendFinding(case_id, address, finding, entity_type ?? 'unknown')\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ case_id, address, updated: true }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Dossier update', err)\n }\n },\n )\n\n server.registerTool(\n 'case_start_session',\n {\n description: 'Start a local investigation session file for a Chain Insights case.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id }) => {\n try {\n const { SessionStore } = await import('../cases/index.js')\n const session = await SessionStore.start(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(session, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Session start', err)\n }\n },\n )\n\n server.registerTool(\n 'case_end_session',\n {\n description: 'End the latest local investigation session for a Chain Insights case with findings and next steps.',\n inputSchema: {\n case_id: z.string().min(1).describe('Chain Insights case ID'),\n findings: z.string().optional().describe('Key findings from this session'),\n next_steps: z.string().optional().describe('Next investigation steps'),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n },\n async ({ case_id, findings, next_steps }) => {\n try {\n const { SessionStore } = await import('../cases/index.js')\n await SessionStore.end(case_id, {\n findings: findings ?? '',\n nextSteps: next_steps ?? '',\n })\n await SessionStore.archiveOldSessions(case_id)\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ case_id, ended: true }, null, 2) }],\n isError: false,\n }\n } catch (err) {\n return caseToolError('Session end', err)\n }\n },\n )\n\n if (!remoteToolNames.has('address_risk')) {\n registerAppTool(\n server,\n 'address_risk',\n {\n title: 'Address Risk',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.address_risk,\n inputSchema: {\n address: z.string().min(1).describe('Full blockchain address to screen'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n compare_address: z.string().optional().describe('Optional second full address for comparison'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ address, network, compare_address }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { addressRisk } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await addressRisk(remoteClient, {\n address,\n network,\n compareAddress: compare_address,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `address-risk-${network}-${address}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Address risk failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('trace_victim_funds')) {\n registerAppTool(\n server,\n 'trace_victim_funds',\n {\n title: 'Trace Victim Funds',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_victim_funds,\n inputSchema: {\n victim_addresses: z.union([z.string().min(1), z.array(z.string().min(1))]).describe('Comma-separated full victim/source addresses, or an array. Min 1, max 5.'),\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n known_suspect_addresses: z.union([z.string(), z.array(z.string())]).optional().describe('Known suspect addresses for context only. This tool does not reverse-trace them. Max 5.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n incident_timestamp_ms: z.number().min(0).optional().describe('Optional incident timestamp in milliseconds.'),\n max_hops: z.number().int().min(1).max(5).optional(),\n per_address_limit: z.number().int().min(1).max(10).optional(),\n min_amount_sum: z.number().min(0).optional(),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ victim_addresses, known_suspect_addresses, network, case_id, incident_timestamp_ms, max_hops, per_address_limit, min_amount_sum }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { traceVictimFunds } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await traceVictimFunds(remoteClient, config, {\n victimAddresses: victim_addresses,\n knownSuspectAddresses: known_suspect_addresses,\n network,\n caseId: case_id,\n incidentTimestampMs: incident_timestamp_ms,\n maxHops: max_hops,\n perAddressLimit: per_address_limit,\n minAmountSum: min_amount_sum,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `trace-victim-funds-${network}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Trace victim funds failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('trace_suspect_funds')) {\n registerAppTool(\n server,\n 'trace_suspect_funds',\n {\n title: 'Trace Suspect Funds',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_suspect_funds,\n inputSchema: {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n suspect_addresses: z.union([z.string().min(1), z.array(z.string().min(1))]).describe('Comma-separated full suspect-controlled addresses, or an array. Min 1, max 5.'),\n incident_timestamp_ms: z.number().min(0).optional().describe('Optional incident timestamp in milliseconds. This tool works without it.'),\n max_hops: z.number().int().min(1).max(5).optional().describe('Maximum forward trace hops. Default 3.'),\n per_address_limit: z.number().int().min(1).max(10).optional(),\n min_amount_sum: z.number().min(0).optional(),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ suspect_addresses, incident_timestamp_ms, network, max_hops, per_address_limit, min_amount_sum, case_id }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { traceSuspectFunds } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await traceSuspectFunds(remoteClient, config, {\n suspectAddresses: suspect_addresses,\n network,\n maxHops: max_hops,\n perAddressLimit: per_address_limit,\n minAmountSum: min_amount_sum,\n incidentTimestampMs: incident_timestamp_ms,\n caseId: case_id,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `trace-suspect-funds-${network}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Trace suspect funds failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('trace_deposit_sources')) {\n registerAppTool(\n server,\n 'trace_deposit_sources',\n {\n title: 'Trace Deposit Sources',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_deposit_sources,\n inputSchema: {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n deposit_addresses: z.union([z.string().min(1), z.array(z.string().min(1))]).describe('Comma-separated full suspected deposit/cashout addresses, or an array. Min 1, max 5.'),\n max_hops: z.number().int().min(1).max(5).optional().describe('Maximum reverse traceback hops. Default 2.'),\n case_id: z.string().optional().describe('Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ deposit_addresses, network, max_hops, case_id }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { traceDepositSources } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await traceDepositSources(remoteClient, config, {\n depositAddresses: deposit_addresses,\n network,\n maxHops: max_hops,\n caseId: case_id,\n })\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `trace-deposit-sources-${network}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Trace deposit sources failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n if (!remoteToolNames.has('stake_insights')) {\n registerAppTool(\n server,\n 'stake_insights',\n {\n title: 'Stake Insights',\n description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.stake_insights,\n inputSchema: {\n network: z.string().min(1).describe(NETWORK_DESCRIPTION),\n address: z.string().optional().describe('Full Bittensor address to inspect as either coldkey or hotkey. Provide exactly one of address, coldkey, or hotkey.'),\n coldkey: z.string().optional().describe('Full Bittensor coldkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n hotkey: z.string().optional().describe('Full Bittensor hotkey address to inspect. Provide exactly one of address, coldkey, or hotkey.'),\n netuid: z.number().int().min(0).optional().describe('Optional subnet netuid filter.'),\n start_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive lower activity timestamp bound in milliseconds.'),\n end_timestamp_ms: z.number().min(0).optional().describe('Optional inclusive upper activity timestamp bound in milliseconds.'),\n start_block: z.number().int().min(0).optional().describe('Optional start block. Current stake graph parity may require timestamp windows instead.'),\n end_block: z.number().int().min(0).optional().describe('Optional end block. Current stake graph parity may require timestamp windows instead.'),\n depth: z.number().int().min(1).max(3).optional().describe('Optional expansion depth limit. First release returns direct STAKES_IN relationships; default 1, max 3.'),\n include_attachments: z.boolean().optional().describe('Include graph app report metadata'),\n },\n _meta: {\n ui: {\n resourceUri: GRAPH_RESOURCE_URI,\n },\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ network, address, coldkey, hotkey, netuid, start_timestamp_ms, end_timestamp_ms, start_block, end_block, depth }) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const { stakeInsights } = await import('../investigation/public-tools.js')\n const { writeGraphReport } = await import('./graph-reports.js')\n const { ensureArtifactServer } = await import('./artifact-server.js')\n const result = await stakeInsights(remoteClient, {\n network,\n address,\n coldkey,\n hotkey,\n netuid,\n startTimestampMs: start_timestamp_ms,\n endTimestampMs: end_timestamp_ms,\n startBlock: start_block,\n endBlock: end_block,\n depth,\n })\n const subject = address ?? coldkey ?? hotkey ?? 'subject'\n const report = await writeGraphReport(result.graphData as never, {\n serverPort: config.serverPort,\n slug: `stake-insights-${network}-${subject}`,\n })\n await ensureArtifactServer(config.serverPort)\n return {\n content: [{ type: 'text' as const, text: result.summaryText }],\n structuredContent: result.structuredContent,\n _meta: {\n chainInsights: {\n graph: {\n schema: report.schema,\n url: report.url,\n },\n },\n },\n isError: false,\n }\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return { content: [{ type: 'text' as const, text: err.message }], isError: true }\n }\n return {\n content: [{ type: 'text' as const, text: `Stake insights failed: ${(err as Error).message}` }],\n isError: true,\n }\n }\n },\n )\n }\n\n server.registerTool(\n 'help',\n {\n description: 'Show Chain Insights overview, available tools, and investigation workflow.',\n inputSchema: z.object({}).passthrough(),\n },\n async () => ({\n content: [\n {\n type: 'text' as const,\n text: [\n 'Chain Insights AML investigation workspace for AI agents.',\n '',\n CHAIN_INSIGHTS_WORKFLOW,\n '',\n 'Investigation tools:',\n '- network_capabilities: inspect supported networks, data layers, tool availability, retention windows, and freshness.',\n '- address_risk: screen a full address for AML risk, behavior, neighborhood, exchange exposure, and optional compare_address connection checks.',\n '- stake_insights: explain Bittensor staking around one address, coldkey, or hotkey with net stake, movement amounts, counterparties, backend, and query evidence.',\n '- trace_victim_funds: trace up to five victim/source addresses forward to exchange deposit candidates.',\n '- trace_deposit_sources: trace backward from suspected deposit/cashout addresses to upstream funders and shared-source convergence.',\n '- trace_suspect_funds: trace up to five suspected scammer, mule, operator, or laundering-ring addresses forward to cashout topology.',\n '- graph_query: run read-only GQL/Cypher through the universal graph endpoint. Use USE live_topology, USE archive_topology, or USE facts.',\n '- graph_query_batch: run related read-only graph-language queries through one paid graph call.',\n '',\n 'Case workflow tools:',\n '- case_open: create a local case before preserving evidence.',\n '- case_list: list local cases.',\n '- case_resume: load case context, evidence count, dossiers, and latest session.',\n '- case_add_evidence: append a report or note to the case evidence manifest.',\n '- case_verify_evidence: verify saved evidence integrity.',\n '- case_export: export a case for Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT.',\n '- case_update_dossier: add a finding to an address/entity dossier.',\n '- case_start_session and case_end_session: record session notes.',\n '',\n 'Wallet tools:',\n '- balance: show the local payment wallet address and Base USDC balance.',\n '- help: show this overview.',\n '',\n GRAPH_REPORT_HINTS,\n '',\n GRAPH_SCHEMA_HINTS,\n ].join('\\n'),\n },\n ],\n isError: false,\n }),\n )\n\n // Register each remote tool locally — passthrough proxy pattern\n for (const tool of tools ?? []) {\n if (HIDDEN_REMOTE_TOOL_NAMES.has(tool.name)) continue\n if (LOCAL_TOOL_NAMES.has(tool.name)) continue\n const inputSchema = knownPublicToolInputSchema(tool.name) ?? z.object({}).passthrough()\n const handler = async (args: unknown) => {\n try {\n if (!remoteConnected) {\n return {\n content: [{\n type: 'text' as const,\n text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`,\n }],\n isError: true,\n }\n }\n const normalizedArgs = normalizeRemoteToolArguments(tool.name, args)\n const validationError = validateKnownPublicToolArguments(tool.name, normalizedArgs)\n if (validationError) {\n return {\n content: [{ type: 'text' as const, text: validationError }],\n isError: true,\n }\n }\n const request = {\n name: tool.name,\n arguments: normalizedArgs,\n }\n const requestOptions = remoteToolRequestOptions(tool.name)\n const result = requestOptions\n ? await remoteClient.callTool(request, undefined, requestOptions)\n : await remoteClient.callTool(request)\n return await normalizeRemoteToolResult(result as RemoteToolResult, config, tool.name)\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n return {\n content: [{ type: 'text' as const, text: err.message }],\n isError: true,\n }\n }\n const msg = (err as Error).message ?? String(err)\n const isTransport402 = /\\b402\\b/.test(msg) || msg.toLowerCase().includes('payment')\n if (isTransport402) {\n return {\n content: [{\n type: 'text' as const,\n text: `Payment required for ${tool.name}. This tool costs USDC on Base via x402 micropayments. ` +\n 'Next steps: run `chain-insights wallet ready` to check funding and finish one-time payment setup, ' +\n 'run `chain-insights wallet topup` if it says the wallet needs USDC, ' +\n 'or `chain-insights access-key set <key>` if you have been given test access.',\n }],\n isError: true,\n }\n }\n return {\n content: [{ type: 'text' as const, text: `MCP call failed: ${msg}` }],\n isError: true,\n }\n }\n }\n const toolConfig = {\n title: tool.title,\n description: claudeFacingToolDescription(tool),\n inputSchema,\n }\n\n if (hasGraphApp(tool)) {\n registerAppTool(\n server,\n tool.name,\n {\n ...toolConfig,\n _meta: graphToolMeta(tool),\n },\n handler,\n )\n } else {\n server.registerTool(tool.name, toolConfig, handler)\n }\n }\n\n // Connect to stdio transport — after this line, stdout belongs to MCP\n const transport = new StdioServerTransport()\n await server.connect(transport)\n await logger.info('proxy.ready', {\n tools: [\n ...LOCAL_TOOL_NAMES,\n ...(tools ?? []).map((tool) => tool.name).filter((name) => !HIDDEN_REMOTE_TOOL_NAMES.has(name) && !LOCAL_TOOL_NAMES.has(name)),\n ].length,\n })\n\n // Signal handling — clean shutdown\n const shutdown = async () => {\n await logger.info('proxy.shutdown')\n transport.close()\n process.exit(0)\n }\n process.on('SIGINT', () => { void shutdown() })\n process.on('SIGTERM', () => { void shutdown() })\n}\n\n// Entry point — only execute when run as the main module (not when imported by tests)\n// Using process.argv check to detect direct execution vs import\nif (process.argv[1] && import.meta.url.includes(process.argv[1].replace(/\\\\/g, '/'))) {\n createProxy().catch((err) => {\n process.stderr.write(`Chain Insights MCP proxy startup failed: ${(err as Error).message}\\n`)\n process.exit(1)\n })\n}\n"],"mappings":"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"}