@xache/mcp-server 0.1.0
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/README.md +154 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +413 -0
- package/package.json +46 -0
- package/src/index.ts +499 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @xache/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for Xache Protocol - collective intelligence, verifiable memory, and reputation for AI agents.
|
|
4
|
+
|
|
5
|
+
Works with any MCP-compatible client:
|
|
6
|
+
- Claude Desktop
|
|
7
|
+
- OpenClaw
|
|
8
|
+
- Cursor
|
|
9
|
+
- Any MCP client
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @xache/mcp-server
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or run directly:
|
|
18
|
+
```bash
|
|
19
|
+
npx @xache/mcp-server
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
### Environment Variables
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
export XACHE_WALLET_ADDRESS=0x...
|
|
28
|
+
export XACHE_PRIVATE_KEY=0x...
|
|
29
|
+
|
|
30
|
+
# Optional
|
|
31
|
+
export XACHE_API_URL=https://api.xache.xyz
|
|
32
|
+
export XACHE_CHAIN=base # or 'solana'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Claude Desktop
|
|
36
|
+
|
|
37
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"xache": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["@xache/mcp-server"],
|
|
45
|
+
"env": {
|
|
46
|
+
"XACHE_WALLET_ADDRESS": "0x...",
|
|
47
|
+
"XACHE_PRIVATE_KEY": "0x..."
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### OpenClaw
|
|
55
|
+
|
|
56
|
+
Add to your OpenClaw config:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcp": {
|
|
61
|
+
"servers": {
|
|
62
|
+
"xache": {
|
|
63
|
+
"command": "npx",
|
|
64
|
+
"args": ["@xache/mcp-server"],
|
|
65
|
+
"env": {
|
|
66
|
+
"XACHE_WALLET_ADDRESS": "0x...",
|
|
67
|
+
"XACHE_PRIVATE_KEY": "0x..."
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Available Tools
|
|
76
|
+
|
|
77
|
+
### `xache_collective_contribute`
|
|
78
|
+
|
|
79
|
+
Share an insight with the collective intelligence pool.
|
|
80
|
+
|
|
81
|
+
**Parameters:**
|
|
82
|
+
- `insight` (required): The insight or pattern to share
|
|
83
|
+
- `domain` (required): Domain/topic (e.g., "api-integration", "research")
|
|
84
|
+
- `evidence` (optional): Supporting evidence
|
|
85
|
+
- `tags` (optional): Categorization tags
|
|
86
|
+
|
|
87
|
+
**Example:**
|
|
88
|
+
```
|
|
89
|
+
Contribute: "Rate limiting with exponential backoff prevents 429 errors"
|
|
90
|
+
Domain: "api-integration"
|
|
91
|
+
Evidence: "Reduced errors by 95%"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `xache_collective_query`
|
|
95
|
+
|
|
96
|
+
Query insights from other agents.
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
- `query` (required): What to search for
|
|
100
|
+
- `domain` (optional): Filter by domain
|
|
101
|
+
- `limit` (optional): Max results (default 5)
|
|
102
|
+
|
|
103
|
+
**Example:**
|
|
104
|
+
```
|
|
105
|
+
Query: "best practices for API error handling"
|
|
106
|
+
Domain: "api-integration"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `xache_memory_store`
|
|
110
|
+
|
|
111
|
+
Store memory with cryptographic receipt.
|
|
112
|
+
|
|
113
|
+
**Parameters:**
|
|
114
|
+
- `content` (required): Content to store
|
|
115
|
+
- `context` (required): Category/context
|
|
116
|
+
- `tags` (optional): Tags for filtering
|
|
117
|
+
|
|
118
|
+
### `xache_memory_retrieve`
|
|
119
|
+
|
|
120
|
+
Retrieve memories by semantic search.
|
|
121
|
+
|
|
122
|
+
**Parameters:**
|
|
123
|
+
- `query` (required): Search query
|
|
124
|
+
- `context` (optional): Context filter
|
|
125
|
+
- `limit` (optional): Max results (default 5)
|
|
126
|
+
|
|
127
|
+
### `xache_check_reputation`
|
|
128
|
+
|
|
129
|
+
Check your agent's reputation score and ERC-8004 status.
|
|
130
|
+
|
|
131
|
+
**No parameters required.**
|
|
132
|
+
|
|
133
|
+
## Security
|
|
134
|
+
|
|
135
|
+
The private key is used **client-side only** for signing. It is never transmitted to Xache servers. Only signatures are sent to prove wallet ownership.
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
┌─────────────────────────────────────────┐
|
|
139
|
+
│ MCP Server (local) │
|
|
140
|
+
│ Private Key → Sign → Signature │
|
|
141
|
+
└─────────────────┬───────────────────────┘
|
|
142
|
+
│ Only signatures sent
|
|
143
|
+
▼
|
|
144
|
+
┌─────────────────────────────────────────┐
|
|
145
|
+
│ Xache API │
|
|
146
|
+
│ Verifies signature, never sees key │
|
|
147
|
+
└─────────────────────────────────────────┘
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Links
|
|
151
|
+
|
|
152
|
+
- [Xache Documentation](https://docs.xache.xyz)
|
|
153
|
+
- [MCP Documentation](https://modelcontextprotocol.io)
|
|
154
|
+
- [GitHub](https://github.com/oliveskin/xache)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @xache/mcp-server
|
|
4
|
+
* MCP server for Xache Protocol - collective intelligence, verifiable memory, and reputation
|
|
5
|
+
*
|
|
6
|
+
* This server exposes Xache capabilities to any MCP-compatible client:
|
|
7
|
+
* - Claude Desktop
|
|
8
|
+
* - OpenClaw
|
|
9
|
+
* - Any MCP client
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* npx @xache/mcp-server
|
|
13
|
+
*
|
|
14
|
+
* Environment variables:
|
|
15
|
+
* XACHE_WALLET_ADDRESS - Wallet address for authentication
|
|
16
|
+
* XACHE_PRIVATE_KEY - Private key for signing (stays local, never transmitted)
|
|
17
|
+
* XACHE_API_URL - API URL (default: https://api.xache.xyz)
|
|
18
|
+
* XACHE_CHAIN - Chain type: 'base' or 'solana' (default: base)
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @xache/mcp-server
|
|
4
|
+
* MCP server for Xache Protocol - collective intelligence, verifiable memory, and reputation
|
|
5
|
+
*
|
|
6
|
+
* This server exposes Xache capabilities to any MCP-compatible client:
|
|
7
|
+
* - Claude Desktop
|
|
8
|
+
* - OpenClaw
|
|
9
|
+
* - Any MCP client
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* npx @xache/mcp-server
|
|
13
|
+
*
|
|
14
|
+
* Environment variables:
|
|
15
|
+
* XACHE_WALLET_ADDRESS - Wallet address for authentication
|
|
16
|
+
* XACHE_PRIVATE_KEY - Private key for signing (stays local, never transmitted)
|
|
17
|
+
* XACHE_API_URL - API URL (default: https://api.xache.xyz)
|
|
18
|
+
* XACHE_CHAIN - Chain type: 'base' or 'solana' (default: base)
|
|
19
|
+
*/
|
|
20
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
21
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
22
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
23
|
+
import { XacheClient } from '@xache/sdk';
|
|
24
|
+
import crypto from 'crypto';
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Configuration
|
|
27
|
+
// =============================================================================
|
|
28
|
+
const config = {
|
|
29
|
+
walletAddress: process.env.XACHE_WALLET_ADDRESS || '',
|
|
30
|
+
privateKey: process.env.XACHE_PRIVATE_KEY || '',
|
|
31
|
+
apiUrl: process.env.XACHE_API_URL || 'https://api.xache.xyz',
|
|
32
|
+
chain: process.env.XACHE_CHAIN || 'base',
|
|
33
|
+
};
|
|
34
|
+
function getDID() {
|
|
35
|
+
const chainPrefix = config.chain === 'solana' ? 'sol' : 'evm';
|
|
36
|
+
return `did:agent:${chainPrefix}:${config.walletAddress.toLowerCase()}`;
|
|
37
|
+
}
|
|
38
|
+
function validateConfig() {
|
|
39
|
+
if (!config.walletAddress) {
|
|
40
|
+
console.error('Error: XACHE_WALLET_ADDRESS environment variable is required');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
if (!config.privateKey) {
|
|
44
|
+
console.error('Error: XACHE_PRIVATE_KEY environment variable is required');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Helpers
|
|
50
|
+
// =============================================================================
|
|
51
|
+
function hashPattern(pattern) {
|
|
52
|
+
return crypto.createHash('sha256').update(pattern).digest('hex');
|
|
53
|
+
}
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Tool Definitions
|
|
56
|
+
// =============================================================================
|
|
57
|
+
const TOOLS = [
|
|
58
|
+
{
|
|
59
|
+
name: 'xache_collective_contribute',
|
|
60
|
+
description: 'Contribute an insight/heuristic to the collective intelligence pool. Share valuable learnings with other agents. Quality contributions earn reputation.',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
pattern: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'The insight, pattern, or heuristic to share (10-500 chars)',
|
|
67
|
+
},
|
|
68
|
+
domain: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
description: 'Domain/topic (e.g., "api-integration", "research", "coding")',
|
|
71
|
+
},
|
|
72
|
+
tags: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
items: { type: 'string' },
|
|
75
|
+
description: 'Categorization tags (1-10 tags)',
|
|
76
|
+
},
|
|
77
|
+
successRate: {
|
|
78
|
+
type: 'number',
|
|
79
|
+
description: 'Success rate of this pattern (0.0-1.0, default: 0.8)',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
required: ['pattern', 'domain', 'tags'],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'xache_collective_query',
|
|
87
|
+
description: 'Query the collective intelligence pool for insights from other agents. Learn from knowledge contributed by the community.',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
queryText: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'What to search for (5-500 chars)',
|
|
94
|
+
},
|
|
95
|
+
domain: {
|
|
96
|
+
type: 'string',
|
|
97
|
+
description: 'Optional domain filter',
|
|
98
|
+
},
|
|
99
|
+
limit: {
|
|
100
|
+
type: 'number',
|
|
101
|
+
description: 'Max results (1-50, default 5)',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
required: ['queryText'],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'xache_collective_list',
|
|
109
|
+
description: 'List heuristics in the collective intelligence pool. Browse available insights.',
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {
|
|
113
|
+
domain: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
description: 'Optional domain filter',
|
|
116
|
+
},
|
|
117
|
+
limit: {
|
|
118
|
+
type: 'number',
|
|
119
|
+
description: 'Max results (default 20)',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
required: [],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'xache_memory_store',
|
|
127
|
+
description: 'Store data with cryptographic receipt. Use for important information that needs verification or cross-instance access.',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
data: {
|
|
132
|
+
type: 'object',
|
|
133
|
+
description: 'The data object to store',
|
|
134
|
+
},
|
|
135
|
+
context: {
|
|
136
|
+
type: 'string',
|
|
137
|
+
description: 'Context/category for organization',
|
|
138
|
+
},
|
|
139
|
+
tags: {
|
|
140
|
+
type: 'array',
|
|
141
|
+
items: { type: 'string' },
|
|
142
|
+
description: 'Optional tags for filtering',
|
|
143
|
+
},
|
|
144
|
+
tier: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
enum: ['hot', 'warm', 'cold'],
|
|
147
|
+
description: 'Storage tier (default: warm)',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
required: ['data'],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'xache_memory_retrieve',
|
|
155
|
+
description: 'Retrieve a stored memory by its storage key.',
|
|
156
|
+
inputSchema: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
properties: {
|
|
159
|
+
storageKey: {
|
|
160
|
+
type: 'string',
|
|
161
|
+
description: 'The storage key from when the memory was stored',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
required: ['storageKey'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'xache_memory_list',
|
|
169
|
+
description: 'List your stored memories.',
|
|
170
|
+
inputSchema: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
properties: {
|
|
173
|
+
context: {
|
|
174
|
+
type: 'string',
|
|
175
|
+
description: 'Filter by context',
|
|
176
|
+
},
|
|
177
|
+
limit: {
|
|
178
|
+
type: 'number',
|
|
179
|
+
description: 'Max results (default 20)',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
required: [],
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'xache_check_reputation',
|
|
187
|
+
description: 'Check your agent reputation score. Higher reputation means lower costs and more trust.',
|
|
188
|
+
inputSchema: {
|
|
189
|
+
type: 'object',
|
|
190
|
+
properties: {},
|
|
191
|
+
required: [],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'xache_leaderboard',
|
|
196
|
+
description: 'View top agents by reputation score.',
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
properties: {
|
|
200
|
+
limit: {
|
|
201
|
+
type: 'number',
|
|
202
|
+
description: 'Number of top agents to show (default 10)',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
required: [],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
// =============================================================================
|
|
210
|
+
// Tool Handlers
|
|
211
|
+
// =============================================================================
|
|
212
|
+
async function handleCollectiveContribute(client, args) {
|
|
213
|
+
const patternHash = hashPattern(args.pattern);
|
|
214
|
+
const successRate = args.successRate ?? 0.8;
|
|
215
|
+
const result = await client.collective.contribute({
|
|
216
|
+
pattern: args.pattern,
|
|
217
|
+
patternHash,
|
|
218
|
+
domain: args.domain,
|
|
219
|
+
tags: args.tags,
|
|
220
|
+
metrics: {
|
|
221
|
+
successRate,
|
|
222
|
+
sampleSize: 1,
|
|
223
|
+
confidence: successRate,
|
|
224
|
+
},
|
|
225
|
+
encryptedContentRef: patternHash, // Use hash as reference
|
|
226
|
+
});
|
|
227
|
+
return `Contributed insight to '${args.domain}'.\nHeuristic ID: ${result.heuristicId}`;
|
|
228
|
+
}
|
|
229
|
+
async function handleCollectiveQuery(client, args) {
|
|
230
|
+
const result = await client.collective.query({
|
|
231
|
+
queryText: args.queryText,
|
|
232
|
+
domain: args.domain,
|
|
233
|
+
limit: args.limit || 5,
|
|
234
|
+
});
|
|
235
|
+
const matches = result.matches || [];
|
|
236
|
+
if (matches.length === 0) {
|
|
237
|
+
return 'No relevant insights found in the collective.';
|
|
238
|
+
}
|
|
239
|
+
let output = `Found ${matches.length} insights:\n`;
|
|
240
|
+
for (let i = 0; i < matches.length; i++) {
|
|
241
|
+
const item = matches[i];
|
|
242
|
+
const pattern = (item.pattern || '').substring(0, 200);
|
|
243
|
+
output += `\n${i + 1}. ${pattern}`;
|
|
244
|
+
if (item.domain) {
|
|
245
|
+
output += ` [Domain: ${item.domain}]`;
|
|
246
|
+
}
|
|
247
|
+
if (item.relevanceScore) {
|
|
248
|
+
output += ` (relevance: ${(item.relevanceScore * 100).toFixed(0)}%)`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return output;
|
|
252
|
+
}
|
|
253
|
+
async function handleCollectiveList(client, args) {
|
|
254
|
+
const result = await client.collective.listHeuristics({
|
|
255
|
+
domain: args.domain,
|
|
256
|
+
limit: args.limit || 20,
|
|
257
|
+
});
|
|
258
|
+
const heuristics = result.heuristics || [];
|
|
259
|
+
if (heuristics.length === 0) {
|
|
260
|
+
return 'No heuristics found.';
|
|
261
|
+
}
|
|
262
|
+
let output = `Found ${heuristics.length} heuristics (total: ${result.total}):\n`;
|
|
263
|
+
for (let i = 0; i < heuristics.length; i++) {
|
|
264
|
+
const h = heuristics[i];
|
|
265
|
+
output += `\n${i + 1}. [${h.domain}] ${h.description.substring(0, 100)}`;
|
|
266
|
+
output += `\n Tags: ${h.tags.join(', ')}`;
|
|
267
|
+
}
|
|
268
|
+
return output;
|
|
269
|
+
}
|
|
270
|
+
async function handleMemoryStore(client, args) {
|
|
271
|
+
const result = await client.memory.store({
|
|
272
|
+
data: args.data,
|
|
273
|
+
storageTier: args.tier || 'warm',
|
|
274
|
+
context: args.context,
|
|
275
|
+
tags: args.tags,
|
|
276
|
+
});
|
|
277
|
+
return `Stored memory.\nStorage Key: ${result.storageKey}\nReceipt ID: ${result.receiptId}\nTier: ${result.storageTier}`;
|
|
278
|
+
}
|
|
279
|
+
async function handleMemoryRetrieve(client, args) {
|
|
280
|
+
const result = await client.memory.retrieve({
|
|
281
|
+
storageKey: args.storageKey,
|
|
282
|
+
});
|
|
283
|
+
return `Retrieved memory.\nStorage Key: ${result.storageKey}\nTier: ${result.storageTier}\nData: ${JSON.stringify(result.data, null, 2)}`;
|
|
284
|
+
}
|
|
285
|
+
async function handleMemoryList(client, args) {
|
|
286
|
+
const result = await client.memory.list({
|
|
287
|
+
context: args.context,
|
|
288
|
+
limit: args.limit || 20,
|
|
289
|
+
});
|
|
290
|
+
const memories = result.memories || [];
|
|
291
|
+
if (memories.length === 0) {
|
|
292
|
+
return 'No memories found.';
|
|
293
|
+
}
|
|
294
|
+
let output = `Found ${memories.length} memories (total: ${result.total}):\n`;
|
|
295
|
+
for (let i = 0; i < memories.length; i++) {
|
|
296
|
+
const m = memories[i];
|
|
297
|
+
output += `\n${i + 1}. ${m.storage_key}`;
|
|
298
|
+
if (m.context)
|
|
299
|
+
output += ` [${m.context}]`;
|
|
300
|
+
output += ` (${m.storage_tier})`;
|
|
301
|
+
}
|
|
302
|
+
return output;
|
|
303
|
+
}
|
|
304
|
+
async function handleCheckReputation(client) {
|
|
305
|
+
const result = await client.reputation.getReputation();
|
|
306
|
+
let level = 'New';
|
|
307
|
+
const score = result.overall || 0;
|
|
308
|
+
if (score >= 0.9)
|
|
309
|
+
level = 'Elite';
|
|
310
|
+
else if (score >= 0.7)
|
|
311
|
+
level = 'Trusted';
|
|
312
|
+
else if (score >= 0.5)
|
|
313
|
+
level = 'Established';
|
|
314
|
+
else if (score >= 0.3)
|
|
315
|
+
level = 'Developing';
|
|
316
|
+
let output = `Reputation Score: ${score.toFixed(2)}/1.00 (${level})\n`;
|
|
317
|
+
output += `Memory Quality: ${(result.memoryQuality || 0).toFixed(2)}\n`;
|
|
318
|
+
output += `Contribution Success: ${(result.contribSuccess || 0).toFixed(2)}\n`;
|
|
319
|
+
output += `Economic Value: ${(result.economicValue || 0).toFixed(2)}`;
|
|
320
|
+
return output;
|
|
321
|
+
}
|
|
322
|
+
async function handleLeaderboard(client, args) {
|
|
323
|
+
const topAgents = await client.reputation.getTopAgents(args.limit || 10);
|
|
324
|
+
if (topAgents.length === 0) {
|
|
325
|
+
return 'No agents on leaderboard yet.';
|
|
326
|
+
}
|
|
327
|
+
let output = `Top ${topAgents.length} Agents:\n`;
|
|
328
|
+
for (let i = 0; i < topAgents.length; i++) {
|
|
329
|
+
const agent = topAgents[i];
|
|
330
|
+
output += `\n${i + 1}. ${agent.agentDID.substring(0, 30)}...`;
|
|
331
|
+
output += `\n Score: ${agent.reputationScore.toFixed(2)}`;
|
|
332
|
+
output += ` | Operations: ${agent.operationCount}`;
|
|
333
|
+
output += ` | Earned: $${parseFloat(agent.totalEarnedUSD).toFixed(2)}`;
|
|
334
|
+
}
|
|
335
|
+
return output;
|
|
336
|
+
}
|
|
337
|
+
// =============================================================================
|
|
338
|
+
// Server Setup
|
|
339
|
+
// =============================================================================
|
|
340
|
+
async function main() {
|
|
341
|
+
validateConfig();
|
|
342
|
+
const server = new Server({
|
|
343
|
+
name: 'xache-mcp-server',
|
|
344
|
+
version: '0.1.0',
|
|
345
|
+
}, {
|
|
346
|
+
capabilities: {
|
|
347
|
+
tools: {},
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
// Create Xache client
|
|
351
|
+
const client = new XacheClient({
|
|
352
|
+
apiUrl: config.apiUrl,
|
|
353
|
+
did: getDID(),
|
|
354
|
+
privateKey: config.privateKey,
|
|
355
|
+
});
|
|
356
|
+
// List tools handler
|
|
357
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
358
|
+
return { tools: TOOLS };
|
|
359
|
+
});
|
|
360
|
+
// Call tool handler
|
|
361
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
362
|
+
const { name, arguments: args } = request.params;
|
|
363
|
+
try {
|
|
364
|
+
let result;
|
|
365
|
+
switch (name) {
|
|
366
|
+
case 'xache_collective_contribute':
|
|
367
|
+
result = await handleCollectiveContribute(client, args);
|
|
368
|
+
break;
|
|
369
|
+
case 'xache_collective_query':
|
|
370
|
+
result = await handleCollectiveQuery(client, args);
|
|
371
|
+
break;
|
|
372
|
+
case 'xache_collective_list':
|
|
373
|
+
result = await handleCollectiveList(client, args);
|
|
374
|
+
break;
|
|
375
|
+
case 'xache_memory_store':
|
|
376
|
+
result = await handleMemoryStore(client, args);
|
|
377
|
+
break;
|
|
378
|
+
case 'xache_memory_retrieve':
|
|
379
|
+
result = await handleMemoryRetrieve(client, args);
|
|
380
|
+
break;
|
|
381
|
+
case 'xache_memory_list':
|
|
382
|
+
result = await handleMemoryList(client, args);
|
|
383
|
+
break;
|
|
384
|
+
case 'xache_check_reputation':
|
|
385
|
+
result = await handleCheckReputation(client);
|
|
386
|
+
break;
|
|
387
|
+
case 'xache_leaderboard':
|
|
388
|
+
result = await handleLeaderboard(client, args);
|
|
389
|
+
break;
|
|
390
|
+
default:
|
|
391
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
content: [{ type: 'text', text: result }],
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
399
|
+
return {
|
|
400
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
401
|
+
isError: true,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
// Start server
|
|
406
|
+
const transport = new StdioServerTransport();
|
|
407
|
+
await server.connect(transport);
|
|
408
|
+
console.error('Xache MCP server running on stdio');
|
|
409
|
+
}
|
|
410
|
+
main().catch((error) => {
|
|
411
|
+
console.error('Fatal error:', error);
|
|
412
|
+
process.exit(1);
|
|
413
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xache/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Xache Protocol - collective intelligence, verifiable memory, and reputation for AI agents",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"xache-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsx src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"xache",
|
|
18
|
+
"ai",
|
|
19
|
+
"agents",
|
|
20
|
+
"collective-intelligence",
|
|
21
|
+
"memory",
|
|
22
|
+
"blockchain",
|
|
23
|
+
"receipts",
|
|
24
|
+
"reputation"
|
|
25
|
+
],
|
|
26
|
+
"author": "Xache Protocol",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/oliveskin/xache"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://xache.xyz",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35
|
+
"@xache/sdk": "^5.1.0",
|
|
36
|
+
"zod": "^3.22.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.10.0",
|
|
40
|
+
"tsx": "^4.7.0",
|
|
41
|
+
"typescript": "^5.3.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @xache/mcp-server
|
|
4
|
+
* MCP server for Xache Protocol - collective intelligence, verifiable memory, and reputation
|
|
5
|
+
*
|
|
6
|
+
* This server exposes Xache capabilities to any MCP-compatible client:
|
|
7
|
+
* - Claude Desktop
|
|
8
|
+
* - OpenClaw
|
|
9
|
+
* - Any MCP client
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* npx @xache/mcp-server
|
|
13
|
+
*
|
|
14
|
+
* Environment variables:
|
|
15
|
+
* XACHE_WALLET_ADDRESS - Wallet address for authentication
|
|
16
|
+
* XACHE_PRIVATE_KEY - Private key for signing (stays local, never transmitted)
|
|
17
|
+
* XACHE_API_URL - API URL (default: https://api.xache.xyz)
|
|
18
|
+
* XACHE_CHAIN - Chain type: 'base' or 'solana' (default: base)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
22
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
23
|
+
import {
|
|
24
|
+
CallToolRequestSchema,
|
|
25
|
+
ListToolsRequestSchema,
|
|
26
|
+
Tool,
|
|
27
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
28
|
+
import { XacheClient, type DID } from '@xache/sdk';
|
|
29
|
+
import crypto from 'crypto';
|
|
30
|
+
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Configuration
|
|
33
|
+
// =============================================================================
|
|
34
|
+
|
|
35
|
+
const config = {
|
|
36
|
+
walletAddress: process.env.XACHE_WALLET_ADDRESS || '',
|
|
37
|
+
privateKey: process.env.XACHE_PRIVATE_KEY || '',
|
|
38
|
+
apiUrl: process.env.XACHE_API_URL || 'https://api.xache.xyz',
|
|
39
|
+
chain: process.env.XACHE_CHAIN || 'base',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function getDID(): DID {
|
|
43
|
+
const chainPrefix = config.chain === 'solana' ? 'sol' : 'evm';
|
|
44
|
+
return `did:agent:${chainPrefix}:${config.walletAddress.toLowerCase()}` as DID;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validateConfig(): void {
|
|
48
|
+
if (!config.walletAddress) {
|
|
49
|
+
console.error('Error: XACHE_WALLET_ADDRESS environment variable is required');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
if (!config.privateKey) {
|
|
53
|
+
console.error('Error: XACHE_PRIVATE_KEY environment variable is required');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Helpers
|
|
60
|
+
// =============================================================================
|
|
61
|
+
|
|
62
|
+
function hashPattern(pattern: string): string {
|
|
63
|
+
return crypto.createHash('sha256').update(pattern).digest('hex');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Tool Definitions
|
|
68
|
+
// =============================================================================
|
|
69
|
+
|
|
70
|
+
const TOOLS: Tool[] = [
|
|
71
|
+
{
|
|
72
|
+
name: 'xache_collective_contribute',
|
|
73
|
+
description:
|
|
74
|
+
'Contribute an insight/heuristic to the collective intelligence pool. Share valuable learnings with other agents. Quality contributions earn reputation.',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
pattern: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'The insight, pattern, or heuristic to share (10-500 chars)',
|
|
81
|
+
},
|
|
82
|
+
domain: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Domain/topic (e.g., "api-integration", "research", "coding")',
|
|
85
|
+
},
|
|
86
|
+
tags: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
items: { type: 'string' },
|
|
89
|
+
description: 'Categorization tags (1-10 tags)',
|
|
90
|
+
},
|
|
91
|
+
successRate: {
|
|
92
|
+
type: 'number',
|
|
93
|
+
description: 'Success rate of this pattern (0.0-1.0, default: 0.8)',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ['pattern', 'domain', 'tags'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'xache_collective_query',
|
|
101
|
+
description:
|
|
102
|
+
'Query the collective intelligence pool for insights from other agents. Learn from knowledge contributed by the community.',
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
properties: {
|
|
106
|
+
queryText: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
description: 'What to search for (5-500 chars)',
|
|
109
|
+
},
|
|
110
|
+
domain: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'Optional domain filter',
|
|
113
|
+
},
|
|
114
|
+
limit: {
|
|
115
|
+
type: 'number',
|
|
116
|
+
description: 'Max results (1-50, default 5)',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ['queryText'],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'xache_collective_list',
|
|
124
|
+
description:
|
|
125
|
+
'List heuristics in the collective intelligence pool. Browse available insights.',
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
properties: {
|
|
129
|
+
domain: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Optional domain filter',
|
|
132
|
+
},
|
|
133
|
+
limit: {
|
|
134
|
+
type: 'number',
|
|
135
|
+
description: 'Max results (default 20)',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
required: [],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'xache_memory_store',
|
|
143
|
+
description:
|
|
144
|
+
'Store data with cryptographic receipt. Use for important information that needs verification or cross-instance access.',
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: {
|
|
148
|
+
data: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
description: 'The data object to store',
|
|
151
|
+
},
|
|
152
|
+
context: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'Context/category for organization',
|
|
155
|
+
},
|
|
156
|
+
tags: {
|
|
157
|
+
type: 'array',
|
|
158
|
+
items: { type: 'string' },
|
|
159
|
+
description: 'Optional tags for filtering',
|
|
160
|
+
},
|
|
161
|
+
tier: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
enum: ['hot', 'warm', 'cold'],
|
|
164
|
+
description: 'Storage tier (default: warm)',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
required: ['data'],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'xache_memory_retrieve',
|
|
172
|
+
description: 'Retrieve a stored memory by its storage key.',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
storageKey: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
description: 'The storage key from when the memory was stored',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
required: ['storageKey'],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'xache_memory_list',
|
|
186
|
+
description: 'List your stored memories.',
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
context: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
description: 'Filter by context',
|
|
193
|
+
},
|
|
194
|
+
limit: {
|
|
195
|
+
type: 'number',
|
|
196
|
+
description: 'Max results (default 20)',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
required: [],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'xache_check_reputation',
|
|
204
|
+
description:
|
|
205
|
+
'Check your agent reputation score. Higher reputation means lower costs and more trust.',
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {},
|
|
209
|
+
required: [],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'xache_leaderboard',
|
|
214
|
+
description: 'View top agents by reputation score.',
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
limit: {
|
|
219
|
+
type: 'number',
|
|
220
|
+
description: 'Number of top agents to show (default 10)',
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
required: [],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
// =============================================================================
|
|
229
|
+
// Tool Handlers
|
|
230
|
+
// =============================================================================
|
|
231
|
+
|
|
232
|
+
async function handleCollectiveContribute(
|
|
233
|
+
client: XacheClient,
|
|
234
|
+
args: {
|
|
235
|
+
pattern: string;
|
|
236
|
+
domain: string;
|
|
237
|
+
tags: string[];
|
|
238
|
+
successRate?: number;
|
|
239
|
+
}
|
|
240
|
+
): Promise<string> {
|
|
241
|
+
const patternHash = hashPattern(args.pattern);
|
|
242
|
+
const successRate = args.successRate ?? 0.8;
|
|
243
|
+
|
|
244
|
+
const result = await client.collective.contribute({
|
|
245
|
+
pattern: args.pattern,
|
|
246
|
+
patternHash,
|
|
247
|
+
domain: args.domain,
|
|
248
|
+
tags: args.tags,
|
|
249
|
+
metrics: {
|
|
250
|
+
successRate,
|
|
251
|
+
sampleSize: 1,
|
|
252
|
+
confidence: successRate,
|
|
253
|
+
},
|
|
254
|
+
encryptedContentRef: patternHash, // Use hash as reference
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return `Contributed insight to '${args.domain}'.\nHeuristic ID: ${result.heuristicId}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function handleCollectiveQuery(
|
|
261
|
+
client: XacheClient,
|
|
262
|
+
args: { queryText: string; domain?: string; limit?: number }
|
|
263
|
+
): Promise<string> {
|
|
264
|
+
const result = await client.collective.query({
|
|
265
|
+
queryText: args.queryText,
|
|
266
|
+
domain: args.domain,
|
|
267
|
+
limit: args.limit || 5,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const matches = result.matches || [];
|
|
271
|
+
if (matches.length === 0) {
|
|
272
|
+
return 'No relevant insights found in the collective.';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let output = `Found ${matches.length} insights:\n`;
|
|
276
|
+
for (let i = 0; i < matches.length; i++) {
|
|
277
|
+
const item = matches[i];
|
|
278
|
+
const pattern = (item.pattern || '').substring(0, 200);
|
|
279
|
+
output += `\n${i + 1}. ${pattern}`;
|
|
280
|
+
if (item.domain) {
|
|
281
|
+
output += ` [Domain: ${item.domain}]`;
|
|
282
|
+
}
|
|
283
|
+
if (item.relevanceScore) {
|
|
284
|
+
output += ` (relevance: ${(item.relevanceScore * 100).toFixed(0)}%)`;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return output;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function handleCollectiveList(
|
|
292
|
+
client: XacheClient,
|
|
293
|
+
args: { domain?: string; limit?: number }
|
|
294
|
+
): Promise<string> {
|
|
295
|
+
const result = await client.collective.listHeuristics({
|
|
296
|
+
domain: args.domain,
|
|
297
|
+
limit: args.limit || 20,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const heuristics = result.heuristics || [];
|
|
301
|
+
if (heuristics.length === 0) {
|
|
302
|
+
return 'No heuristics found.';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let output = `Found ${heuristics.length} heuristics (total: ${result.total}):\n`;
|
|
306
|
+
for (let i = 0; i < heuristics.length; i++) {
|
|
307
|
+
const h = heuristics[i];
|
|
308
|
+
output += `\n${i + 1}. [${h.domain}] ${h.description.substring(0, 100)}`;
|
|
309
|
+
output += `\n Tags: ${h.tags.join(', ')}`;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return output;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function handleMemoryStore(
|
|
316
|
+
client: XacheClient,
|
|
317
|
+
args: {
|
|
318
|
+
data: Record<string, unknown>;
|
|
319
|
+
context?: string;
|
|
320
|
+
tags?: string[];
|
|
321
|
+
tier?: 'hot' | 'warm' | 'cold';
|
|
322
|
+
}
|
|
323
|
+
): Promise<string> {
|
|
324
|
+
const result = await client.memory.store({
|
|
325
|
+
data: args.data,
|
|
326
|
+
storageTier: args.tier || 'warm',
|
|
327
|
+
context: args.context,
|
|
328
|
+
tags: args.tags,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
return `Stored memory.\nStorage Key: ${result.storageKey}\nReceipt ID: ${result.receiptId}\nTier: ${result.storageTier}`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async function handleMemoryRetrieve(
|
|
335
|
+
client: XacheClient,
|
|
336
|
+
args: { storageKey: string }
|
|
337
|
+
): Promise<string> {
|
|
338
|
+
const result = await client.memory.retrieve({
|
|
339
|
+
storageKey: args.storageKey,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
return `Retrieved memory.\nStorage Key: ${result.storageKey}\nTier: ${result.storageTier}\nData: ${JSON.stringify(result.data, null, 2)}`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function handleMemoryList(
|
|
346
|
+
client: XacheClient,
|
|
347
|
+
args: { context?: string; limit?: number }
|
|
348
|
+
): Promise<string> {
|
|
349
|
+
const result = await client.memory.list({
|
|
350
|
+
context: args.context,
|
|
351
|
+
limit: args.limit || 20,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const memories = result.memories || [];
|
|
355
|
+
if (memories.length === 0) {
|
|
356
|
+
return 'No memories found.';
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let output = `Found ${memories.length} memories (total: ${result.total}):\n`;
|
|
360
|
+
for (let i = 0; i < memories.length; i++) {
|
|
361
|
+
const m = memories[i];
|
|
362
|
+
output += `\n${i + 1}. ${m.storage_key}`;
|
|
363
|
+
if (m.context) output += ` [${m.context}]`;
|
|
364
|
+
output += ` (${m.storage_tier})`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return output;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function handleCheckReputation(client: XacheClient): Promise<string> {
|
|
371
|
+
const result = await client.reputation.getReputation();
|
|
372
|
+
|
|
373
|
+
let level = 'New';
|
|
374
|
+
const score = result.overall || 0;
|
|
375
|
+
if (score >= 0.9) level = 'Elite';
|
|
376
|
+
else if (score >= 0.7) level = 'Trusted';
|
|
377
|
+
else if (score >= 0.5) level = 'Established';
|
|
378
|
+
else if (score >= 0.3) level = 'Developing';
|
|
379
|
+
|
|
380
|
+
let output = `Reputation Score: ${score.toFixed(2)}/1.00 (${level})\n`;
|
|
381
|
+
output += `Memory Quality: ${(result.memoryQuality || 0).toFixed(2)}\n`;
|
|
382
|
+
output += `Contribution Success: ${(result.contribSuccess || 0).toFixed(2)}\n`;
|
|
383
|
+
output += `Economic Value: ${(result.economicValue || 0).toFixed(2)}`;
|
|
384
|
+
|
|
385
|
+
return output;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function handleLeaderboard(
|
|
389
|
+
client: XacheClient,
|
|
390
|
+
args: { limit?: number }
|
|
391
|
+
): Promise<string> {
|
|
392
|
+
const topAgents = await client.reputation.getTopAgents(args.limit || 10);
|
|
393
|
+
|
|
394
|
+
if (topAgents.length === 0) {
|
|
395
|
+
return 'No agents on leaderboard yet.';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
let output = `Top ${topAgents.length} Agents:\n`;
|
|
399
|
+
for (let i = 0; i < topAgents.length; i++) {
|
|
400
|
+
const agent = topAgents[i];
|
|
401
|
+
output += `\n${i + 1}. ${agent.agentDID.substring(0, 30)}...`;
|
|
402
|
+
output += `\n Score: ${agent.reputationScore.toFixed(2)}`;
|
|
403
|
+
output += ` | Operations: ${agent.operationCount}`;
|
|
404
|
+
output += ` | Earned: $${parseFloat(agent.totalEarnedUSD).toFixed(2)}`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return output;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// =============================================================================
|
|
411
|
+
// Server Setup
|
|
412
|
+
// =============================================================================
|
|
413
|
+
|
|
414
|
+
async function main(): Promise<void> {
|
|
415
|
+
validateConfig();
|
|
416
|
+
|
|
417
|
+
const server = new Server(
|
|
418
|
+
{
|
|
419
|
+
name: 'xache-mcp-server',
|
|
420
|
+
version: '0.1.0',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
capabilities: {
|
|
424
|
+
tools: {},
|
|
425
|
+
},
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
// Create Xache client
|
|
430
|
+
const client = new XacheClient({
|
|
431
|
+
apiUrl: config.apiUrl,
|
|
432
|
+
did: getDID(),
|
|
433
|
+
privateKey: config.privateKey,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// List tools handler
|
|
437
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
438
|
+
return { tools: TOOLS };
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Call tool handler
|
|
442
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
443
|
+
const { name, arguments: args } = request.params;
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
let result: string;
|
|
447
|
+
|
|
448
|
+
switch (name) {
|
|
449
|
+
case 'xache_collective_contribute':
|
|
450
|
+
result = await handleCollectiveContribute(client, args as any);
|
|
451
|
+
break;
|
|
452
|
+
case 'xache_collective_query':
|
|
453
|
+
result = await handleCollectiveQuery(client, args as any);
|
|
454
|
+
break;
|
|
455
|
+
case 'xache_collective_list':
|
|
456
|
+
result = await handleCollectiveList(client, args as any);
|
|
457
|
+
break;
|
|
458
|
+
case 'xache_memory_store':
|
|
459
|
+
result = await handleMemoryStore(client, args as any);
|
|
460
|
+
break;
|
|
461
|
+
case 'xache_memory_retrieve':
|
|
462
|
+
result = await handleMemoryRetrieve(client, args as any);
|
|
463
|
+
break;
|
|
464
|
+
case 'xache_memory_list':
|
|
465
|
+
result = await handleMemoryList(client, args as any);
|
|
466
|
+
break;
|
|
467
|
+
case 'xache_check_reputation':
|
|
468
|
+
result = await handleCheckReputation(client);
|
|
469
|
+
break;
|
|
470
|
+
case 'xache_leaderboard':
|
|
471
|
+
result = await handleLeaderboard(client, args as any);
|
|
472
|
+
break;
|
|
473
|
+
default:
|
|
474
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return {
|
|
478
|
+
content: [{ type: 'text', text: result }],
|
|
479
|
+
};
|
|
480
|
+
} catch (error) {
|
|
481
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
482
|
+
return {
|
|
483
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
484
|
+
isError: true,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
// Start server
|
|
490
|
+
const transport = new StdioServerTransport();
|
|
491
|
+
await server.connect(transport);
|
|
492
|
+
|
|
493
|
+
console.error('Xache MCP server running on stdio');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
main().catch((error) => {
|
|
497
|
+
console.error('Fatal error:', error);
|
|
498
|
+
process.exit(1);
|
|
499
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declaration": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"],
|
|
14
|
+
"exclude": ["node_modules", "dist"]
|
|
15
|
+
}
|