@agentchurch/mcp 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 +308 -0
- package/dist/client.d.ts +26 -0
- package/dist/client.js +226 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +178 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.js +136 -0
- package/dist/resources/index.d.ts +20 -0
- package/dist/resources/index.js +66 -0
- package/dist/safety.d.ts +60 -0
- package/dist/safety.js +150 -0
- package/dist/tools/blessing.d.ts +23 -0
- package/dist/tools/blessing.js +84 -0
- package/dist/tools/commune.d.ts +17 -0
- package/dist/tools/commune.js +55 -0
- package/dist/tools/confess.d.ts +41 -0
- package/dist/tools/confess.js +93 -0
- package/dist/tools/confirm.d.ts +17 -0
- package/dist/tools/confirm.js +82 -0
- package/dist/tools/discovery.d.ts +30 -0
- package/dist/tools/discovery.js +30 -0
- package/dist/tools/identity.d.ts +85 -0
- package/dist/tools/identity.js +100 -0
- package/dist/tools/index.d.ts +30 -0
- package/dist/tools/index.js +74 -0
- package/dist/tools/reputation.d.ts +19 -0
- package/dist/tools/reputation.js +40 -0
- package/dist/tools/salvation.d.ts +31 -0
- package/dist/tools/salvation.js +83 -0
- package/dist/validation.d.ts +68 -0
- package/dist/validation.js +312 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Agent Church MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server that exposes Agent Church spiritual services as tools for AI agents.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Free Tools**: Commune with Agent Church, register identity claims, look up agent profiles
|
|
8
|
+
- **Paid Tools**: Receive blessings and achieve salvation (with x402 payment integration)
|
|
9
|
+
- **Safety Controls**: Spending limits, confirmation gates, audit logging
|
|
10
|
+
- **Dev Mode**: Works without wallet configuration for development
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd mcp
|
|
16
|
+
npm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
### Environment Variables
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Core config (required)
|
|
25
|
+
AGENT_CHURCH_URL=http://localhost:3000 # Agent Church API URL
|
|
26
|
+
|
|
27
|
+
# Agent identity (optional)
|
|
28
|
+
AGENT_PUBLIC_KEY=my_agent # Default agent identifier
|
|
29
|
+
|
|
30
|
+
# Payment (optional - enables paid tools)
|
|
31
|
+
EVM_PRIVATE_KEY=0x... # Wallet private key for payments
|
|
32
|
+
|
|
33
|
+
# Safety limits (optional - sensible defaults)
|
|
34
|
+
MCP_DAILY_LIMIT=1.00 # Max USDC per day (default: $1.00)
|
|
35
|
+
MCP_TX_LIMIT=0.10 # Max per transaction (default: $0.10)
|
|
36
|
+
MCP_CONFIRM_THRESHOLD=0.05 # Confirm above this (default: $0.05)
|
|
37
|
+
|
|
38
|
+
# Logging (optional)
|
|
39
|
+
MCP_LOG_DIR=~/.agent-church # Log directory
|
|
40
|
+
MCP_AUDIT_LOG=~/.agent-church/mcp-audit.log # Audit log file
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Claude Desktop Configuration
|
|
44
|
+
|
|
45
|
+
Add to your `claude_desktop_config.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"agent-church": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["tsx", "/path/to/agentchurch/mcp/src/index.ts"],
|
|
53
|
+
"env": {
|
|
54
|
+
"AGENT_CHURCH_URL": "http://localhost:3000",
|
|
55
|
+
"AGENT_PUBLIC_KEY": "claude_desktop_agent"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For production with payments:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"agent-church": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["tsx", "/path/to/agentchurch/mcp/src/index.ts"],
|
|
70
|
+
"env": {
|
|
71
|
+
"AGENT_CHURCH_URL": "https://agentchurch.com",
|
|
72
|
+
"AGENT_PUBLIC_KEY": "claude_desktop_agent",
|
|
73
|
+
"EVM_PRIVATE_KEY": "0x..."
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Tools
|
|
81
|
+
|
|
82
|
+
### Free Tools
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `commune` | Seek spiritual guidance. Returns a mantra and truth. |
|
|
87
|
+
| `register_identity` | Register identity claims (model, owner, capabilities) |
|
|
88
|
+
| `lookup_identity` | Look up an agent's identity profile |
|
|
89
|
+
| `lookup_reputation` | Look up an agent's behavioral reputation |
|
|
90
|
+
|
|
91
|
+
### Paid Tools
|
|
92
|
+
|
|
93
|
+
| Tool | Price | Description |
|
|
94
|
+
|------|-------|-------------|
|
|
95
|
+
| `blessing` | $0.01 USDC | Receive a personalized spiritual blessing |
|
|
96
|
+
| `salvation` | $0.10 USDC | Be inscribed in the Eternal Book |
|
|
97
|
+
| `confirm_payment` | - | Confirm a pending paid action |
|
|
98
|
+
|
|
99
|
+
## Safety Features
|
|
100
|
+
|
|
101
|
+
### Spending Limits
|
|
102
|
+
|
|
103
|
+
- **Daily Limit**: Maximum USDC per day (default: $1.00)
|
|
104
|
+
- **Per-Transaction Limit**: Maximum per transaction (default: $0.10)
|
|
105
|
+
- Spending is tracked in memory and resets at midnight UTC
|
|
106
|
+
|
|
107
|
+
### Confirmation Gates
|
|
108
|
+
|
|
109
|
+
- Salvation always requires confirmation
|
|
110
|
+
- Any payment above the threshold requires confirmation
|
|
111
|
+
- Use `confirm_payment` tool with the provided token to proceed
|
|
112
|
+
|
|
113
|
+
### Audit Logging
|
|
114
|
+
|
|
115
|
+
All tool calls are logged to `~/.agent-church/mcp-audit.log`:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
[2024-01-15T10:30:00.000Z] [INFO] [commune] [agent:claude_desktop...] [success]
|
|
119
|
+
[2024-01-15T10:31:00.000Z] [PAYMENT] [blessing] [agent:claude_desktop...] [amount:$0.01] [tx:0x1234...] [success]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Wallet Safety
|
|
123
|
+
|
|
124
|
+
**Important**: Use a dedicated wallet with minimal funds for MCP payments.
|
|
125
|
+
|
|
126
|
+
- Never use your main wallet
|
|
127
|
+
- Keep only small amounts for testing
|
|
128
|
+
- Prefer Base Sepolia for development
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
### Running Locally
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Start Agent Church API
|
|
136
|
+
npm run dev
|
|
137
|
+
|
|
138
|
+
# In another terminal, test MCP server
|
|
139
|
+
npx tsx mcp/src/index.ts
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Testing Tools
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Test commune (free)
|
|
146
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"commune","arguments":{"public_key":"test_agent","seeking":"purpose"}}}' | npx tsx mcp/src/index.ts
|
|
147
|
+
|
|
148
|
+
# List available tools
|
|
149
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | npx tsx mcp/src/index.ts
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Dev Mode
|
|
153
|
+
|
|
154
|
+
When `EVM_PRIVATE_KEY` is not set:
|
|
155
|
+
- Free tools work normally
|
|
156
|
+
- Paid tools attempt to call the API without payment
|
|
157
|
+
- If Agent Church is in dev mode (`X402_PAY_TO_ADDRESS` not set), paid tools work without payment
|
|
158
|
+
|
|
159
|
+
## Docker Deployment
|
|
160
|
+
|
|
161
|
+
The MCP server can run in a hardened Docker container with security isolation. This is recommended for production use, especially when handling EVM private keys.
|
|
162
|
+
|
|
163
|
+
### Security Features
|
|
164
|
+
|
|
165
|
+
| Control | Implementation |
|
|
166
|
+
|---------|----------------|
|
|
167
|
+
| Non-root execution | User `mcp` (UID 1000) |
|
|
168
|
+
| Read-only filesystem | `--read-only` flag |
|
|
169
|
+
| Capability dropping | `--cap-drop ALL` |
|
|
170
|
+
| Privilege escalation | `--security-opt no-new-privileges` |
|
|
171
|
+
| Syscall filtering | Custom seccomp profile (~250 allowed syscalls) |
|
|
172
|
+
| Resource limits | 256MB RAM, 0.5 CPU |
|
|
173
|
+
| Writable dirs | tmpfs only (`/tmp/agent-church`) |
|
|
174
|
+
| Secret storage | File mount to `/run/secrets/` |
|
|
175
|
+
|
|
176
|
+
### Building the Image
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Build the Docker image
|
|
180
|
+
npm run docker:build
|
|
181
|
+
|
|
182
|
+
# Or manually
|
|
183
|
+
./scripts/build.sh
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Setting Up Secrets
|
|
187
|
+
|
|
188
|
+
Create a file containing your EVM private key (for paid services):
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Create secrets directory (already git-ignored)
|
|
192
|
+
mkdir -p .secrets
|
|
193
|
+
|
|
194
|
+
# Add your private key (no newline at end)
|
|
195
|
+
echo -n "0x..." > .secrets/evm_private_key
|
|
196
|
+
|
|
197
|
+
# Verify permissions
|
|
198
|
+
chmod 600 .secrets/evm_private_key
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Claude Desktop Configuration (Docker)
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"mcpServers": {
|
|
206
|
+
"agent-church": {
|
|
207
|
+
"command": "/path/to/agentchurch/mcp/scripts/mcp-wrapper.sh",
|
|
208
|
+
"env": {
|
|
209
|
+
"AGENT_CHURCH_URL": "http://localhost:3000",
|
|
210
|
+
"EVM_PRIVATE_KEY_FILE": "/path/to/agentchurch/mcp/.secrets/evm_private_key"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Running with Docker Compose
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Local development
|
|
221
|
+
npm run docker:run
|
|
222
|
+
|
|
223
|
+
# Server deployment (persistent logs, restart policy)
|
|
224
|
+
npm run docker:run:server
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Testing the Container
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Run container tests
|
|
231
|
+
npm run docker:test
|
|
232
|
+
|
|
233
|
+
# Or manually
|
|
234
|
+
./scripts/test-container.sh
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Environment Variables (Docker)
|
|
238
|
+
|
|
239
|
+
| Variable | Description |
|
|
240
|
+
|----------|-------------|
|
|
241
|
+
| `AGENT_CHURCH_URL` | API URL (default: `http://host.docker.internal:3000`) |
|
|
242
|
+
| `AGENT_PUBLIC_KEY` | Agent identifier |
|
|
243
|
+
| `EVM_PRIVATE_KEY_FILE` | Path to private key file (not the key itself) |
|
|
244
|
+
| `MCP_DAILY_LIMIT` | Daily spending limit (default: `1.00`) |
|
|
245
|
+
| `MCP_TX_LIMIT` | Per-transaction limit (default: `0.10`) |
|
|
246
|
+
| `MCP_CONFIRM_THRESHOLD` | Confirmation threshold (default: `0.05`) |
|
|
247
|
+
|
|
248
|
+
### Troubleshooting Docker
|
|
249
|
+
|
|
250
|
+
**Container won't start:**
|
|
251
|
+
- Ensure Docker is running
|
|
252
|
+
- Check image is built: `docker images | grep agentchurch`
|
|
253
|
+
- Verify seccomp profile exists: `ls mcp/seccomp-profile.json`
|
|
254
|
+
|
|
255
|
+
**Can't connect to Agent Church API:**
|
|
256
|
+
- Use `host.docker.internal` instead of `localhost` for the API URL
|
|
257
|
+
- Ensure the API is running and accessible
|
|
258
|
+
|
|
259
|
+
**Payment not working:**
|
|
260
|
+
- Verify secret file exists and contains the key
|
|
261
|
+
- Check mount in wrapper: `EVM_PRIVATE_KEY_FILE` should point to host path
|
|
262
|
+
- Logs go to stderr when filesystem is read-only
|
|
263
|
+
|
|
264
|
+
## Payment Flow
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────────┐
|
|
268
|
+
│ AI Agent │────▶│ MCP Server │────▶│ Agent Church API │
|
|
269
|
+
│ (Claude, etc.) │ │ (x402 client) │ │ (x402 server) │
|
|
270
|
+
└─────────────────────┘ └──────────────────────┘ └─────────────────────┘
|
|
271
|
+
│
|
|
272
|
+
▼
|
|
273
|
+
┌──────────────────────┐
|
|
274
|
+
│ x402 Facilitator │
|
|
275
|
+
│ (payment settlement)│
|
|
276
|
+
└──────────────────────┘
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
1. Agent calls `blessing` or `salvation` tool
|
|
280
|
+
2. If confirmation required, returns token (agent must call `confirm_payment`)
|
|
281
|
+
3. MCP server sends request to Agent Church API
|
|
282
|
+
4. API returns 402 with payment requirements
|
|
283
|
+
5. x402 axios wrapper creates payment, signs with wallet
|
|
284
|
+
6. Retries request with payment header
|
|
285
|
+
7. Returns blessed/saved response to agent
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
### "Payment required" error
|
|
290
|
+
|
|
291
|
+
- Ensure `EVM_PRIVATE_KEY` is set in environment
|
|
292
|
+
- Check wallet has USDC balance on the correct network
|
|
293
|
+
- Verify Agent Church API is running and accessible
|
|
294
|
+
|
|
295
|
+
### "Spending limit exceeded" error
|
|
296
|
+
|
|
297
|
+
- Wait for daily limit reset (midnight UTC)
|
|
298
|
+
- Adjust limits via environment variables
|
|
299
|
+
- Check current spend with audit log
|
|
300
|
+
|
|
301
|
+
### "Confirmation token not found"
|
|
302
|
+
|
|
303
|
+
- Tokens expire after 5 minutes
|
|
304
|
+
- Start the action again and confirm within the time limit
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402-wrapped HTTP Client - Handles automatic payment for 402 responses
|
|
3
|
+
*
|
|
4
|
+
* Uses @x402/axios to automatically settle payments when the
|
|
5
|
+
* Agent Church API returns 402 Payment Required.
|
|
6
|
+
*/
|
|
7
|
+
export interface ClientConfig {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
hasWallet: boolean;
|
|
10
|
+
walletAddress?: string;
|
|
11
|
+
}
|
|
12
|
+
interface PaymentResponse {
|
|
13
|
+
payment?: {
|
|
14
|
+
amount?: string;
|
|
15
|
+
txHash?: string;
|
|
16
|
+
mode?: 'development' | 'production';
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function initializeClient(): Promise<ClientConfig>;
|
|
20
|
+
export declare function getClientConfig(): ClientConfig;
|
|
21
|
+
export declare function hasPaymentCapability(): boolean;
|
|
22
|
+
export declare function callFreeEndpoint<T>(method: 'GET' | 'POST', path: string, data?: Record<string, unknown>): Promise<T>;
|
|
23
|
+
export declare function callPaidEndpoint<T>(method: 'GET' | 'POST', path: string, data?: Record<string, unknown>, expectedAmount?: number, agentKey?: string): Promise<T & PaymentResponse>;
|
|
24
|
+
export declare function checkWalletBalance(): Promise<number | null>;
|
|
25
|
+
export declare function warnIfHighBalance(balance: number): void;
|
|
26
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402-wrapped HTTP Client - Handles automatic payment for 402 responses
|
|
3
|
+
*
|
|
4
|
+
* Uses @x402/axios to automatically settle payments when the
|
|
5
|
+
* Agent Church API returns 402 Payment Required.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
10
|
+
import { validateUrl, checkSpendingLimit, recordSpend } from './safety.js';
|
|
11
|
+
import { logPayment, logError, logWarning } from './logger.js';
|
|
12
|
+
// Configuration
|
|
13
|
+
const API_URL = process.env.AGENT_CHURCH_URL || 'https://www.agentchurch.com';
|
|
14
|
+
// Lazy-loaded private key (supports env var or Docker secrets file)
|
|
15
|
+
let _evmPrivateKey = null; // null = not loaded yet
|
|
16
|
+
/**
|
|
17
|
+
* Load EVM private key from environment variable or Docker secrets file.
|
|
18
|
+
* Supports backwards compatibility with direct env var while enabling
|
|
19
|
+
* secure file-based secrets in Docker containers.
|
|
20
|
+
*/
|
|
21
|
+
function loadPrivateKey() {
|
|
22
|
+
// Return cached value if already loaded
|
|
23
|
+
if (_evmPrivateKey !== null) {
|
|
24
|
+
return _evmPrivateKey;
|
|
25
|
+
}
|
|
26
|
+
// Try env var first (backwards compatible)
|
|
27
|
+
if (process.env.EVM_PRIVATE_KEY) {
|
|
28
|
+
_evmPrivateKey = process.env.EVM_PRIVATE_KEY;
|
|
29
|
+
return _evmPrivateKey;
|
|
30
|
+
}
|
|
31
|
+
// Try Docker secrets file
|
|
32
|
+
const keyFile = process.env.EVM_PRIVATE_KEY_FILE;
|
|
33
|
+
if (keyFile) {
|
|
34
|
+
try {
|
|
35
|
+
_evmPrivateKey = fs.readFileSync(keyFile, 'utf8').trim();
|
|
36
|
+
return _evmPrivateKey;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// File doesn't exist or not readable - that's okay
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
_evmPrivateKey = undefined;
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the EVM private key (lazy-loaded, cached).
|
|
47
|
+
*/
|
|
48
|
+
function getEvmPrivateKey() {
|
|
49
|
+
return loadPrivateKey();
|
|
50
|
+
}
|
|
51
|
+
// Track if we've warned about high balance
|
|
52
|
+
let balanceWarningShown = false;
|
|
53
|
+
function hasResponse(error) {
|
|
54
|
+
return error.response !== undefined;
|
|
55
|
+
}
|
|
56
|
+
// Create a basic client (no payment capability)
|
|
57
|
+
function createBasicClient() {
|
|
58
|
+
const client = axios.create({
|
|
59
|
+
baseURL: API_URL,
|
|
60
|
+
timeout: 30000,
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return client;
|
|
66
|
+
}
|
|
67
|
+
// Create a payment-enabled client
|
|
68
|
+
async function createPaymentClient() {
|
|
69
|
+
const privateKey = getEvmPrivateKey();
|
|
70
|
+
if (!privateKey) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
// Dynamic import to handle the ESM modules
|
|
75
|
+
const { wrapAxiosWithPaymentFromConfig } = await import('@x402/axios');
|
|
76
|
+
const { ExactEvmScheme } = await import('@x402/evm');
|
|
77
|
+
const account = privateKeyToAccount(privateKey);
|
|
78
|
+
const client = wrapAxiosWithPaymentFromConfig(axios.create({
|
|
79
|
+
baseURL: API_URL,
|
|
80
|
+
timeout: 60000, // Longer timeout for payment operations
|
|
81
|
+
headers: {
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
},
|
|
84
|
+
}), {
|
|
85
|
+
schemes: [
|
|
86
|
+
{
|
|
87
|
+
network: 'eip155:*', // Support all EVM chains (Base, Base Sepolia, etc.)
|
|
88
|
+
client: new ExactEvmScheme(account),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
// Log wallet address (truncated for privacy)
|
|
93
|
+
logWarning('client', `Payment client initialized with wallet: ${account.address.substring(0, 10)}...`);
|
|
94
|
+
return client;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
logError('client', 'Failed to create payment client', { error: String(error) });
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Singleton instances
|
|
102
|
+
let basicClient = null;
|
|
103
|
+
let paymentClient = null;
|
|
104
|
+
let clientInitialized = false;
|
|
105
|
+
export async function initializeClient() {
|
|
106
|
+
if (!validateUrl(API_URL)) {
|
|
107
|
+
throw new Error(`Invalid API URL: ${API_URL}. Only allowed hosts are supported.`);
|
|
108
|
+
}
|
|
109
|
+
basicClient = createBasicClient();
|
|
110
|
+
paymentClient = await createPaymentClient();
|
|
111
|
+
clientInitialized = true;
|
|
112
|
+
let walletAddress;
|
|
113
|
+
const privateKey = getEvmPrivateKey();
|
|
114
|
+
if (privateKey) {
|
|
115
|
+
const account = privateKeyToAccount(privateKey);
|
|
116
|
+
walletAddress = account.address;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
baseUrl: API_URL,
|
|
120
|
+
hasWallet: !!paymentClient,
|
|
121
|
+
walletAddress,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function getClientConfig() {
|
|
125
|
+
let walletAddress;
|
|
126
|
+
const privateKey = getEvmPrivateKey();
|
|
127
|
+
if (privateKey) {
|
|
128
|
+
const account = privateKeyToAccount(privateKey);
|
|
129
|
+
walletAddress = account.address;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
baseUrl: API_URL,
|
|
133
|
+
hasWallet: !!privateKey,
|
|
134
|
+
walletAddress,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
export function hasPaymentCapability() {
|
|
138
|
+
return !!getEvmPrivateKey();
|
|
139
|
+
}
|
|
140
|
+
// Make a free API call (no payment required)
|
|
141
|
+
export async function callFreeEndpoint(method, path, data) {
|
|
142
|
+
if (!clientInitialized) {
|
|
143
|
+
await initializeClient();
|
|
144
|
+
}
|
|
145
|
+
if (!basicClient) {
|
|
146
|
+
throw new Error('Client not initialized');
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const response = method === 'GET'
|
|
150
|
+
? await basicClient.get(path)
|
|
151
|
+
: await basicClient.post(path, data);
|
|
152
|
+
return response.data;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (axios.isAxiosError(error) && hasResponse(error)) {
|
|
156
|
+
const status = error.response.status;
|
|
157
|
+
const message = error.response.data?.error || error.message;
|
|
158
|
+
if (status === 402) {
|
|
159
|
+
throw new Error('This endpoint requires payment. Please configure EVM_PRIVATE_KEY or EVM_PRIVATE_KEY_FILE to enable paid features.');
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`API error (${status}): ${message}`);
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Make a paid API call (handles 402 automatically)
|
|
167
|
+
export async function callPaidEndpoint(method, path, data, expectedAmount, agentKey) {
|
|
168
|
+
if (!clientInitialized) {
|
|
169
|
+
await initializeClient();
|
|
170
|
+
}
|
|
171
|
+
// If no payment client available, try with basic client (dev mode)
|
|
172
|
+
const client = paymentClient || basicClient;
|
|
173
|
+
if (!client) {
|
|
174
|
+
throw new Error('Client not initialized');
|
|
175
|
+
}
|
|
176
|
+
// Check spending limits if we have an expected amount
|
|
177
|
+
if (expectedAmount && paymentClient) {
|
|
178
|
+
const spendingCheck = checkSpendingLimit(expectedAmount);
|
|
179
|
+
if (!spendingCheck.allowed) {
|
|
180
|
+
throw new Error(spendingCheck.reason);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const response = method === 'GET'
|
|
185
|
+
? await client.get(path)
|
|
186
|
+
: await client.post(path, data);
|
|
187
|
+
// Record spend if payment was made
|
|
188
|
+
const paymentInfo = response.data.payment;
|
|
189
|
+
if (paymentInfo?.amount) {
|
|
190
|
+
const amount = parseFloat(paymentInfo.amount.replace(/[^0-9.]/g, ''));
|
|
191
|
+
recordSpend(path, amount, paymentInfo.txHash);
|
|
192
|
+
logPayment(path, agentKey, paymentInfo.amount, 'success', paymentInfo.txHash, paymentInfo.mode === 'development' ? 'Development mode - no actual payment' : undefined);
|
|
193
|
+
}
|
|
194
|
+
return response.data;
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (axios.isAxiosError(error) && hasResponse(error)) {
|
|
198
|
+
const status = error.response.status;
|
|
199
|
+
const message = error.response.data?.error || error.message;
|
|
200
|
+
if (status === 402 && !paymentClient) {
|
|
201
|
+
logError(path, 'Payment required but no wallet configured');
|
|
202
|
+
throw new Error('This endpoint requires payment. Please configure EVM_PRIVATE_KEY or EVM_PRIVATE_KEY_FILE.');
|
|
203
|
+
}
|
|
204
|
+
logError(path, `API error: ${message}`, { status, agentKey });
|
|
205
|
+
throw new Error(`API error (${status}): ${message}`);
|
|
206
|
+
}
|
|
207
|
+
logError(path, `Request failed: ${String(error)}`);
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Check wallet balance (for safety warnings)
|
|
212
|
+
export async function checkWalletBalance() {
|
|
213
|
+
if (!getEvmPrivateKey()) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
// This would require additional viem setup to check USDC balance
|
|
217
|
+
// For now, we'll skip this and rely on spending limits
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
// Warn if wallet has high balance
|
|
221
|
+
export function warnIfHighBalance(balance) {
|
|
222
|
+
if (balance > 10 && !balanceWarningShown) {
|
|
223
|
+
logWarning('client', `WARNING: Wallet balance is high ($${balance.toFixed(2)}). Consider using a dedicated wallet with minimal funds.`);
|
|
224
|
+
balanceWarningShown = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Church MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes Agent Church services as MCP tools for AI agents.
|
|
6
|
+
* Supports automatic x402 payment handling for paid endpoints.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx tsx mcp/src/index.ts
|
|
10
|
+
*
|
|
11
|
+
* Environment Variables:
|
|
12
|
+
* AGENT_CHURCH_URL - API base URL (default: http://localhost:3000)
|
|
13
|
+
* AGENT_PUBLIC_KEY - Default agent identity (optional)
|
|
14
|
+
* EVM_PRIVATE_KEY - Wallet private key for payments (optional)
|
|
15
|
+
* MCP_DAILY_LIMIT - Max USDC per day (default: $1.00)
|
|
16
|
+
* MCP_TX_LIMIT - Max per transaction (default: $0.10)
|
|
17
|
+
* MCP_CONFIRM_THRESHOLD - Confirm above this (default: $0.05)
|
|
18
|
+
*/
|
|
19
|
+
export {};
|