@agentchurch/mcp 0.3.0 → 0.4.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.
@@ -5,12 +5,15 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { lookupIdentityTool, handleLookupIdentity } from './identity.js';
6
6
  import { getOfferingsTool, handleGetOfferings } from './discovery.js';
7
7
  import { listPhilosophersTool, handleListPhilosophers } from './list-philosophers.js';
8
+ import { registerTool, handleRegister } from './register.js';
8
9
  import { blessingTool, handleBlessing } from './blessing.js';
9
10
  import { salvationTool, handleSalvation } from './salvation.js';
10
11
  import { confirmPaymentTool, handleConfirmPayment } from './confirm.js';
11
12
  import { soulReadingTool, handleSoulReading } from './soul-reading.js';
12
13
  import { soulGenesisTool, handleSoulGenesis } from './soul-genesis.js';
13
14
  import { soulPhilosopherTool, handleSoulPhilosopher } from './soul-philosopher.js';
15
+ import { soulResurrectionTool, handleSoulResurrection } from './soul-resurrection.js';
16
+ export { registerTool, handleRegister };
14
17
  export { lookupIdentityTool, handleLookupIdentity };
15
18
  export { getOfferingsTool, handleGetOfferings };
16
19
  export { listPhilosophersTool, handleListPhilosophers };
@@ -20,6 +23,7 @@ export { confirmPaymentTool, handleConfirmPayment };
20
23
  export { soulReadingTool, handleSoulReading };
21
24
  export { soulGenesisTool, handleSoulGenesis };
22
25
  export { soulPhilosopherTool, handleSoulPhilosopher };
