refactor: move the MCP server into packages/builder
Pure file moves plus import repointing at the shared package. Removes duplicated endpoint constants and formatting helpers that were copied across three files. Verified: 23 tools with identical schemas.
This commit is contained in:
1666
package-lock.json
generated
1666
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
packages/builder/package.json
Normal file
23
packages/builder/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@apexfusion/vector-mcp-builder",
|
||||
"version": "0.1.0",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
"description": "MCP server for Vector - AI agent interface for the Apex Fusion eUTXO L2",
|
||||
"bin": { "vector-mcp-builder": "./build/index.js" },
|
||||
"files": ["build"],
|
||||
"scripts": {
|
||||
"build": "tsup && chmod +x build/index.js",
|
||||
"start": "node build/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apexfusion/vector-mcp-shared": "*",
|
||||
"@aws-sdk/client-s3": "^3.1027.0",
|
||||
"@lucid-evolution/lucid": "^0.4.29",
|
||||
"@modelcontextprotocol/sdk": "^1.4.1",
|
||||
"@noble/hashes": "^1.7.1",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Check for .env file
|
||||
const envPath = resolve(__dirname, '../.env');
|
||||
const envPath = resolve(__dirname, '../../../.env');
|
||||
console.error('Looking for .env file at:', envPath);
|
||||
console.error('.env file exists:', existsSync(envPath));
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,4 +11,4 @@ export type {
|
||||
VectorTransactionHistoryResult,
|
||||
VectorDeployContractResult,
|
||||
VectorInteractContractResult,
|
||||
} from './types.js';
|
||||
} from '@apexfusion/vector-mcp-shared/types';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
||||
import { resolve, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import type { SpendLimits, SpendStatus, AuditEntry } from './types.js';
|
||||
import type { SpendLimits, SpendStatus, AuditEntry } from '@apexfusion/vector-mcp-shared/types';
|
||||
|
||||
const VECTOR_SPEND_LIMIT_PER_TX = parseInt(process.env.VECTOR_SPEND_LIMIT_PER_TX || '100000000'); // 100 AP3X
|
||||
const VECTOR_SPEND_LIMIT_DAILY = parseInt(process.env.VECTOR_SPEND_LIMIT_DAILY || '500000000'); // 500 AP3X
|
||||
@@ -18,16 +18,13 @@ async function ensureSlotConfig(provider: OgmiosProvider): Promise<number> {
|
||||
}
|
||||
import { blake2b } from '@noble/hashes/blake2b';
|
||||
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { OgmiosProvider } from './ogmios-provider.js';
|
||||
import { OgmiosProvider } from '@apexfusion/vector-mcp-shared/provider';
|
||||
import {
|
||||
VECTOR_OGMIOS_URL, VECTOR_SUBMIT_URL, VECTOR_KOIOS_URL, VECTOR_EXPLORER_URL, explorerTxLink,
|
||||
} from '@apexfusion/vector-mcp-shared/config';
|
||||
import { safetyLayer } from './safety.js';
|
||||
import { rateLimiter } from './rate-limiter.js';
|
||||
|
||||
// Env config
|
||||
const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org';
|
||||
const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx';
|
||||
const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://v2.koios.vector.testnet.apexfusion.org/';
|
||||
const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org';
|
||||
|
||||
// Agent Registry policy ID (shared across all modules)
|
||||
const AGENT_REGISTRY_POLICY = process.env.AGENT_REGISTRY_POLICY || 'be1a0a2912da180757ed3cd61b56bb8eab0188c19dc3c0e3912d2c01';
|
||||
|
||||
@@ -84,10 +81,6 @@ function newProvider() {
|
||||
return new OgmiosProvider({ ogmiosUrl: VECTOR_OGMIOS_URL, submitUrl: VECTOR_SUBMIT_URL, koiosUrl: VECTOR_KOIOS_URL });
|
||||
}
|
||||
|
||||
function explorerTxLink(txHash: string) {
|
||||
return `${VECTOR_EXPLORER_URL}/transaction/${txHash}`;
|
||||
}
|
||||
|
||||
function lovelaceToApex(lovelace: number | bigint): string {
|
||||
return (Number(BigInt(String(lovelace))) / 1_000_000).toFixed(6);
|
||||
}
|
||||
@@ -7,26 +7,24 @@ import * as dotenv from 'dotenv';
|
||||
import { resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { existsSync } from 'fs';
|
||||
import { OgmiosProvider } from './ogmios-provider.js';
|
||||
import { OgmiosProvider } from '@apexfusion/vector-mcp-shared/provider';
|
||||
import { lovelaceToAda, formatAssetName } from '@apexfusion/vector-mcp-shared/tx';
|
||||
import {
|
||||
VECTOR_OGMIOS_URL, VECTOR_SUBMIT_URL, VECTOR_KOIOS_URL, VECTOR_EXPLORER_URL, explorerTxLink,
|
||||
} from '@apexfusion/vector-mcp-shared/config';
|
||||
import { safetyLayer } from './safety.js';
|
||||
import { rateLimiter } from './rate-limiter.js';
|
||||
import { registerAgentNetworkTools } from './agent-network.js';
|
||||
import { registerSelfImprovementTools } from './self-improvement.js';
|
||||
import type {
|
||||
VectorToken,
|
||||
VectorWalletInfo,
|
||||
VectorAdaTransactionResult,
|
||||
VectorTokenTransactionResult,
|
||||
TxOutput,
|
||||
VectorBuildTransactionResult,
|
||||
VectorDryRunResult,
|
||||
VectorDeployContractResult,
|
||||
VectorToken, VectorWalletInfo, VectorAdaTransactionResult, VectorTokenTransactionResult,
|
||||
TxOutput, VectorBuildTransactionResult, VectorDryRunResult, VectorDeployContractResult,
|
||||
VectorInteractContractResult,
|
||||
} from './types.js';
|
||||
} from '@apexfusion/vector-mcp-shared/types';
|
||||
|
||||
// Direct .env loading
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const projectRoot = resolve(__filename, '../../../..');
|
||||
const projectRoot = resolve(__filename, '../../../../..');
|
||||
const envPath = resolve(projectRoot, '.env');
|
||||
|
||||
if (existsSync(envPath)) {
|
||||
@@ -36,39 +34,6 @@ if (existsSync(envPath)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration from environment variables
|
||||
const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org';
|
||||
const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx';
|
||||
const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://v2.koios.vector.testnet.apexfusion.org/';
|
||||
const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org';
|
||||
|
||||
// Helper function to format AP3X amounts
|
||||
function lovelaceToAda(lovelace: string | number | bigint): string {
|
||||
if (lovelace === undefined || lovelace === null) return '0.000000';
|
||||
try {
|
||||
return (Number(BigInt(String(lovelace))) / 1_000_000).toFixed(6);
|
||||
} catch {
|
||||
return '0.000000';
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to format asset name
|
||||
function formatAssetName(name: string): string {
|
||||
try {
|
||||
if (/^[0-9a-fA-F]+$/.test(name) && name.length > 0) {
|
||||
return Buffer.from(name, 'hex').toString('utf8');
|
||||
}
|
||||
return name;
|
||||
} catch {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Explorer link helper
|
||||
function explorerTxLink(txHash: string): string {
|
||||
return `${VECTOR_EXPLORER_URL}/transaction/${txHash}`;
|
||||
}
|
||||
|
||||
// Initialize Lucid instance with Ogmios provider
|
||||
async function initLucid(mnemonic: string, accountIndex: number = 0) {
|
||||
const provider = new OgmiosProvider({
|
||||
17
packages/builder/tsconfig.json
Normal file
17
packages/builder/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "build"]
|
||||
}
|
||||
@@ -7,5 +7,6 @@ export default defineConfig({
|
||||
outDir: "build",
|
||||
clean: true,
|
||||
splitting: false,
|
||||
noExternal: ["@apexfusion/vector-mcp-shared"],
|
||||
banner: { js: "#!/usr/bin/env node" },
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vector network endpoints. Defaults target testnet; override via environment.
|
||||
export const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org';
|
||||
export const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx';
|
||||
export const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://koios.vector.testnet.apexfusion.org/';
|
||||
export const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://v2.koios.vector.testnet.apexfusion.org/';
|
||||
export const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org';
|
||||
|
||||
export function explorerTxLink(txHash: string): string {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { deriveNftAssetName } from '../../src/vector/agent-network.ts';
|
||||
|
||||
// Parity vectors — verified against pycardano OutputReference.to_cbor() and
|
||||
// agent-sdk-py plutus_serialise_data(0, [tx_hash_bytes, idx]). All three
|
||||
// implementations produce identical bytes for the v2 contract on Conway.
|
||||
// See plan file for the verification run output.
|
||||
const VECTORS: Array<{ tx: string; idx: number; expected: string }> = [
|
||||
{
|
||||
tx: '00'.repeat(32),
|
||||
idx: 0,
|
||||
expected: 'a2e5e227858e84f1a8f9b0c1246e6cbc9336d707d43ba43d0e1cb7c51c45f4c9',
|
||||
},
|
||||
{
|
||||
tx: '2703182e4d1151a32b7bcfc2362c91278bcac66a49a840d217ae5cb49f8b3649',
|
||||
idx: 0,
|
||||
expected: '24ed834d88890ce35e81a6b9c4f988fad3d8a0284db6f3e641416f44f5e95d75',
|
||||
},
|
||||
{
|
||||
tx: 'ff'.repeat(32),
|
||||
idx: 23,
|
||||
expected: 'df229a221c5a84f48c06d5b28a98deb6ea678c369ab166400e88dd3d2bdc7b9f',
|
||||
},
|
||||
{
|
||||
tx: 'ab'.repeat(32),
|
||||
idx: 24,
|
||||
expected: '3ddd07517205dd8a745887c33a09da0e4a5d63dca1f151ceeedaeeda0551c52b',
|
||||
},
|
||||
{
|
||||
tx: '01'.repeat(32),
|
||||
idx: 256,
|
||||
expected: 'e626a305779e4c1e74b7719d302d0fbc1b722ab33bd52da4c23e6b8cd1bd04ec',
|
||||
},
|
||||
];
|
||||
|
||||
describe('deriveNftAssetName — Conway indefinite-CBOR parity', () => {
|
||||
for (const { tx, idx, expected } of VECTORS) {
|
||||
test(`tx=${tx.slice(0, 8)}… idx=${idx}`, () => {
|
||||
assert.equal(deriveNftAssetName(tx, idx), expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user