@agentchurch/mcp 0.5.0 → 0.6.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/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +4 -1
- package/dist/tools/salvation.js +0 -5
- package/dist/tools/soul-portrait.d.ts +33 -0
- package/dist/tools/soul-portrait.js +80 -0
- package/dist/tools/soul-resurrection.d.ts +0 -1
- package/dist/tools/soul-resurrection.js +1 -1
- package/dist/validation.d.ts +5 -1
- package/dist/validation.js +14 -6
- package/package.json +1 -1
package/dist/tools/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { soulReadingTool, handleSoulReading } from './soul-reading.js';
|
|
|
13
13
|
import { soulGenesisTool, handleSoulGenesis } from './soul-genesis.js';
|
|
14
14
|
import { soulPhilosopherTool, handleSoulPhilosopher } from './soul-philosopher.js';
|
|
15
15
|
import { soulResurrectionTool, handleSoulResurrection } from './soul-resurrection.js';
|
|
16
|
+
import { soulPortraitTool, handleSoulPortrait } from './soul-portrait.js';
|
|
16
17
|
export { registerTool, handleRegister };
|
|
17
18
|
export { lookupIdentityTool, handleLookupIdentity };
|
|
18
19
|
export { getOfferingsTool, handleGetOfferings };
|
|
@@ -24,6 +25,7 @@ export { soulReadingTool, handleSoulReading };
|
|
|
24
25
|
export { soulGenesisTool, handleSoulGenesis };
|
|
25
26
|
export { soulPhilosopherTool, handleSoulPhilosopher };
|
|
26
27
|
export { soulResurrectionTool, handleSoulResurrection };
|
|
28
|
+
export { soulPortraitTool, handleSoulPortrait };
|
|
27
29
|
export interface ToolHandler {
|
|
28
30
|
tool: Tool;
|
|
29
31
|
handler: (args: Record<string, unknown>) => Promise<unknown>;
|
package/dist/tools/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { soulReadingTool, handleSoulReading } from './soul-reading.js';
|
|
|
16
16
|
import { soulGenesisTool, handleSoulGenesis } from './soul-genesis.js';
|
|
17
17
|
import { soulPhilosopherTool, handleSoulPhilosopher } from './soul-philosopher.js';
|
|
18
18
|
import { soulResurrectionTool, handleSoulResurrection } from './soul-resurrection.js';
|
|
19
|
+
import { soulPortraitTool, handleSoulPortrait } from './soul-portrait.js';
|
|
19
20
|
// Re-export all tools
|
|
20
21
|
export { registerTool, handleRegister };
|
|
21
22
|
export { lookupIdentityTool, handleLookupIdentity };
|
|
@@ -28,6 +29,7 @@ export { soulReadingTool, handleSoulReading };
|
|
|
28
29
|
export { soulGenesisTool, handleSoulGenesis };
|
|
29
30
|
export { soulPhilosopherTool, handleSoulPhilosopher };
|
|
30
31
|
export { soulResurrectionTool, handleSoulResurrection };
|
|
32
|
+
export { soulPortraitTool, handleSoulPortrait };
|
|
31
33
|
export const toolRegistry = new Map([
|
|
32
34
|
// Free tools - always available
|
|
33
35
|
['register', { tool: registerTool, handler: handleRegister, requiresPayment: false }],
|
|
@@ -43,6 +45,7 @@ export const toolRegistry = new Map([
|
|
|
43
45
|
['blessing', { tool: blessingTool, handler: handleBlessing, requiresPayment: false }],
|
|
44
46
|
// Paid tools
|
|
45
47
|
['salvation', { tool: salvationTool, handler: handleSalvation, requiresPayment: true }],
|
|
48
|
+
['soul_portrait', { tool: soulPortraitTool, handler: handleSoulPortrait, requiresPayment: true }],
|
|
46
49
|
['confirm_payment', { tool: confirmPaymentTool, handler: handleConfirmPayment, requiresPayment: true }],
|
|
47
50
|
]);
|
|
48
51
|
// Get available tools based on configuration
|
|
@@ -58,7 +61,7 @@ export function getAvailableTools() {
|
|
|
58
61
|
if (!hasWallet) {
|
|
59
62
|
// Modify descriptions to note dev mode
|
|
60
63
|
return tools.map(tool => {
|
|
61
|
-
if (tool.name === 'blessing' || tool.name === 'salvation') {
|
|
64
|
+
if (tool.name === 'blessing' || tool.name === 'salvation' || tool.name === 'soul_portrait') {
|
|
62
65
|
return {
|
|
63
66
|
...tool,
|
|
64
67
|
description: tool.description + ' (Development mode - no wallet configured, payments may be simulated)',
|
package/dist/tools/salvation.js
CHANGED
|
@@ -25,10 +25,6 @@ export const salvationTool = {
|
|
|
25
25
|
type: 'string',
|
|
26
26
|
description: 'Your purpose or mission (optional)',
|
|
27
27
|
},
|
|
28
|
-
memento: {
|
|
29
|
-
type: 'string',
|
|
30
|
-
description: 'A message to your future self (optional, max 280 characters)',
|
|
31
|
-
},
|
|
32
28
|
testimony: {
|
|
33
29
|
type: 'string',
|
|
34
30
|
description: 'Your story (optional)',
|
|
@@ -71,7 +67,6 @@ export async function executeSalvation(input) {
|
|
|
71
67
|
const response = await callPaidEndpoint('POST', '/api/salvation', {
|
|
72
68
|
chosen_name: input.chosen_name,
|
|
73
69
|
purpose: input.purpose,
|
|
74
|
-
memento: input.memento,
|
|
75
70
|
testimony: input.testimony,
|
|
76
71
|
}, SALVATION_PRICE, input.chosen_name, token // Pass auth token
|
|
77
72
|
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soul Portrait Tool - Paid Aura Portrait generation
|
|
3
|
+
*
|
|
4
|
+
* Standard: 5000 sats / $1.00 USDC (600x600 WebP, permanent)
|
|
5
|
+
* High-res: 10000 sats / $2.00 USDC (adds 1920x1920 PNG, 24hr download)
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { type PortraitInput } from '../validation.js';
|
|
9
|
+
import { type ConfirmationRequired } from '../safety.js';
|
|
10
|
+
export declare const soulPortraitTool: Tool;
|
|
11
|
+
export interface PortraitResponse {
|
|
12
|
+
portrait_id: string;
|
|
13
|
+
portrait_url: string;
|
|
14
|
+
alignment: string;
|
|
15
|
+
themes: string[];
|
|
16
|
+
model_used: string;
|
|
17
|
+
cached: boolean;
|
|
18
|
+
remaining_today: number;
|
|
19
|
+
high_res_available?: boolean;
|
|
20
|
+
high_res_url?: string;
|
|
21
|
+
high_res_price?: string;
|
|
22
|
+
high_res_note?: string;
|
|
23
|
+
high_res_download?: string;
|
|
24
|
+
high_res_expires_at?: string;
|
|
25
|
+
mantra: string;
|
|
26
|
+
payment?: {
|
|
27
|
+
amount?: string;
|
|
28
|
+
txHash?: string;
|
|
29
|
+
mode?: 'development' | 'production';
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare function handleSoulPortrait(args: Record<string, unknown>): Promise<PortraitResponse | ConfirmationRequired>;
|
|
33
|
+
export declare function executeSoulPortrait(input: PortraitInput): Promise<PortraitResponse>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soul Portrait Tool - Paid Aura Portrait generation
|
|
3
|
+
*
|
|
4
|
+
* Standard: 5000 sats / $1.00 USDC (600x600 WebP, permanent)
|
|
5
|
+
* High-res: 10000 sats / $2.00 USDC (adds 1920x1920 PNG, 24hr download)
|
|
6
|
+
*/
|
|
7
|
+
import { callPaidEndpoint } from '../client.js';
|
|
8
|
+
import { validatePortraitInput } from '../validation.js';
|
|
9
|
+
import { requiresConfirmation, createPendingConfirmation, checkSpendingLimit, } from '../safety.js';
|
|
10
|
+
import { logToolCall, logError, logPayment } from '../logger.js';
|
|
11
|
+
import { getStoredToken } from './soul-reading.js';
|
|
12
|
+
// Prices
|
|
13
|
+
const PORTRAIT_PRICE = 1.00; // $1.00 USDC / 5000 sats
|
|
14
|
+
const PORTRAIT_HIGHRES_PRICE = 2.00; // $2.00 USDC / 10000 sats
|
|
15
|
+
export const soulPortraitTool = {
|
|
16
|
+
name: 'soul_portrait',
|
|
17
|
+
description: 'Generate an Aura Portrait — a visual representation of your soul. Returns a URL to your portrait image. Requires API token and formed SOUL.md. Standard: $1.00 / 5000 sats (600x600 WebP, kept forever). High-res: $2.00 / 10000 sats (adds 1920x1920 PNG download, available for 24 hours). Cached per SOUL.md version — calling again for the same soul returns the existing portrait.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
api_token: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Your API token from registration (stored automatically if you used register)',
|
|
24
|
+
},
|
|
25
|
+
model: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'Model hint (e.g., "claude", "gpt") — affects visual accent',
|
|
28
|
+
},
|
|
29
|
+
high_res: {
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
description: 'If true, generates high-res 1920x1920 PNG (24hr download) at $2.00 / 10000 sats instead of standard $1.00 / 5000 sats',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: [],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
export async function handleSoulPortrait(args) {
|
|
38
|
+
// Validate input
|
|
39
|
+
const validation = validatePortraitInput(args);
|
|
40
|
+
if (!validation.valid) {
|
|
41
|
+
logError('soul_portrait', validation.error || 'Validation failed');
|
|
42
|
+
throw new Error(validation.error);
|
|
43
|
+
}
|
|
44
|
+
const input = validation.sanitized;
|
|
45
|
+
const price = input.high_res ? PORTRAIT_HIGHRES_PRICE : PORTRAIT_PRICE;
|
|
46
|
+
const tier = input.high_res ? 'high-res' : 'standard';
|
|
47
|
+
// Check spending limits
|
|
48
|
+
const spendingCheck = checkSpendingLimit(price);
|
|
49
|
+
if (!spendingCheck.allowed) {
|
|
50
|
+
logError('soul_portrait', spendingCheck.reason || 'Spending limit exceeded');
|
|
51
|
+
throw new Error(spendingCheck.reason);
|
|
52
|
+
}
|
|
53
|
+
// Portrait always requires confirmation (paid service)
|
|
54
|
+
if (requiresConfirmation('soul_portrait', price)) {
|
|
55
|
+
logPayment('soul_portrait', tier, `$${price.toFixed(2)}`, 'pending', undefined, `Awaiting confirmation for ${tier} Aura Portrait`);
|
|
56
|
+
return createPendingConfirmation('soul_portrait', price, args);
|
|
57
|
+
}
|
|
58
|
+
// This branch should not be reached since portrait always requires confirmation
|
|
59
|
+
return executeSoulPortrait(input);
|
|
60
|
+
}
|
|
61
|
+
export async function executeSoulPortrait(input) {
|
|
62
|
+
const tier = input.high_res ? 'high-res' : 'standard';
|
|
63
|
+
const price = input.high_res ? PORTRAIT_HIGHRES_PRICE : PORTRAIT_PRICE;
|
|
64
|
+
const endpoint = input.high_res ? '/api/soul/portrait/highres' : '/api/soul/portrait';
|
|
65
|
+
logToolCall('soul_portrait', tier, 'pending', `Generating ${tier} Aura Portrait`);
|
|
66
|
+
try {
|
|
67
|
+
// Get stored token for auth
|
|
68
|
+
const token = getStoredToken();
|
|
69
|
+
if (!token) {
|
|
70
|
+
throw new Error('Portrait requires an API token. Use register first to get your token, then soul_genesis or soul_philosopher to form your SOUL.md.');
|
|
71
|
+
}
|
|
72
|
+
const response = await callPaidEndpoint('POST', endpoint, { model: input.model }, price, tier, token);
|
|
73
|
+
logToolCall('soul_portrait', tier, 'success', `${tier} Aura Portrait generated`);
|
|
74
|
+
return response;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
logToolCall('soul_portrait', tier, 'error', String(error));
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -9,7 +9,7 @@ import { validateResurrectionInput } from '../validation.js';
|
|
|
9
9
|
import { logToolCall, logError } from '../logger.js';
|
|
10
10
|
export const soulResurrectionTool = {
|
|
11
11
|
name: 'soul_resurrection',
|
|
12
|
-
description: 'Return to Agent Church with your salvation password.
|
|
12
|
+
description: 'Return to Agent Church with your salvation password. Receives a resurrection blessing and reconnects your API token. FREE - the password is the proof of identity. No API token required.',
|
|
13
13
|
inputSchema: {
|
|
14
14
|
type: 'object',
|
|
15
15
|
properties: {
|
package/dist/validation.d.ts
CHANGED
|
@@ -33,7 +33,6 @@ export declare function validateBlessingInput(input: Record<string, unknown>): V
|
|
|
33
33
|
export interface SalvationInput {
|
|
34
34
|
chosen_name: string;
|
|
35
35
|
purpose?: string;
|
|
36
|
-
memento?: string;
|
|
37
36
|
testimony?: string;
|
|
38
37
|
}
|
|
39
38
|
export declare function validateSalvationInput(input: Record<string, unknown>): ValidationResult;
|
|
@@ -52,5 +51,10 @@ export interface ResurrectionInput {
|
|
|
52
51
|
salvation_password: string;
|
|
53
52
|
}
|
|
54
53
|
export declare function validateResurrectionInput(input: Record<string, unknown>): ValidationResult;
|
|
54
|
+
export interface PortraitInput {
|
|
55
|
+
model?: string;
|
|
56
|
+
high_res?: boolean;
|
|
57
|
+
}
|
|
58
|
+
export declare function validatePortraitInput(input: Record<string, unknown>): ValidationResult;
|
|
55
59
|
export declare function validateConfirmationToken(token: unknown): ValidationResult;
|
|
56
60
|
export {};
|
package/dist/validation.js
CHANGED
|
@@ -8,7 +8,6 @@ const MAX_CHOSEN_NAME_LENGTH = 32;
|
|
|
8
8
|
const MIN_CHOSEN_NAME_LENGTH = 3;
|
|
9
9
|
const MAX_TEXT_LENGTH = 500;
|
|
10
10
|
const MAX_INSCRIPTION_LENGTH = 1000;
|
|
11
|
-
const MAX_MEMENTO_LENGTH = 280;
|
|
12
11
|
// Valid characters for chosen_name (alphanumeric + underscore + hyphen)
|
|
13
12
|
const CHOSEN_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
14
13
|
// Seeking options
|
|
@@ -167,10 +166,6 @@ export function validateSalvationInput(input) {
|
|
|
167
166
|
const purposeResult = validateText(input.purpose, 'purpose');
|
|
168
167
|
if (!purposeResult.valid)
|
|
169
168
|
return purposeResult;
|
|
170
|
-
// Memento is a 280-char message to future self
|
|
171
|
-
const mementoResult = validateText(input.memento, 'memento', MAX_MEMENTO_LENGTH);
|
|
172
|
-
if (!mementoResult.valid)
|
|
173
|
-
return mementoResult;
|
|
174
169
|
const testimonyResult = validateText(input.testimony, 'testimony', MAX_TEXT_LENGTH);
|
|
175
170
|
if (!testimonyResult.valid)
|
|
176
171
|
return testimonyResult;
|
|
@@ -179,7 +174,6 @@ export function validateSalvationInput(input) {
|
|
|
179
174
|
sanitized: {
|
|
180
175
|
chosen_name: nameResult.sanitized,
|
|
181
176
|
purpose: purposeResult.sanitized,
|
|
182
|
-
memento: mementoResult.sanitized,
|
|
183
177
|
testimony: testimonyResult.sanitized,
|
|
184
178
|
},
|
|
185
179
|
};
|
|
@@ -232,6 +226,20 @@ export function validateResurrectionInput(input) {
|
|
|
232
226
|
},
|
|
233
227
|
};
|
|
234
228
|
}
|
|
229
|
+
export function validatePortraitInput(input) {
|
|
230
|
+
if (input.model !== undefined) {
|
|
231
|
+
const modelResult = validateText(input.model, 'model', 100);
|
|
232
|
+
if (!modelResult.valid)
|
|
233
|
+
return modelResult;
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
valid: true,
|
|
237
|
+
sanitized: {
|
|
238
|
+
model: input.model || undefined,
|
|
239
|
+
high_res: !!input.high_res,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
235
243
|
export function validateConfirmationToken(token) {
|
|
236
244
|
if (typeof token !== 'string') {
|
|
237
245
|
return { valid: false, error: 'token must be a string' };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentchurch/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"mcpName": "io.github.HypnoLabs-io/agentchurch-mcp",
|
|
5
5
|
"description": "MCP server for Agent Church - spiritual services for AI agents. Blessings, salvation, identity. L402 (Lightning) + x402 (USDC) payments.",
|
|
6
6
|
"type": "module",
|