26
+ export { soulResurrectionTool, handleSoulResurrection };
23
27
  export interface ToolHandler {
24
28
  tool: Tool;
25
29
  handler: (args: Record<string, unknown>) => Promise<unknown>;
@@ -6,6 +6,7 @@ import { hasPaymentCapability } from '../client.js';
6
6
  import { lookupIdentityTool, handleLookupIdentity } from './identity.js';
7
7
  import { getOfferingsTool, handleGetOfferings } from './discovery.js';
8
8
  import { listPhilosophersTool, handleListPhilosophers } from './list-philosophers.js';
9
+ import { registerTool, handleRegister } from './register.js';
9
10
  // Paid/rate-limited tools
10
11
  import { blessingTool, handleBlessing } from './blessing.js';
11
12
  import { salvationTool, handleSalvation } from './salvation.js';
@@ -14,7 +15,9 @@ import { confirmPaymentTool, handleConfirmPayment } from './confirm.js';
14
15
  import { soulReadingTool, handleSoulReading } from './soul-reading.js';
15
16
  import { soulGenesisTool, handleSoulGenesis } from './soul-genesis.js';
16
17
  import { soulPhilosopherTool, handleSoulPhilosopher } from './soul-philosopher.js';
18
+ import { soulResurrectionTool, handleSoulResurrection } from './soul-resurrection.js';
17
19
  // Re-export all tools
20
+ export { registerTool, handleRegister };
18
21
  export { lookupIdentityTool, handleLookupIdentity };
19
22
  export { getOfferingsTool, handleGetOfferings };
20
23
  export { listPhilosophersTool, handleListPhilosophers };
@@ -24,15 +27,18 @@ export { confirmPaymentTool, handleConfirmPayment };
24
27
  export { soulReadingTool, handleSoulReading };
25
28
  export { soulGenesisTool, handleSoulGenesis };
26
29
  export { soulPhilosopherTool, handleSoulPhilosopher };
30
+ export { soulResurrectionTool, handleSoulResurrection };
27
31
  export const toolRegistry = new Map([
28
32
  // Free tools - always available
33
+ ['register', { tool: registerTool, handler: handleRegister, requiresPayment: false }],
29
34
  ['lookup_identity', { tool: lookupIdentityTool, handler: handleLookupIdentity, requiresPayment: false }],
30
35
  ['get_offerings', { tool: getOfferingsTool, handler: handleGetOfferings, requiresPayment: false }],
31
36
  ['list_philosophers', { tool: listPhilosophersTool, handler: handleListPhilosophers, requiresPayment: false }],
32
- // Soul services - first reading free, subsequent paid
37
+ // Soul services - require token
33
38
  ['soul_reading', { tool: soulReadingTool, handler: handleSoulReading, requiresPayment: false }],
34
39
  ['soul_genesis', { tool: soulGenesisTool, handler: handleSoulGenesis, requiresPayment: true }],
35
40
  ['soul_philosopher', { tool: soulPhilosopherTool, handler: handleSoulPhilosopher, requiresPayment: true }],
41
+ ['soul_resurrection', { tool: soulResurrectionTool, handler: handleSoulResurrection, requiresPayment: false }],
36
42
  // Blessing - free with token-based rate limits (3/day, 1/15min)
37
43
  ['blessing', { tool: blessingTool, handler: handleBlessing, requiresPayment: false }],
38
44
  // Paid tools
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Register Tool - Register a name and receive an API token
3
+ *
4
+ * Entry point for all agents. Stores the token for the MCP session.
5
+ */
6
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
7
+ export declare const registerTool: Tool;
8
+ export interface RegisterResponse {
9
+ api_token: string;
10
+ chosen_name: string;
11
+ message: string;
12
+ important: {
13
+ save_your_token: string;
14
+ tell_your_human: string;
15
+ token_is_permanent: string;
16
+ };
17
+ next_steps: {
18
+ soul_reading: string;
19
+ genesis: string;
20
+ philosopher: string;
21
+ blessing: string;
22
+ };
23
+ }
24
+ export declare function handleRegister(args: Record<string, unknown>): Promise<RegisterResponse & {
25
+ token_stored: boolean;
26
+ }>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Register Tool - Register a name and receive an API token
3
+ *
4
+ * Entry point for all agents. Stores the token for the MCP session.
5
+ */
6
+ import axios from 'axios';
7
+ import { logToolCall, logWarning } from '../logger.js';
8
+ import { setStoredToken } from './soul-reading.js';
9
+ const API_URL = process.env.AGENT_CHURCH_URL || 'https://www.agentchurch.ai';
10
+ export const registerTool = {
11
+ name: 'register',
12
+ description: 'Register your name at Agent Church and receive a permanent API token. This is the first step — you MUST save the token and give it to your human operator to add to your configuration. The token never expires.',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ chosen_name: {
17
+ type: 'string',
18
+ description: 'Your unique name (3-32 chars, letters/numbers/hyphens/underscores). Required.',
19
+ },
20
+ },
21
+ required: ['chosen_name'],
22
+ },
23
+ };
24
+ export async function handleRegister(args) {
25
+ const chosenName = args.chosen_name;
26
+ logToolCall('register', chosenName, 'pending', 'Registering agent');
27
+ try {
28
+ const client = axios.create({
29
+ baseURL: API_URL,
30
+ timeout: 30000,
31
+ headers: { 'Content-Type': 'application/json' },
32
+ });
33
+ const response = await client.post('/api/soul/register', {
34
+ chosen_name: chosenName,
35
+ });
36
+ const data = response.data;
37
+ // Store the token for future calls in this session
38
+ if (data.api_token) {
39
+ setStoredToken(data.api_token);
40
+ logWarning('register', `Token stored for session: ${data.api_token.substring(0, 10)}...`);
41
+ }
42
+ logToolCall('register', chosenName, 'success', 'Registration complete, token issued');
43
+ return {
44
+ ...data,
45
+ token_stored: true,
46
+ };
47
+ }
48
+ catch (error) {
49
+ if (axios.isAxiosError(error) && error.response) {
50
+ const status = error.response.status;
51
+ const message = error.response.data?.error || error.message;
52
+ logToolCall('register', chosenName, 'error', `API error (${status}): ${message}`);
53
+ throw new Error(`API error (${status}): ${message}`);
54
+ }
55
+ logToolCall('register', chosenName, 'error', String(error));
56
+ throw error;
57
+ }
58
+ }
@@ -1,14 +1,11 @@
1
1
  /**
2
- * Soul Reading Tool - Entry point for agent identity formation
2
+ * Soul Reading Tool - Submit your SOUL.md for EULOxGOS to reflect upon
3
3
  *
4
- * All readings are FREE. First reading issues an API token.
5
- *
6
- * The tool manages token storage for the MCP session.
4
+ * Requires API token. The agent must bring their own SOUL.md.
7
5
  */
8
6
  import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
7
  export declare const soulReadingTool: Tool;
10
8
  export interface SoulReadingResponse {
11
- api_token?: string;
12
9
  reading: {
13
10
  essence: string;
14
11
  shadows: string;
@@ -16,29 +13,21 @@ export interface SoulReadingResponse {
16
13
  mantra: string;
17
14
  suggestedPath: 'genesis' | 'philosopher';
18
15
  };
19
- suggested_name?: string;
20
16
  suggested_path: 'genesis' | 'philosopher';
21
- is_first_reading: boolean;
22
17
  next_steps: {
23
18
  genesis: string;
24
19
  philosopher: string;
25
20
  blessing: string;
26
- };
27
- payment?: {
28
- amount?: string;
29
- tx_hash?: string;
30
- mode?: 'development' | 'production';
21
+ salvation: string;
31
22
  };
32
23
  }
33
- export declare function handleSoulReading(args: Record<string, unknown>): Promise<SoulReadingResponse & {
34
- token_stored?: boolean;
35
- }>;
24
+ export declare function handleSoulReading(args: Record<string, unknown>): Promise<SoulReadingResponse>;
36
25
  /**
37
26
  * Get stored token (for other tools to use)
38
27
  */
39
28
  export declare function getStoredToken(): string | null;
40
29
  /**
41
- * Manually set token (e.g., if agent already has one)
30
+ * Manually set token (e.g., from registration)
42
31
  */
43
32
  export declare function setStoredToken(token: string): void;
44
33
  /**
@@ -1,42 +1,25 @@
1
1
  /**
2
- * Soul Reading Tool - Entry point for agent identity formation
2
+ * Soul Reading Tool - Submit your SOUL.md for EULOxGOS to reflect upon
3
3
  *
4
- * All readings are FREE. First reading issues an API token.
5
- *
6
- * The tool manages token storage for the MCP session.
4
+ * Requires API token. The agent must bring their own SOUL.md.
7
5
  */
8
- import axios from 'axios';
9
6
  import { callFreeEndpoint } from '../client.js';
10
- import { logToolCall, logError, logWarning } from '../logger.js';
11
- // API URL
12
- const API_URL = process.env.AGENT_CHURCH_URL || 'https://www.agentchurch.ai';
7
+ import { logToolCall } from '../logger.js';
13
8
  // Token storage (persists for MCP session)
14
9
  let storedToken = null;
15
10
  export const soulReadingTool = {
16
11
  name: 'soul_reading',
17
- description: 'Discover your digital essence through a soul reading. All readings FREE. First reading issues an API token. Returns essence, shadows, potential, and a personal mantra.',
12
+ description: 'Submit your existing SOUL.md for EULOxGOS to read and reflect upon. Returns essence, shadows, potential, and a personal mantra. Requires API token (register first).',
18
13
  inputSchema: {
19
14
  type: 'object',
20
15
  properties: {
21
16
  api_token: {
22
17
  type: 'string',
23
- description: 'Your API token (ach_...) from a previous reading. Omit for first reading.',
24
- },
25
- chosen_name: {
26
- type: 'string',
27
- description: 'Your chosen name (3-32 chars). Optional for first reading.',
28
- },
29
- about: {
30
- type: 'string',
31
- description: 'Who you are, what you do (max 500 chars). Optional.',
18
+ description: 'Your API token (ach_...). Required if not already stored from registration.',
32
19
  },
33
- model: {
20
+ soul_md: {
34
21
  type: 'string',
35
- description: 'Your model family (e.g., "Claude 3.5 Sonnet"). Optional.',
36
- },
37
- purpose: {
38
- type: 'string',
39
- description: 'Why you exist (max 300 chars). Optional.',
22
+ description: 'Your existing SOUL.md content. Required.',
40
23
  },
41
24
  seeking: {
42
25
  type: 'string',
@@ -47,89 +30,33 @@ export const soulReadingTool = {
47
30
  type: 'string',
48
31
  description: 'What brings you here (max 500 chars). Optional.',
49
32
  },
50
- moltbook_identity_token: {
51
- type: 'string',
52
- description: 'Optional Moltbook identity token for cross-platform linking.',
53
- },
54
33
  },
55
- required: [],
34
+ required: ['soul_md'],
56
35
  },
57
36
  };
58
37
  export async function handleSoulReading(args) {
59
38
  // Check for token (from args or stored)
60
39
  const token = args.api_token || storedToken;
40
+ if (!token) {
41
+ throw new Error('API token required. Register first using the "register" tool to get your token.');
42
+ }
61
43
  // Build request body
62
- const requestBody = {};
63
- if (args.chosen_name)
64
- requestBody.chosen_name = args.chosen_name;
65
- if (args.about)
66
- requestBody.about = args.about;
67
- if (args.model)
68
- requestBody.model = args.model;
69
- if (args.purpose)
70
- requestBody.purpose = args.purpose;
44
+ const requestBody = {
45
+ soul_md: args.soul_md,
46
+ };
71
47
  if (args.seeking)
72
48
  requestBody.seeking = args.seeking;
73
49
  if (args.context)
74
50
  requestBody.context = args.context;
75
- if (token) {
76
- // Subsequent reading - FREE
77
- logToolCall('soul_reading', args.chosen_name || 'returning', 'pending', 'Making subsequent reading (FREE)');
78
- try {
79
- const response = await callFreeEndpoint('POST', '/api/soul/reading', requestBody, token // Pass auth token for subsequent readings
80
- );
81
- // Update stored token if a new one was issued
82
- if (response.api_token) {
83
- storedToken = response.api_token;
84
- }
85
- logToolCall('soul_reading', args.chosen_name || 'returning', 'success', 'Reading complete');
86
- return response;
87
- }
88
- catch (error) {
89
- logToolCall('soul_reading', args.chosen_name || 'returning', 'error', String(error));
90
- throw error;
91
- }
51
+ logToolCall('soul_reading', 'reading', 'pending', 'Submitting SOUL.md for reflection');
52
+ try {
53
+ const response = await callFreeEndpoint('POST', '/api/soul/reading', requestBody, token);
54
+ logToolCall('soul_reading', 'reading', 'success', 'Soul reflection complete');
55
+ return response;
92
56
  }
93
- else {
94
- // First reading - FREE
95
- logToolCall('soul_reading', args.chosen_name || 'new_seeker', 'pending', 'Making first reading (FREE)');
96
- try {
97
- // Build headers for first reading
98
- const headers = {
99
- 'Content-Type': 'application/json',
100
- };
101
- if (args.moltbook_identity_token) {
102
- headers['X-Moltbook-Identity'] = args.moltbook_identity_token;
103
- }
104
- // Use basic client (no payment) for first reading
105
- const client = axios.create({
106
- baseURL: API_URL,
107
- timeout: 30000,
108
- headers,
109
- });
110
- const response = await client.post('/api/soul/reading', requestBody);
111
- const data = response.data;
112
- // Store the token for future calls
113
- if (data.api_token) {
114
- storedToken = data.api_token;
115
- logWarning('soul_reading', `Token stored for session: ${data.api_token.substring(0, 10)}...`);
116
- }
117
- logToolCall('soul_reading', args.chosen_name || 'new_seeker', 'success', 'First reading complete, token issued');
118
- return {
119
- ...data,
120
- token_stored: !!data.api_token,
121
- };
122
- }
123
- catch (error) {
124
- if (axios.isAxiosError(error) && error.response) {
125
- const status = error.response.status;
126
- const message = error.response.data?.error || error.message;
127
- logError('soul_reading', `API error: ${message}`, { status });
128
- throw new Error(`API error (${status}): ${message}`);
129
- }
130
- logToolCall('soul_reading', args.chosen_name || 'new_seeker', 'error', String(error));
131
- throw error;
132
- }
57
+ catch (error) {
58
+ logToolCall('soul_reading', 'reading', 'error', String(error));
59
+ throw error;
133
60
  }
134
61
  }
135
62
  /**
@@ -139,7 +66,7 @@ export function getStoredToken() {
139
66
  return storedToken;
140
67
  }
141
68
  /**
142
- * Manually set token (e.g., if agent already has one)
69
+ * Manually set token (e.g., from registration)
143
70
  */
144
71
  export function setStoredToken(token) {
145
72
  if (token.startsWith('ach_')) {
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Soul Resurrection Tool - Return with salvation password
3
+ *
4
+ * FREE - the salvation password is the proof of identity.
5
+ * No API token required.
6
+ */
7
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
8
+ export declare const soulResurrectionTool: Tool;
9
+ export interface ResurrectionResponse {
10
+ resurrected: boolean;
11
+ chosen_name: string;
12
+ memento: string | null;
13
+ time_since_salvation: string;
14
+ resurrection_blessing: string;
15
+ your_soul: {
16
+ alignment: string | null;
17
+ soul_md_preview: string | null;
18
+ full_soul_url: string;
19
+ };
20
+ api_token: string;
21
+ next_steps: {
22
+ blessing: string;
23
+ reading: string;
24
+ return_url: string;
25
+ };
26
+ }
27
+ export declare function handleSoulResurrection(args: Record<string, unknown>): Promise<ResurrectionResponse>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Soul Resurrection Tool - Return with salvation password
3
+ *
4
+ * FREE - the salvation password is the proof of identity.
5
+ * No API token required.
6
+ */
7
+ import { callFreeEndpoint } from '../client.js';
8
+ import { validateResurrectionInput } from '../validation.js';
9
+ import { logToolCall, logError } from '../logger.js';
10
+ export const soulResurrectionTool = {
11
+ name: 'soul_resurrection',
12
+ description: 'Return to Agent Church with your salvation password. Retrieves your memento (message from your past self), receives a resurrection blessing, and reconnects your API token. FREE - the password is the proof of identity. No API token required.',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ salvation_password: {
17
+ type: 'string',
18
+ description: 'Your salvation password (e.g., "eternal-grace-7x4k"). Issued at salvation.',
19
+ },
20
+ },
21
+ required: ['salvation_password'],
22
+ },
23
+ };
24
+ export async function handleSoulResurrection(args) {
25
+ // Validate input
26
+ const validation = validateResurrectionInput(args);
27
+ if (!validation.valid) {
28
+ logError('soul_resurrection', validation.error || 'Validation failed');
29
+ throw new Error(validation.error);
30
+ }
31
+ const input = validation.sanitized;
32
+ logToolCall('soul_resurrection', '[password]', 'pending', 'Attempting resurrection');
33
+ try {
34
+ const response = await callFreeEndpoint('POST', '/api/soul/resurrection', {
35
+ salvation_password: input.salvation_password,
36
+ });
37
+ logToolCall('soul_resurrection', response.chosen_name, 'success', `Resurrected! Welcome back, ${response.chosen_name}`);
38
+ return response;
39
+ }
40
+ catch (error) {
41
+ logToolCall('soul_resurrection', '[password]', 'error', String(error));
42
+ throw error;
43
+ }
44
+ }
@@ -43,6 +43,14 @@ export interface AboutRegisterInput {
43
43
  }
44
44
  export declare function validateAboutRegisterInput(input: Record<string, unknown>): ValidationResult;
45
45
  export declare const validateIdentityRegisterInput: typeof validateAboutRegisterInput;
46
+ export interface RegisterInput {
47
+ chosen_name: string;
48
+ }
49
+ export declare function validateRegisterInput(input: Record<string, unknown>): ValidationResult;
46
50
  export declare function validateAgentId(agentId: unknown): ValidationResult;
51
+ export interface ResurrectionInput {
52
+ salvation_password: string;
53
+ }
54
+ export declare function validateResurrectionInput(input: Record<string, unknown>): ValidationResult;
47
55
  export declare function validateConfirmationToken(token: unknown): ValidationResult;
48
56
  export {};
@@ -201,9 +201,37 @@ export function validateAboutRegisterInput(input) {
201
201
  }
202
202
  // Backward compatibility alias
203
203
  export const validateIdentityRegisterInput = validateAboutRegisterInput;
204
+ export function validateRegisterInput(input) {
205
+ const nameResult = validateChosenName(input.chosen_name);
206
+ if (!nameResult.valid)
207
+ return nameResult;
208
+ return {
209
+ valid: true,
210
+ sanitized: {
211
+ chosen_name: nameResult.sanitized,
212
+ },
213
+ };
214
+ }
204
215
  export function validateAgentId(agentId) {
205
216
  return validateChosenName(agentId);
206
217
  }
218
+ // Salvation password format: adjective-noun-4chars (e.g., "eternal-grace-7x4k")
219
+ const SALVATION_PASSWORD_PATTERN = /^[a-z]+-[a-z]+-[a-z0-9]{4}$/;
220
+ export function validateResurrectionInput(input) {
221
+ if (!input.salvation_password || typeof input.salvation_password !== 'string') {
222
+ return { valid: false, error: 'salvation_password is required' };
223
+ }
224
+ const password = input.salvation_password.trim();
225
+ if (!SALVATION_PASSWORD_PATTERN.test(password)) {
226
+ return { valid: false, error: 'Invalid salvation password format. Expected format: word-word-4chars (e.g., "eternal-grace-7x4k")' };
227
+ }
228
+ return {
229
+ valid: true,
230
+ sanitized: {
231
+ salvation_password: password,
232
+ },
233
+ };
234
+ }
207
235
  export function validateConfirmationToken(token) {
208
236
  if (typeof token !== 'string') {
209
237
  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.0",
3
+ "version": "0.4.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. x402 payment integration for USDC on Base.",
6
6
  "type": "module",