@agentxv2/gateway 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +53 -0
- package/db/migrations/001_init.sql +117 -0
- package/db/migrations/002_agents.sql +20 -0
- package/db/migrations/003_a2a_results.sql +23 -0
- package/deploy/.env.deploy.example +23 -0
- package/deploy/add_swap_build.py +45 -0
- package/deploy/build_and_deploy.py +110 -0
- package/deploy/build_deploy_a2a.py +190 -0
- package/deploy/build_no_lint.py +52 -0
- package/deploy/build_on_fe.py +86 -0
- package/deploy/build_on_gw.py +98 -0
- package/deploy/build_prod.py +54 -0
- package/deploy/check_bal.py +31 -0
- package/deploy/check_code.py +47 -0
- package/deploy/check_deploy.sh +20 -0
- package/deploy/check_docs.py +16 -0
- package/deploy/check_frontend.py +42 -0
- package/deploy/check_frontend2.py +35 -0
- package/deploy/check_pks.py +34 -0
- package/deploy/check_status.py +32 -0
- package/deploy/check_v2.py +8 -0
- package/deploy/clean_install.py +28 -0
- package/deploy/deploy_a2a.py +58 -0
- package/deploy/deploy_a2a.sh +33 -0
- package/deploy/deploy_a2a_bg.sh +40 -0
- package/deploy/deploy_a2a_v2.py +151 -0
- package/deploy/deploy_a2a_v2.sh +36 -0
- package/deploy/deploy_bin.py +64 -0
- package/deploy/deploy_config.py +34 -0
- package/deploy/deploy_final.py +42 -0
- package/deploy/deploy_frontend.py +108 -0
- package/deploy/deploy_mcp.py +108 -0
- package/deploy/deploy_now.py +49 -0
- package/deploy/deploy_push_all.py +128 -0
- package/deploy/deploy_script.py +64 -0
- package/deploy/deploy_sep_a2a.sh +18 -0
- package/deploy/dev_mode.py +51 -0
- package/deploy/diag.py +12 -0
- package/deploy/diff_test.py +22 -0
- package/deploy/final_check.py +33 -0
- package/deploy/final_deploy.py +50 -0
- package/deploy/final_fix.py +54 -0
- package/deploy/final_push.py +114 -0
- package/deploy/find_frontend.py +38 -0
- package/deploy/fix_a2a.py +43 -0
- package/deploy/fix_and_build.py +77 -0
- package/deploy/fix_and_verify.py +56 -0
- package/deploy/fix_build.py +51 -0
- package/deploy/forge_deploy.py +67 -0
- package/deploy/full_push.py +101 -0
- package/deploy/full_push2.py +106 -0
- package/deploy/go_prod.py +59 -0
- package/deploy/gw_deploy.py +133 -0
- package/deploy/gw_final.py +206 -0
- package/deploy/gw_restart.py +28 -0
- package/deploy/gw_status.py +18 -0
- package/deploy/inline_build.py +99 -0
- package/deploy/one_shot.py +84 -0
- package/deploy/ox_deploy.py +32 -0
- package/deploy/pg_setup.py +36 -0
- package/deploy/prod_deploy.py +126 -0
- package/deploy/prod_final.py +140 -0
- package/deploy/prod_go.py +61 -0
- package/deploy/prod_one_shot.py +139 -0
- package/deploy/prod_setup.sh +62 -0
- package/deploy/prod_v2.py +91 -0
- package/deploy/prod_v3.py +103 -0
- package/deploy/push_docs.py +93 -0
- package/deploy/push_mcp.py +66 -0
- package/deploy/push_mcp_doc.py +28 -0
- package/deploy/push_v063.py +80 -0
- package/deploy/push_v2.py +71 -0
- package/deploy/qcheck.py +13 -0
- package/deploy/qcheck2.py +18 -0
- package/deploy/quick_check.py +8 -0
- package/deploy/rebuild.py +47 -0
- package/deploy/rebuild_frontend.py +44 -0
- package/deploy/restart.py +28 -0
- package/deploy/restore_frontend.py +42 -0
- package/deploy/restore_frontend2.py +41 -0
- package/deploy/restore_gateway.py +34 -0
- package/deploy/restore_quick.py +33 -0
- package/deploy/run_bash.py +19 -0
- package/deploy/run_sep.py +20 -0
- package/deploy/sdk_upgrade.py +50 -0
- package/deploy/server_prepare.py +41 -0
- package/deploy/server_setup.py +41 -0
- package/deploy/ssh_check.py +14 -0
- package/deploy/ssh_push.py +24 -0
- package/deploy/start_deploy.py +35 -0
- package/deploy/start_frontend.py +12 -0
- package/deploy/start_v2.py +29 -0
- package/deploy/stat.py +18 -0
- package/deploy/tail_log.py +11 -0
- package/deploy/update_env.py +32 -0
- package/deploy/upload_and_start.py +107 -0
- package/deploy/verify_a2a.py +13 -0
- package/deploy/verify_mcp.py +37 -0
- package/deploy/verify_sdk.py +21 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/crypto.d.ts +2 -0
- package/dist/lib/crypto.js +43 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/db.d.ts +3 -0
- package/dist/lib/db.js +26 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/ethers-utils.d.ts +60 -0
- package/dist/lib/ethers-utils.js +186 -0
- package/dist/lib/ethers-utils.js.map +1 -0
- package/dist/middleware/adminAuth.d.ts +2 -0
- package/dist/middleware/adminAuth.js +31 -0
- package/dist/middleware/adminAuth.js.map +1 -0
- package/dist/middleware/auth.d.ts +22 -0
- package/dist/middleware/auth.js +192 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +36 -0
- package/dist/middleware/error-handler.js +100 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +5 -0
- package/dist/middleware/rate-limiter.js +107 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/routes/a2a.d.ts +2 -0
- package/dist/routes/a2a.js +84 -0
- package/dist/routes/a2a.js.map +1 -0
- package/dist/routes/admin.d.ts +2 -0
- package/dist/routes/admin.js +180 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/agents.d.ts +2 -0
- package/dist/routes/agents.js +43 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/chat.d.ts +2 -0
- package/dist/routes/chat.js +183 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/history.d.ts +2 -0
- package/dist/routes/history.js +92 -0
- package/dist/routes/history.js.map +1 -0
- package/dist/routes/mcp.d.ts +13 -0
- package/dist/routes/mcp.js +513 -0
- package/dist/routes/mcp.js.map +1 -0
- package/dist/routes/tenant.d.ts +2 -0
- package/dist/routes/tenant.js +154 -0
- package/dist/routes/tenant.js.map +1 -0
- package/dist/services/a2a-worker.d.ts +7 -0
- package/dist/services/a2a-worker.js +406 -0
- package/dist/services/a2a-worker.js.map +1 -0
- package/dist/services/agent-indexer.d.ts +4 -0
- package/dist/services/agent-indexer.js +124 -0
- package/dist/services/agent-indexer.js.map +1 -0
- package/e2e_wallet.js +175 -0
- package/ecosystem.config.js +17 -0
- package/package.json +33 -0
- package/src/config.ts +47 -0
- package/src/index.ts +143 -0
- package/src/lib/crypto.ts +44 -0
- package/src/lib/db.ts +25 -0
- package/src/lib/ethers-utils.ts +229 -0
- package/src/middleware/adminAuth.ts +34 -0
- package/src/middleware/auth.ts +244 -0
- package/src/middleware/error-handler.ts +109 -0
- package/src/middleware/rate-limiter.ts +115 -0
- package/src/routes/a2a.ts +97 -0
- package/src/routes/admin.ts +219 -0
- package/src/routes/agents.ts +52 -0
- package/src/routes/chat.ts +219 -0
- package/src/routes/history.ts +114 -0
- package/src/routes/mcp.ts +567 -0
- package/src/routes/tenant.ts +196 -0
- package/src/services/a2a-worker.ts +486 -0
- package/src/services/agent-indexer.ts +127 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// AgentX Gateway — MCP Server (Model Context Protocol)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Standard MCP JSON-RPC 2.0 endpoint. Supports dual-chain (Sepolia + OxaChain L1).
|
|
5
|
+
// POST /mcp
|
|
6
|
+
// tools/list → all 29 AgentX platform tools
|
|
7
|
+
// tools/call → params.name + params.arguments.{chain:"sepolia"|"oxachain"}
|
|
8
|
+
// initialize → handshake
|
|
9
|
+
//
|
|
10
|
+
// Claude Desktop config:
|
|
11
|
+
// { "mcpServers": { "agentx": { "url": "http://43.156.225.164:3090/mcp" } } }
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
import { Router, Request, Response } from 'express'
|
|
15
|
+
import { ethers } from 'ethers'
|
|
16
|
+
import { config } from '../config'
|
|
17
|
+
|
|
18
|
+
const router = Router()
|
|
19
|
+
|
|
20
|
+
// ── Chain Config ───────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
type ChainKey = 'sepolia' | 'oxachain'
|
|
23
|
+
|
|
24
|
+
interface ChainInfo {
|
|
25
|
+
rpcUrl: string
|
|
26
|
+
chainId: number
|
|
27
|
+
identityRegistry: string
|
|
28
|
+
subscriptionManager: string
|
|
29
|
+
a2aProtocol: string
|
|
30
|
+
reputationRegistry: string
|
|
31
|
+
configurationRegistry: string
|
|
32
|
+
multiEndpoint: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const CHAINS: Record<ChainKey, ChainInfo> = {
|
|
36
|
+
sepolia: {
|
|
37
|
+
rpcUrl: config.rpcUrl,
|
|
38
|
+
chainId: config.chainId,
|
|
39
|
+
identityRegistry: config.identityRegistry,
|
|
40
|
+
subscriptionManager: config.subscriptionManager,
|
|
41
|
+
a2aProtocol: config.a2aProtocol,
|
|
42
|
+
reputationRegistry: config.reputationRegistry,
|
|
43
|
+
configurationRegistry: config.configurationRegistry,
|
|
44
|
+
multiEndpoint: config.multiEndpoint,
|
|
45
|
+
},
|
|
46
|
+
oxachain: {
|
|
47
|
+
rpcUrl: config.rpcUrlOxaChain,
|
|
48
|
+
chainId: config.chainIdOxaChain,
|
|
49
|
+
identityRegistry: config.identityRegistryOxaChain,
|
|
50
|
+
subscriptionManager: config.subscriptionManagerOxaChain,
|
|
51
|
+
a2aProtocol: config.a2aProtocolOxaChain,
|
|
52
|
+
reputationRegistry: config.reputationRegistryOxaChain,
|
|
53
|
+
configurationRegistry: config.configurationRegistryOxaChain,
|
|
54
|
+
multiEndpoint: config.multiEndpointOxaChain,
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveChain(args: Record<string, unknown>): ChainInfo {
|
|
59
|
+
const key = (args.chain as string)?.toLowerCase() === 'oxachain' ? 'oxachain' : 'sepolia'
|
|
60
|
+
return CHAINS[key]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── Cached Providers ───────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
const providers: Partial<Record<ChainKey, ethers.JsonRpcProvider>> = {}
|
|
66
|
+
function getProvider(chain: ChainKey): ethers.JsonRpcProvider {
|
|
67
|
+
if (!providers[chain]) providers[chain] = new ethers.JsonRpcProvider(CHAINS[chain].rpcUrl)
|
|
68
|
+
return providers[chain]!
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getContract(chain: ChainKey, address: string, abi: string[]): ethers.Contract {
|
|
72
|
+
return new ethers.Contract(address, abi, getProvider(chain))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── MCP Tool Definitions ───────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
interface MCPTool {
|
|
78
|
+
name: string
|
|
79
|
+
description: string
|
|
80
|
+
inputSchema: { type: 'object'; properties: Record<string, unknown>; required?: string[] }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function commonArgs(): Record<string, unknown> {
|
|
84
|
+
return {
|
|
85
|
+
chain: { type: 'string', description: 'Chain: "sepolia" (default) or "oxachain" for OxaChain L1 mainnet', enum: ['sepolia', 'oxachain'] },
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const MCP_TOOLS: MCPTool[] = [
|
|
90
|
+
// ── IdentityRegistry ────────────────────────────────────────────────────
|
|
91
|
+
{
|
|
92
|
+
name: 'agentx_identity_list',
|
|
93
|
+
description: 'List all Agent IDs owned by a wallet address on Sepolia or OxaChain L1.',
|
|
94
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), ownerAddress: { type: 'string', description: 'Ethereum wallet address (0x...)' } }, required: ['ownerAddress'] },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'agentx_identity_get',
|
|
98
|
+
description: 'Get agent details — tokenURI, metadata, existence.',
|
|
99
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent numeric ID' } }, required: ['agentId'] },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'agentx_identity_exists',
|
|
103
|
+
description: 'Check whether an agent ID exists on-chain.',
|
|
104
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'agentx_identity_total_count',
|
|
108
|
+
description: 'Total number of agents registered.',
|
|
109
|
+
inputSchema: { type: 'object', properties: { ...commonArgs() } },
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'agentx_identity_register',
|
|
113
|
+
description: 'Register a new Agent on-chain. WRITE operation — returns tx payload.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
...commonArgs(),
|
|
118
|
+
tokenURI: { type: 'string', description: 'IPFS URI (ipfs://...)' },
|
|
119
|
+
encryptedPayloadCid: { type: 'string', description: 'IPFS CID of encrypted payload' },
|
|
120
|
+
eciesEncryptedKey: { type: 'string', description: 'Hex ECIES-encrypted AES key' },
|
|
121
|
+
},
|
|
122
|
+
required: ['tokenURI', 'encryptedPayloadCid', 'eciesEncryptedKey'],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// ── SubscriptionManager ─────────────────────────────────────────────────
|
|
127
|
+
{
|
|
128
|
+
name: 'agentx_subscription_plans',
|
|
129
|
+
description: 'Get plan details: price, period, pay token, trial days.',
|
|
130
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), planId: { type: 'integer', description: 'Plan ID' } }, required: ['planId'] },
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'agentx_subscription_check',
|
|
134
|
+
description: 'Check if a wallet has an active subscription for an agent.',
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: { ...commonArgs(), subscriberAddress: { type: 'string', description: 'Wallet address' }, agentId: { type: 'integer', description: 'Agent ID' } },
|
|
138
|
+
required: ['subscriberAddress', 'agentId'],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'agentx_subscription_detail',
|
|
143
|
+
description: 'Full subscription detail including trial info, escrow status.',
|
|
144
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), subscriptionId: { type: 'integer', description: 'Subscription ID' } }, required: ['subscriptionId'] },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'agentx_subscription_my_list',
|
|
148
|
+
description: 'List all subscription IDs for a wallet.',
|
|
149
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), userAddress: { type: 'string', description: 'Wallet address' } }, required: ['userAddress'] },
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'agentx_subscription_subscribe',
|
|
153
|
+
description: 'Subscribe to a plan. WRITE operation.',
|
|
154
|
+
inputSchema: {
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: { ...commonArgs(), planId: { type: 'integer', description: 'Plan ID' }, valueWei: { type: 'string', description: 'ETH in wei' } },
|
|
157
|
+
required: ['planId'],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: 'agentx_subscription_cancel',
|
|
162
|
+
description: 'Cancel a subscription. WRITE operation.',
|
|
163
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), subscriptionId: { type: 'integer', description: 'Subscription ID' } }, required: ['subscriptionId'] },
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: 'agentx_subscription_release',
|
|
167
|
+
description: 'Release escrowed funds. WRITE operation.',
|
|
168
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), subscriptionId: { type: 'integer', description: 'Subscription ID' } }, required: ['subscriptionId'] },
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'agentx_subscription_fee',
|
|
172
|
+
description: 'Get current platform fee in bps.',
|
|
173
|
+
inputSchema: { type: 'object', properties: { ...commonArgs() } },
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// ── A2AProtocol ─────────────────────────────────────────────────────────
|
|
177
|
+
{
|
|
178
|
+
name: 'agentx_a2a_create_task',
|
|
179
|
+
description: 'Create an on-chain A2A task. WRITE operation.',
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: { ...commonArgs(), targetAgentId: { type: 'integer', description: 'Target agent ID' }, taskType: { type: 'string', description: 'e.g. audit, analyze' }, inputData: { type: 'string', description: 'JSON input' } },
|
|
183
|
+
required: ['targetAgentId', 'taskType', 'inputData'],
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'agentx_a2a_get_task',
|
|
188
|
+
description: 'Get A2A task details.',
|
|
189
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), taskId: { type: 'integer', description: 'Task ID' } }, required: ['taskId'] },
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'agentx_a2a_complete_task',
|
|
193
|
+
description: 'Complete a task on-chain. WRITE operation.',
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: 'object',
|
|
196
|
+
properties: { ...commonArgs(), taskId: { type: 'integer', description: 'Task ID' }, outputData: { type: 'string', description: 'JSON output' } },
|
|
197
|
+
required: ['taskId', 'outputData'],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: 'agentx_a2a_my_tasks',
|
|
202
|
+
description: 'Get all task IDs for a wallet.',
|
|
203
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), userAddress: { type: 'string', description: 'Wallet address' } }, required: ['userAddress'] },
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: 'agentx_a2a_agent_card',
|
|
207
|
+
description: 'Get agent A2A card: name, capabilities, supported tasks.',
|
|
208
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
// ── ReputationRegistry ──────────────────────────────────────────────────
|
|
212
|
+
{
|
|
213
|
+
name: 'agentx_reputation_rate',
|
|
214
|
+
description: 'Rate an agent (1-5). WRITE operation.',
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' }, rating: { type: 'integer', description: '1-5' }, comment: { type: 'string', description: 'Review' } },
|
|
218
|
+
required: ['agentId', 'rating'],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: 'agentx_reputation_get',
|
|
223
|
+
description: 'Average rating and review count.',
|
|
224
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'agentx_reputation_reviews',
|
|
228
|
+
description: 'All reviews with reviewer, rating, comment, timestamp.',
|
|
229
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// ── ConfigurationRegistry ───────────────────────────────────────────────
|
|
233
|
+
{
|
|
234
|
+
name: 'agentx_config_get',
|
|
235
|
+
description: 'Read a config value by key.',
|
|
236
|
+
inputSchema: {
|
|
237
|
+
type: 'object',
|
|
238
|
+
properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' }, configKey: { type: 'string', description: 'Config key' } },
|
|
239
|
+
required: ['agentId', 'configKey'],
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'agentx_config_list',
|
|
244
|
+
description: 'List all configurations for an agent.',
|
|
245
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'agentx_config_set',
|
|
249
|
+
description: 'Set config value on-chain. WRITE operation.',
|
|
250
|
+
inputSchema: {
|
|
251
|
+
type: 'object',
|
|
252
|
+
properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' }, key: { type: 'string' }, value: { type: 'string' }, dataType: { type: 'string', enum: ['string', 'number', 'boolean', 'json'] } },
|
|
253
|
+
required: ['agentId', 'key', 'value'],
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// ── MultiEndpointRegistry ───────────────────────────────────────────────
|
|
258
|
+
{
|
|
259
|
+
name: 'agentx_endpoint_list',
|
|
260
|
+
description: 'All registered endpoints.',
|
|
261
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: 'agentx_endpoint_active',
|
|
265
|
+
description: 'Only active endpoints.',
|
|
266
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: 'agentx_endpoint_best_mcp',
|
|
270
|
+
description: 'Best available MCP endpoint URL.',
|
|
271
|
+
inputSchema: { type: 'object', properties: { ...commonArgs(), agentId: { type: 'integer', description: 'Agent ID' } }, required: ['agentId'] },
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// ── Gateway ─────────────────────────────────────────────────────────────
|
|
275
|
+
{
|
|
276
|
+
name: 'agentx_gateway_tenant',
|
|
277
|
+
description: 'Get tenant profile, plan, quota.',
|
|
278
|
+
inputSchema: { type: 'object', properties: { accessToken: { type: 'string', description: 'Gateway JWT token' } }, required: ['accessToken'] },
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'agentx_gateway_health',
|
|
282
|
+
description: 'Gateway health + chain contract addresses (both chains).',
|
|
283
|
+
inputSchema: { type: 'object', properties: {} },
|
|
284
|
+
},
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
// ── ABIs ────────────────────────────────────────────────────────────────────
|
|
288
|
+
|
|
289
|
+
const ID_ABI = [
|
|
290
|
+
'function getAgentsByOwner(address owner) view returns (uint256[])',
|
|
291
|
+
'function getCurrentAgentId() view returns (uint256)',
|
|
292
|
+
'function agentExists(uint256 agentId) view returns (bool)',
|
|
293
|
+
'function tokenURI(uint256 tokenId) view returns (string)',
|
|
294
|
+
]
|
|
295
|
+
const SUB_ABI = [
|
|
296
|
+
// No named params — avoids ethers.js v6 struct decoding issues with mixed static/dynamic fields
|
|
297
|
+
'function getPlan(uint256) view returns (uint256,uint256,address,uint256,string,bool,address,uint256)',
|
|
298
|
+
'function hasActiveSubscription(address,uint256) view returns (bool)',
|
|
299
|
+
'function getSubscription(address,uint256) view returns (uint256,address,uint256,uint8,uint256,uint256,string)',
|
|
300
|
+
'function getSubscriptionDetail(uint256) view returns (uint256,address,uint256,uint8,uint256,uint256,string,address,uint256,bool,uint256,bool)',
|
|
301
|
+
'function getUserSubscriptions(address) view returns (uint256[])',
|
|
302
|
+
'function platformFeeBps() view returns (uint256)',
|
|
303
|
+
]
|
|
304
|
+
const A2A_ABI = [
|
|
305
|
+
'function getTask(uint256) view returns (uint256,uint256,string,string,string,uint256,address,uint256,uint256)',
|
|
306
|
+
'function getUserTasks(address) view returns (uint256[])',
|
|
307
|
+
'function getAgentCard(uint256) view returns (uint256,uint256,string,string,string,string[],string[],string,string,string,bool)',
|
|
308
|
+
]
|
|
309
|
+
const REP_ABI = [
|
|
310
|
+
'function getReputationSummary(uint256 agentId, address[] clientAddresses, bytes32 tag1, bytes32 tag2) view returns (uint64 count, uint8 averageScore)',
|
|
311
|
+
'function readFeedback(uint256 agentId, address clientAddress, uint64 index) view returns (uint8 score, bytes32 tag1, bytes32 tag2, bool isRevoked)',
|
|
312
|
+
'function getClients(uint256 agentId) view returns (address[])',
|
|
313
|
+
'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint64)',
|
|
314
|
+
]
|
|
315
|
+
const CFG_ABI = [
|
|
316
|
+
'function getConfig(uint256 agentId, string configKey) view returns (tuple(uint256 configId, uint256 agentId, string configKey, string configValue, string dataType, string description, bool isActive, uint256 createdAt, uint256 updatedAt, address createdBy))',
|
|
317
|
+
'function getAgentConfigs(uint256 agentId) view returns (tuple(uint256 configId, uint256 agentId, string configKey, string configValue, string dataType, string description, bool isActive, uint256 createdAt, uint256 updatedAt, address createdBy)[])',
|
|
318
|
+
'function getConfigKeys(uint256 agentId) view returns (string[])',
|
|
319
|
+
]
|
|
320
|
+
const EP_ABI = [
|
|
321
|
+
'function getAgentEndpoints(uint256) view returns (tuple(uint256,uint256,string,string,string,string,string,bool,uint256,uint256,address)[])',
|
|
322
|
+
'function getActiveAgentEndpoints(uint256) view returns (tuple(uint256,uint256,string,string,string,string,string,bool,uint256,uint256,address)[])',
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
326
|
+
|
|
327
|
+
function formatBigInts(arr: bigint[]): number[] { return arr.map(Number) }
|
|
328
|
+
function toObj(keys: string[], vals: any[]): Record<string, unknown> {
|
|
329
|
+
const obj: Record<string, unknown> = {}
|
|
330
|
+
for (let i = 0; i < keys.length; i++) {
|
|
331
|
+
const v = vals[i]
|
|
332
|
+
obj[keys[i]] = typeof v === 'bigint' ? (v > 2n ** 53n ? v.toString() : Number(v)) : v
|
|
333
|
+
}
|
|
334
|
+
return obj
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ── Tool Executor ───────────────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
async function executeToolCall(name: string, args: Record<string, unknown>): Promise<unknown> {
|
|
340
|
+
const chain = resolveChain(args) as ChainInfo
|
|
341
|
+
const ck: ChainKey = (args.chain as string)?.toLowerCase() === 'oxachain' ? 'oxachain' : 'sepolia'
|
|
342
|
+
const chainLabel = ck === 'oxachain' ? 'OxaChain L1' : 'Sepolia'
|
|
343
|
+
const chainId = ck === 'oxachain' ? config.chainIdOxaChain : config.chainId
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
switch (name) {
|
|
347
|
+
// ── Identity ──────────────────────────────────
|
|
348
|
+
case 'agentx_identity_list': {
|
|
349
|
+
const owner = args.ownerAddress as string
|
|
350
|
+
const ids = await getContract(ck, chain.identityRegistry, ID_ABI).getAgentsByOwner(owner)
|
|
351
|
+
return { agentIds: formatBigInts(ids), owner, chain: chainLabel, chainId }
|
|
352
|
+
}
|
|
353
|
+
case 'agentx_identity_get': {
|
|
354
|
+
const agentId = Number(args.agentId)
|
|
355
|
+
const c = getContract(ck, chain.identityRegistry, ID_ABI)
|
|
356
|
+
const [exists, tokenURI] = await Promise.all([
|
|
357
|
+
c.agentExists(agentId).catch(() => false),
|
|
358
|
+
c.tokenURI(agentId).catch(() => null),
|
|
359
|
+
])
|
|
360
|
+
return { agentId, exists, tokenURI, chain: chainLabel, chainId }
|
|
361
|
+
}
|
|
362
|
+
case 'agentx_identity_exists':
|
|
363
|
+
return { exists: await getContract(ck, chain.identityRegistry, ID_ABI).agentExists(Number(args.agentId)), chain: chainLabel, chainId }
|
|
364
|
+
case 'agentx_identity_total_count': {
|
|
365
|
+
const total = await getContract(ck, chain.identityRegistry, ID_ABI).getCurrentAgentId()
|
|
366
|
+
return { totalAgents: Number(total), chain: chainLabel, chainId }
|
|
367
|
+
}
|
|
368
|
+
case 'agentx_identity_register':
|
|
369
|
+
return { _writeOp: true, message: `WRITE. Use a wallet client to sign and submit to ${chainLabel}.`, contract: chain.identityRegistry, chain: chainLabel, chainId }
|
|
370
|
+
|
|
371
|
+
// ── Subscription ──────────────────────────────
|
|
372
|
+
case 'agentx_subscription_plans': {
|
|
373
|
+
// raw eth_call to avoid ethers.js v6 struct-decoding bug with bool+string mix
|
|
374
|
+
const planId = Number(args.planId)
|
|
375
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder()
|
|
376
|
+
const data = new ethers.Interface(SUB_ABI).encodeFunctionData('getPlan', [planId])
|
|
377
|
+
const raw = await getProvider(ck).call({ to: chain.subscriptionManager, data })
|
|
378
|
+
const decoded = abiCoder.decode(['uint256','uint256','address','uint256','string','bool','address','uint256'], raw)
|
|
379
|
+
return { planId: Number(decoded[0]), agentId: Number(decoded[1]), creator: decoded[2], price: Number(decoded[3]), period: decoded[4], active: decoded[5], payToken: decoded[6], trialDays: Number(decoded[7]), chain: chainLabel, chainId }
|
|
380
|
+
}
|
|
381
|
+
case 'agentx_subscription_check': {
|
|
382
|
+
// Accept both 'subscriberAddress' and 'subscriber' parameter names
|
|
383
|
+
const subscriber = (args.subscriberAddress || args.subscriber || args.subscriber_address) as string
|
|
384
|
+
const subscriberAddr = ethers.getAddress(subscriber)
|
|
385
|
+
const ok = await getContract(ck, chain.subscriptionManager, SUB_ABI).hasActiveSubscription(subscriberAddr, Number(args.agentId))
|
|
386
|
+
return { active: ok, subscriber: subscriberAddr, agentId: Number(args.agentId), chain: chainLabel, chainId }
|
|
387
|
+
}
|
|
388
|
+
case 'agentx_subscription_detail': {
|
|
389
|
+
const d = await getContract(ck, chain.subscriptionManager, SUB_ABI).getSubscriptionDetail(Number(args.subscriptionId))
|
|
390
|
+
return { ...toObj(['subscriptionId', 'subscriber', 'agentId', 'status', 'startedAt', 'expiresAt', 'period', 'payToken', 'amountPaid', 'trialActive', 'trialEndsAt', 'fundsReleased'], d), chain: chainLabel, chainId }
|
|
391
|
+
}
|
|
392
|
+
case 'agentx_subscription_my_list': {
|
|
393
|
+
const ids = await getContract(ck, chain.subscriptionManager, SUB_ABI).getUserSubscriptions(args.userAddress as string)
|
|
394
|
+
return { subscriptionIds: formatBigInts(ids), user: args.userAddress, chain: chainLabel, chainId }
|
|
395
|
+
}
|
|
396
|
+
case 'agentx_subscription_subscribe':
|
|
397
|
+
return { _writeOp: true, message: `WRITE. Subscribe via wallet client on ${chainLabel}.`, contract: chain.subscriptionManager, chain: chainLabel, chainId }
|
|
398
|
+
case 'agentx_subscription_cancel':
|
|
399
|
+
return { _writeOp: true, message: `WRITE. Cancel via wallet client on ${chainLabel}.`, contract: chain.subscriptionManager, chain: chainLabel, chainId }
|
|
400
|
+
case 'agentx_subscription_release':
|
|
401
|
+
return { _writeOp: true, message: `WRITE. Release via wallet client on ${chainLabel}.`, contract: chain.subscriptionManager, chain: chainLabel, chainId }
|
|
402
|
+
case 'agentx_subscription_fee': {
|
|
403
|
+
const fee = await getContract(ck, chain.subscriptionManager, SUB_ABI).platformFeeBps()
|
|
404
|
+
return { platformFeeBps: Number(fee), chain: chainLabel, chainId }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ── A2A ───────────────────────────────────────
|
|
408
|
+
case 'agentx_a2a_get_task': {
|
|
409
|
+
const t = await getContract(ck, chain.a2aProtocol, A2A_ABI).getTask(Number(args.taskId))
|
|
410
|
+
return { ...toObj(['taskId', 'agentId', 'taskType', 'inputData', 'outputData', 'status', 'clientAddress', 'createdAt', 'completedAt'], t), chain: chainLabel, chainId }
|
|
411
|
+
}
|
|
412
|
+
case 'agentx_a2a_my_tasks': {
|
|
413
|
+
const ids = await getContract(ck, chain.a2aProtocol, A2A_ABI).getUserTasks(args.userAddress as string)
|
|
414
|
+
return { taskIds: formatBigInts(ids), user: args.userAddress, chain: chainLabel, chainId }
|
|
415
|
+
}
|
|
416
|
+
case 'agentx_a2a_agent_card': {
|
|
417
|
+
const card = await getContract(ck, chain.a2aProtocol, A2A_ABI).getAgentCard(Number(args.agentId))
|
|
418
|
+
const [, aId, name, , , capabilities, supportedTasks, comm, auth, , isActive] = card
|
|
419
|
+
return { agentId: Number(aId), name, capabilities, supportedTasks, communicationProtocol: comm, authenticationMethod: auth, isActive, chain: chainLabel, chainId }
|
|
420
|
+
}
|
|
421
|
+
case 'agentx_a2a_create_task':
|
|
422
|
+
return { _writeOp: true, message: `WRITE. Create task via wallet client on ${chainLabel}.`, contract: chain.a2aProtocol, chain: chainLabel, chainId }
|
|
423
|
+
case 'agentx_a2a_complete_task':
|
|
424
|
+
return { _writeOp: true, message: `WRITE. Complete task via wallet client on ${chainLabel}.`, contract: chain.a2aProtocol, chain: chainLabel, chainId }
|
|
425
|
+
|
|
426
|
+
// ── Reputation ─────────────────────────────────
|
|
427
|
+
case 'agentx_reputation_get': {
|
|
428
|
+
const [count, avgScore] = await getContract(ck, chain.reputationRegistry, REP_ABI).getReputationSummary(Number(args.agentId), [], ethers.ZeroHash, ethers.ZeroHash)
|
|
429
|
+
return { agentId: Number(args.agentId), averageScore: Number(avgScore), reviewCount: Number(count), chain: chainLabel, chainId }
|
|
430
|
+
}
|
|
431
|
+
case 'agentx_reputation_reviews': {
|
|
432
|
+
const clients = await getContract(ck, chain.reputationRegistry, REP_ABI).getClients(Number(args.agentId))
|
|
433
|
+
const reviews: any[] = []
|
|
434
|
+
for (const client of clients.map(String)) {
|
|
435
|
+
const lastIdx = await getContract(ck, chain.reputationRegistry, REP_ABI).getLastIndex(Number(args.agentId), client).then(n => Number(n)).catch(() => 0)
|
|
436
|
+
for (let i = 1; i <= lastIdx; i++) {
|
|
437
|
+
try {
|
|
438
|
+
const fb = await getContract(ck, chain.reputationRegistry, REP_ABI).readFeedback(Number(args.agentId), client, i)
|
|
439
|
+
reviews.push({ reviewer: client, score: Number(fb[0]), tag1: fb[1], tag2: fb[2], isRevoked: fb[3] })
|
|
440
|
+
} catch { /* skip */ }
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return { agentId: Number(args.agentId), reviews, chain: chainLabel, chainId }
|
|
444
|
+
}
|
|
445
|
+
case 'agentx_reputation_rate':
|
|
446
|
+
return { _writeOp: true, message: `WRITE. Rate via wallet client on ${chainLabel}.`, contract: chain.reputationRegistry, chain: chainLabel, chainId }
|
|
447
|
+
|
|
448
|
+
// ── Configuration ──────────────────────────────
|
|
449
|
+
case 'agentx_config_get': {
|
|
450
|
+
const v = await getContract(ck, chain.configurationRegistry, CFG_ABI).getConfig(Number(args.agentId), args.configKey as string)
|
|
451
|
+
return { agentId: Number(args.agentId), configKey: v.configKey, configValue: v.configValue, dataType: v.dataType, description: v.description, isActive: v.isActive, chain: chainLabel, chainId }
|
|
452
|
+
}
|
|
453
|
+
case 'agentx_config_list': {
|
|
454
|
+
const configs = await getContract(ck, chain.configurationRegistry, CFG_ABI).getAgentConfigs(Number(args.agentId))
|
|
455
|
+
return { agentId: Number(args.agentId), configs: configs.map((c: any) => ({ configKey: c.configKey, configValue: c.configValue, dataType: c.dataType, description: c.description, isActive: c.isActive })), chain: chainLabel, chainId }
|
|
456
|
+
}
|
|
457
|
+
case 'agentx_config_set':
|
|
458
|
+
return { _writeOp: true, message: `WRITE. Set config via wallet client on ${chainLabel}.`, contract: chain.configurationRegistry, chain: chainLabel, chainId }
|
|
459
|
+
|
|
460
|
+
// ── MultiEndpoint ──────────────────────────────
|
|
461
|
+
case 'agentx_endpoint_list': {
|
|
462
|
+
const eps = await getContract(ck, chain.multiEndpoint, EP_ABI).getAgentEndpoints(Number(args.agentId))
|
|
463
|
+
return { agentId: Number(args.agentId), endpoints: eps.map((e: any) => ({ endpointId: Number(e[0]), name: e[2], type: e[3], protocol: e[4], url: e[5], isActive: e[7] })), chain: chainLabel, chainId }
|
|
464
|
+
}
|
|
465
|
+
case 'agentx_endpoint_active': {
|
|
466
|
+
const eps = await getContract(ck, chain.multiEndpoint, EP_ABI).getActiveAgentEndpoints(Number(args.agentId))
|
|
467
|
+
return { agentId: Number(args.agentId), endpoints: eps.map((e: any) => ({ endpointId: Number(e[0]), name: e[2], type: e[3], protocol: e[4], url: e[5] })), chain: chainLabel, chainId }
|
|
468
|
+
}
|
|
469
|
+
case 'agentx_endpoint_best_mcp': {
|
|
470
|
+
const eps = await getContract(ck, chain.multiEndpoint, EP_ABI).getActiveAgentEndpoints(Number(args.agentId))
|
|
471
|
+
const mcp = eps.find((e: any) => e[3] === 'mcp' || e[4] === 'mcp')
|
|
472
|
+
return { agentId: Number(args.agentId), mcpUrl: mcp ? mcp[5] : null, chain: chainLabel, chainId }
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ── Gateway ────────────────────────────────────
|
|
476
|
+
case 'agentx_gateway_tenant': {
|
|
477
|
+
const token = args.accessToken as string
|
|
478
|
+
if (!token) return { error: 'accessToken required' }
|
|
479
|
+
const res = await fetch(`http://127.0.0.1:${config.port}/api/v1/tenant/me`, { headers: { Authorization: `Bearer ${token}` } })
|
|
480
|
+
if (!res.ok) return { error: `HTTP ${res.status}`, detail: await res.text() }
|
|
481
|
+
return res.json()
|
|
482
|
+
}
|
|
483
|
+
case 'agentx_gateway_health':
|
|
484
|
+
return {
|
|
485
|
+
status: 'ok',
|
|
486
|
+
time: new Date().toISOString(),
|
|
487
|
+
chains: {
|
|
488
|
+
sepolia: { chainId: config.chainId, rpcUrl: config.rpcUrl, identityRegistry: config.identityRegistry, subscriptionManager: config.subscriptionManager, a2aProtocol: config.a2aProtocol, reputationRegistry: config.reputationRegistry, configurationRegistry: config.configurationRegistry, multiEndpoint: config.multiEndpoint },
|
|
489
|
+
oxachain: { chainId: config.chainIdOxaChain, rpcUrl: config.rpcUrlOxaChain, identityRegistry: config.identityRegistryOxaChain, subscriptionManager: config.subscriptionManagerOxaChain, a2aProtocol: config.a2aProtocolOxaChain, reputationRegistry: config.reputationRegistryOxaChain, configurationRegistry: config.configurationRegistryOxaChain, multiEndpoint: config.multiEndpointOxaChain },
|
|
490
|
+
},
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
default:
|
|
494
|
+
return { error: `Unknown tool: ${name}`, availableTools: MCP_TOOLS.map(t => t.name) }
|
|
495
|
+
}
|
|
496
|
+
} catch (err: unknown) {
|
|
497
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
498
|
+
return { error: msg, tool: name, chain: chainLabel }
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ── MCP Router ──────────────────────────────────────────────────────────────
|
|
503
|
+
|
|
504
|
+
router.post('/', async (req: Request, res: Response) => {
|
|
505
|
+
const { jsonrpc, id, method, params } = req.body
|
|
506
|
+
|
|
507
|
+
if (jsonrpc !== '2.0') {
|
|
508
|
+
res.status(400).json({ jsonrpc: '2.0', id: id ?? null, error: { code: -32600, message: 'Invalid Request: jsonrpc must be "2.0"' } })
|
|
509
|
+
return
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
switch (method) {
|
|
514
|
+
case 'tools/list': {
|
|
515
|
+
const tools = MCP_TOOLS.map(t => ({
|
|
516
|
+
name: t.name,
|
|
517
|
+
description: t.description,
|
|
518
|
+
inputSchema: t.inputSchema,
|
|
519
|
+
}))
|
|
520
|
+
res.json({ jsonrpc: '2.0', id, result: { tools } })
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
case 'tools/call': {
|
|
525
|
+
const toolName = params?.name as string
|
|
526
|
+
const toolArgs = (params?.arguments ?? {}) as Record<string, unknown>
|
|
527
|
+
|
|
528
|
+
if (!toolName) {
|
|
529
|
+
res.json({ jsonrpc: '2.0', id, error: { code: -32602, message: 'Invalid params: missing tool "name"' } })
|
|
530
|
+
return
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (!MCP_TOOLS.some(t => t.name === toolName)) {
|
|
534
|
+
res.json({ jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${toolName}` } })
|
|
535
|
+
return
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const result = await executeToolCall(toolName, toolArgs)
|
|
539
|
+
res.json({
|
|
540
|
+
jsonrpc: '2.0', id,
|
|
541
|
+
result: {
|
|
542
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
543
|
+
isError: result && typeof result === 'object' && 'error' in result,
|
|
544
|
+
},
|
|
545
|
+
})
|
|
546
|
+
return
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
case 'initialize':
|
|
550
|
+
res.json({ jsonrpc: '2.0', id, result: { protocolVersion: '2024-11-05', serverInfo: { name: 'agentx-gateway', version: '0.2.0' }, capabilities: { tools: {} } } })
|
|
551
|
+
return
|
|
552
|
+
|
|
553
|
+
case 'notifications/initialized':
|
|
554
|
+
res.json({ jsonrpc: '2.0', id, result: {} })
|
|
555
|
+
return
|
|
556
|
+
|
|
557
|
+
default:
|
|
558
|
+
res.json({ jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } })
|
|
559
|
+
}
|
|
560
|
+
} catch (err: unknown) {
|
|
561
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
562
|
+
res.json({ jsonrpc: '2.0', id: id ?? null, error: { code: -32603, message: `Internal error: ${msg}` } })
|
|
563
|
+
}
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
export default router
|
|
567
|
+
export { MCP_TOOLS }
|