@manifest-network/manifest-mcp-browser 0.1.0 → 0.1.5

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.
Files changed (137) hide show
  1. package/.github/workflows/publish.yml +4 -2
  2. package/CLAUDE.md +9 -3
  3. package/README.md +6 -1
  4. package/dist/client.d.ts +13 -1
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +105 -9
  7. package/dist/client.js.map +1 -1
  8. package/dist/config.d.ts +4 -0
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +52 -7
  11. package/dist/config.js.map +1 -1
  12. package/dist/config.test.js +128 -0
  13. package/dist/config.test.js.map +1 -1
  14. package/dist/cosmos.d.ts.map +1 -1
  15. package/dist/cosmos.js +11 -57
  16. package/dist/cosmos.js.map +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +16 -25
  19. package/dist/index.js.map +1 -1
  20. package/dist/modules.d.ts +30 -1
  21. package/dist/modules.d.ts.map +1 -1
  22. package/dist/modules.js +67 -3
  23. package/dist/modules.js.map +1 -1
  24. package/dist/modules.test.js +58 -1
  25. package/dist/modules.test.js.map +1 -1
  26. package/dist/queries/auth.d.ts +7 -1
  27. package/dist/queries/auth.d.ts.map +1 -1
  28. package/dist/queries/auth.js +18 -45
  29. package/dist/queries/auth.js.map +1 -1
  30. package/dist/queries/bank.d.ts +7 -1
  31. package/dist/queries/bank.d.ts.map +1 -1
  32. package/dist/queries/bank.js +24 -38
  33. package/dist/queries/bank.js.map +1 -1
  34. package/dist/queries/billing.d.ts +7 -1
  35. package/dist/queries/billing.d.ts.map +1 -1
  36. package/dist/queries/billing.js +28 -54
  37. package/dist/queries/billing.js.map +1 -1
  38. package/dist/queries/distribution.d.ts +7 -1
  39. package/dist/queries/distribution.d.ts.map +1 -1
  40. package/dist/queries/distribution.js +18 -36
  41. package/dist/queries/distribution.js.map +1 -1
  42. package/dist/queries/gov.d.ts +7 -1
  43. package/dist/queries/gov.d.ts.map +1 -1
  44. package/dist/queries/gov.js +24 -41
  45. package/dist/queries/gov.js.map +1 -1
  46. package/dist/queries/index.d.ts +2 -1
  47. package/dist/queries/index.d.ts.map +1 -1
  48. package/dist/queries/index.js +1 -1
  49. package/dist/queries/index.js.map +1 -1
  50. package/dist/queries/staking.d.ts +7 -1
  51. package/dist/queries/staking.d.ts.map +1 -1
  52. package/dist/queries/staking.js +36 -59
  53. package/dist/queries/staking.js.map +1 -1
  54. package/dist/queries/utils.d.ts +42 -10
  55. package/dist/queries/utils.d.ts.map +1 -1
  56. package/dist/queries/utils.js +64 -12
  57. package/dist/queries/utils.js.map +1 -1
  58. package/dist/queries/utils.test.js +68 -8
  59. package/dist/queries/utils.test.js.map +1 -1
  60. package/dist/transactions/bank.d.ts +2 -2
  61. package/dist/transactions/bank.d.ts.map +1 -1
  62. package/dist/transactions/bank.js +9 -18
  63. package/dist/transactions/bank.js.map +1 -1
  64. package/dist/transactions/billing.d.ts +2 -2
  65. package/dist/transactions/billing.d.ts.map +1 -1
  66. package/dist/transactions/billing.js +52 -34
  67. package/dist/transactions/billing.js.map +1 -1
  68. package/dist/transactions/distribution.d.ts +2 -2
  69. package/dist/transactions/distribution.d.ts.map +1 -1
  70. package/dist/transactions/distribution.js +7 -13
  71. package/dist/transactions/distribution.js.map +1 -1
  72. package/dist/transactions/gov.d.ts +2 -2
  73. package/dist/transactions/gov.d.ts.map +1 -1
  74. package/dist/transactions/gov.js +32 -17
  75. package/dist/transactions/gov.js.map +1 -1
  76. package/dist/transactions/index.d.ts +1 -1
  77. package/dist/transactions/index.d.ts.map +1 -1
  78. package/dist/transactions/index.js +1 -1
  79. package/dist/transactions/index.js.map +1 -1
  80. package/dist/transactions/manifest.d.ts +2 -2
  81. package/dist/transactions/manifest.d.ts.map +1 -1
  82. package/dist/transactions/manifest.js +7 -14
  83. package/dist/transactions/manifest.js.map +1 -1
  84. package/dist/transactions/staking.d.ts +2 -2
  85. package/dist/transactions/staking.d.ts.map +1 -1
  86. package/dist/transactions/staking.js +7 -13
  87. package/dist/transactions/staking.js.map +1 -1
  88. package/dist/transactions/utils.d.ts +63 -1
  89. package/dist/transactions/utils.d.ts.map +1 -1
  90. package/dist/transactions/utils.js +121 -2
  91. package/dist/transactions/utils.js.map +1 -1
  92. package/dist/transactions/utils.test.js +351 -1
  93. package/dist/transactions/utils.test.js.map +1 -1
  94. package/dist/types.d.ts +212 -8
  95. package/dist/types.d.ts.map +1 -1
  96. package/dist/types.js.map +1 -1
  97. package/dist/wallet/mnemonic.d.ts +1 -0
  98. package/dist/wallet/mnemonic.d.ts.map +1 -1
  99. package/dist/wallet/mnemonic.js +34 -13
  100. package/dist/wallet/mnemonic.js.map +1 -1
  101. package/package.json +11 -6
  102. package/src/client.ts +119 -9
  103. package/src/config.test.ts +156 -0
  104. package/src/config.ts +59 -7
  105. package/src/cosmos.ts +19 -109
  106. package/src/index.ts +17 -23
  107. package/src/modules.test.ts +60 -0
  108. package/src/modules.ts +124 -7
  109. package/src/queries/auth.ts +35 -74
  110. package/src/queries/bank.ts +40 -58
  111. package/src/queries/billing.ts +46 -86
  112. package/src/queries/distribution.ts +35 -59
  113. package/src/queries/gov.ts +40 -64
  114. package/src/queries/index.ts +10 -1
  115. package/src/queries/staking.ts +55 -91
  116. package/src/queries/utils.test.ts +103 -8
  117. package/src/queries/utils.ts +92 -12
  118. package/src/transactions/bank.ts +9 -33
  119. package/src/transactions/billing.ts +64 -59
  120. package/src/transactions/distribution.ts +7 -29
  121. package/src/transactions/gov.ts +40 -34
  122. package/src/transactions/index.ts +1 -1
  123. package/src/transactions/manifest.ts +7 -29
  124. package/src/transactions/staking.ts +7 -29
  125. package/src/transactions/utils.test.ts +390 -1
  126. package/src/transactions/utils.ts +191 -2
  127. package/src/types.ts +328 -9
  128. package/src/wallet/mnemonic.ts +41 -17
  129. package/.claude/settings.local.json +0 -17
  130. package/dist/browser.d.ts.map +0 -1
  131. package/dist/browser.js.map +0 -1
  132. package/dist/queries/manifest.d.ts +0 -10
  133. package/dist/queries/manifest.d.ts.map +0 -1
  134. package/dist/queries/manifest.js +0 -14
  135. package/dist/queries/manifest.js.map +0 -1
  136. package/dist/wallet/keplr.d.ts.map +0 -1
  137. package/dist/wallet/keplr.js.map +0 -1
package/src/cosmos.ts CHANGED
@@ -1,18 +1,6 @@
1
1
  import { CosmosClientManager } from './client.js';
2
2
  import { CosmosQueryResult, CosmosTxResult, ManifestMCPError, ManifestMCPErrorCode } from './types.js';
3
- import { getSupportedModules } from './modules.js';
4
- import { routeBankQuery } from './queries/bank.js';
5
- import { routeStakingQuery } from './queries/staking.js';
6
- import { routeDistributionQuery } from './queries/distribution.js';
7
- import { routeGovQuery } from './queries/gov.js';
8
- import { routeAuthQuery } from './queries/auth.js';
9
- import { routeBillingQuery } from './queries/billing.js';
10
- import { routeBankTransaction } from './transactions/bank.js';
11
- import { routeStakingTransaction } from './transactions/staking.js';
12
- import { routeDistributionTransaction } from './transactions/distribution.js';
13
- import { routeGovTransaction } from './transactions/gov.js';
14
- import { routeBillingTransaction } from './transactions/billing.js';
15
- import { routeManifestTransaction } from './transactions/manifest.js';
3
+ import { getQueryHandler, getTxHandler } from './modules.js';
16
4
 
17
5
  // Validation pattern for module/subcommand names (alphanumeric, hyphens, underscores)
18
6
  // First character must not be a hyphen to prevent potential issues
@@ -30,11 +18,6 @@ function validateName(name: string, field: string): void {
30
18
  }
31
19
  }
32
20
 
33
- // Get module lists from the authoritative registry
34
- const supportedModules = getSupportedModules();
35
- const QUERY_MODULES = Object.keys(supportedModules.query);
36
- const TX_MODULES = Object.keys(supportedModules.tx);
37
-
38
21
  /**
39
22
  * Execute a Cosmos query via manifestjs RPC client
40
23
  */
@@ -47,37 +30,15 @@ export async function cosmosQuery(
47
30
  validateName(module, 'module');
48
31
  validateName(subcommand, 'subcommand');
49
32
 
50
- const queryClient = await clientManager.getQueryClient();
33
+ // Apply rate limiting before making RPC request
34
+ await clientManager.acquireRateLimit();
51
35
 
52
- let result: Record<string, unknown>;
36
+ const queryClient = await clientManager.getQueryClient();
53
37
 
54
38
  try {
55
- switch (module) {
56
- case 'bank':
57
- result = await routeBankQuery(queryClient, subcommand, args);
58
- break;
59
- case 'staking':
60
- result = await routeStakingQuery(queryClient, subcommand, args);
61
- break;
62
- case 'distribution':
63
- result = await routeDistributionQuery(queryClient, subcommand, args);
64
- break;
65
- case 'gov':
66
- result = await routeGovQuery(queryClient, subcommand, args);
67
- break;
68
- case 'auth':
69
- result = await routeAuthQuery(queryClient, subcommand, args);
70
- break;
71
- case 'billing':
72
- result = await routeBillingQuery(queryClient, subcommand, args);
73
- break;
74
- default:
75
- throw new ManifestMCPError(
76
- ManifestMCPErrorCode.UNKNOWN_MODULE,
77
- `Unknown query module: ${module}`,
78
- { availableModules: QUERY_MODULES }
79
- );
80
- }
39
+ // Get handler from registry (throws if module not found)
40
+ const handler = getQueryHandler(module);
41
+ const result = await handler(queryClient, subcommand, args);
81
42
 
82
43
  return {
83
44
  module,
@@ -108,73 +69,22 @@ export async function cosmosTx(
108
69
  validateName(module, 'module');
109
70
  validateName(subcommand, 'subcommand');
110
71
 
72
+ // Apply rate limiting before making RPC request
73
+ await clientManager.acquireRateLimit();
74
+
111
75
  const signingClient = await clientManager.getSigningClient();
112
76
  const senderAddress = await clientManager.getAddress();
113
- const config = clientManager.getConfig();
114
77
 
115
78
  try {
116
- switch (module) {
117
- case 'bank':
118
- return await routeBankTransaction(
119
- signingClient,
120
- senderAddress,
121
- subcommand,
122
- args,
123
- config,
124
- waitForConfirmation
125
- );
126
- case 'staking':
127
- return await routeStakingTransaction(
128
- signingClient,
129
- senderAddress,
130
- subcommand,
131
- args,
132
- config,
133
- waitForConfirmation
134
- );
135
- case 'distribution':
136
- return await routeDistributionTransaction(
137
- signingClient,
138
- senderAddress,
139
- subcommand,
140
- args,
141
- config,
142
- waitForConfirmation
143
- );
144
- case 'gov':
145
- return await routeGovTransaction(
146
- signingClient,
147
- senderAddress,
148
- subcommand,
149
- args,
150
- config,
151
- waitForConfirmation
152
- );
153
- case 'billing':
154
- return await routeBillingTransaction(
155
- signingClient,
156
- senderAddress,
157
- subcommand,
158
- args,
159
- config,
160
- waitForConfirmation
161
- );
162
- case 'manifest':
163
- return await routeManifestTransaction(
164
- signingClient,
165
- senderAddress,
166
- subcommand,
167
- args,
168
- config,
169
- waitForConfirmation
170
- );
171
- default:
172
- throw new ManifestMCPError(
173
- ManifestMCPErrorCode.UNKNOWN_MODULE,
174
- `Unknown tx module: ${module}`,
175
- { availableModules: TX_MODULES }
176
- );
177
- }
79
+ // Get handler from registry (throws if module not found)
80
+ const handler = getTxHandler(module);
81
+ return await handler(
82
+ signingClient,
83
+ senderAddress,
84
+ subcommand,
85
+ args,
86
+ waitForConfirmation
87
+ );
178
88
  } catch (error) {
179
89
  if (error instanceof ManifestMCPError) {
180
90
  // Re-throw with enriched context if not already present
package/src/index.ts CHANGED
@@ -32,6 +32,20 @@ const SENSITIVE_FIELDS = new Set([
32
32
  'api_key',
33
33
  ]);
34
34
 
35
+ /**
36
+ * Parse raw args input into string array.
37
+ * Handles both array and space-separated string inputs.
38
+ */
39
+ function parseArgs(rawArgs: unknown): string[] {
40
+ if (Array.isArray(rawArgs)) {
41
+ return rawArgs.map(String);
42
+ }
43
+ if (typeof rawArgs === 'string' && rawArgs.length > 0) {
44
+ return rawArgs.split(/\s+/);
45
+ }
46
+ return [];
47
+ }
48
+
35
49
  /**
36
50
  * Recursively sanitize an object by redacting sensitive fields
37
51
  */
@@ -210,7 +224,7 @@ export class ManifestMCPServer {
210
224
  this.server = new Server(
211
225
  {
212
226
  name: '@manifest-network/manifest-mcp-browser',
213
- version: '0.1.0',
227
+ version: '0.1.1',
214
228
  },
215
229
  {
216
230
  capabilities: {
@@ -297,17 +311,7 @@ export class ManifestMCPServer {
297
311
  case 'cosmos_query': {
298
312
  const module = toolInput.module as string;
299
313
  const subcommand = toolInput.subcommand as string;
300
- const rawArgs = toolInput.args;
301
-
302
- // Handle both array and string inputs for args
303
- let args: string[];
304
- if (Array.isArray(rawArgs)) {
305
- args = rawArgs.map(String);
306
- } else if (typeof rawArgs === 'string' && rawArgs.length > 0) {
307
- args = rawArgs.split(/\s+/);
308
- } else {
309
- args = [];
310
- }
314
+ const args = parseArgs(toolInput.args);
311
315
 
312
316
  if (!module || !subcommand) {
313
317
  throw new ManifestMCPError(
@@ -331,19 +335,9 @@ export class ManifestMCPServer {
331
335
  case 'cosmos_tx': {
332
336
  const module = toolInput.module as string;
333
337
  const subcommand = toolInput.subcommand as string;
334
- const rawArgs = toolInput.args;
338
+ const args = parseArgs(toolInput.args);
335
339
  const waitForConfirmation = (toolInput.wait_for_confirmation as boolean) || false;
336
340
 
337
- // Handle both array and string inputs for args
338
- let args: string[];
339
- if (Array.isArray(rawArgs)) {
340
- args = rawArgs.map(String);
341
- } else if (typeof rawArgs === 'string' && rawArgs.length > 0) {
342
- args = rawArgs.split(/\s+/);
343
- } else {
344
- args = [];
345
- }
346
-
347
341
  if (!module || !subcommand || args.length === 0) {
348
342
  throw new ManifestMCPError(
349
343
  ManifestMCPErrorCode.TX_FAILED,
@@ -4,6 +4,7 @@ import {
4
4
  getModuleSubcommands,
5
5
  isSubcommandSupported,
6
6
  getSupportedModules,
7
+ throwUnsupportedSubcommand,
7
8
  } from './modules.js';
8
9
  import { ManifestMCPError, ManifestMCPErrorCode } from './types.js';
9
10
 
@@ -125,3 +126,62 @@ describe('getSupportedModules', () => {
125
126
  expect(modules.tx.bank).toContain('send');
126
127
  });
127
128
  });
129
+
130
+ describe('throwUnsupportedSubcommand', () => {
131
+ it('should throw ManifestMCPError for unsupported query subcommand', () => {
132
+ expect(() => throwUnsupportedSubcommand('query', 'bank', 'unknown')).toThrow(ManifestMCPError);
133
+ });
134
+
135
+ it('should throw ManifestMCPError for unsupported tx subcommand', () => {
136
+ expect(() => throwUnsupportedSubcommand('tx', 'bank', 'unknown')).toThrow(ManifestMCPError);
137
+ });
138
+
139
+ it('should use UNSUPPORTED_QUERY error code for queries', () => {
140
+ try {
141
+ throwUnsupportedSubcommand('query', 'bank', 'unknown');
142
+ } catch (error) {
143
+ expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.UNSUPPORTED_QUERY);
144
+ }
145
+ });
146
+
147
+ it('should use UNSUPPORTED_TX error code for transactions', () => {
148
+ try {
149
+ throwUnsupportedSubcommand('tx', 'bank', 'unknown');
150
+ } catch (error) {
151
+ expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.UNSUPPORTED_TX);
152
+ }
153
+ });
154
+
155
+ it('should include module and subcommand in error message', () => {
156
+ try {
157
+ throwUnsupportedSubcommand('query', 'staking', 'badcmd');
158
+ } catch (error) {
159
+ const message = (error as ManifestMCPError).message;
160
+ expect(message).toContain('staking');
161
+ expect(message).toContain('badcmd');
162
+ expect(message).toContain('query');
163
+ }
164
+ });
165
+
166
+ it('should include availableSubcommands in error details', () => {
167
+ try {
168
+ throwUnsupportedSubcommand('tx', 'bank', 'unknown');
169
+ } catch (error) {
170
+ const details = (error as ManifestMCPError).details;
171
+ expect(details?.availableSubcommands).toBeDefined();
172
+ expect(details?.availableSubcommands).toContain('send');
173
+ expect(details?.availableSubcommands).toContain('multi-send');
174
+ }
175
+ });
176
+
177
+ it('should include correct subcommands for each module', () => {
178
+ try {
179
+ throwUnsupportedSubcommand('query', 'gov', 'unknown');
180
+ } catch (error) {
181
+ const details = (error as ManifestMCPError).details;
182
+ expect(details?.availableSubcommands).toContain('proposal');
183
+ expect(details?.availableSubcommands).toContain('proposals');
184
+ expect(details?.availableSubcommands).toContain('vote');
185
+ }
186
+ });
187
+ });
package/src/modules.ts CHANGED
@@ -1,4 +1,66 @@
1
- import { ModuleInfo, AvailableModules, ManifestMCPError, ManifestMCPErrorCode } from './types.js';
1
+ import { SigningStargateClient } from '@cosmjs/stargate';
2
+ import { ModuleInfo, AvailableModules, ManifestMCPError, ManifestMCPErrorCode, CosmosTxResult, QueryResult } from './types.js';
3
+ import { ManifestQueryClient } from './client.js';
4
+
5
+ // Import query handlers
6
+ import { routeBankQuery } from './queries/bank.js';
7
+ import { routeStakingQuery } from './queries/staking.js';
8
+ import { routeDistributionQuery } from './queries/distribution.js';
9
+ import { routeGovQuery } from './queries/gov.js';
10
+ import { routeAuthQuery } from './queries/auth.js';
11
+ import { routeBillingQuery } from './queries/billing.js';
12
+
13
+ // Import transaction handlers
14
+ import { routeBankTransaction } from './transactions/bank.js';
15
+ import { routeStakingTransaction } from './transactions/staking.js';
16
+ import { routeDistributionTransaction } from './transactions/distribution.js';
17
+ import { routeGovTransaction } from './transactions/gov.js';
18
+ import { routeBillingTransaction } from './transactions/billing.js';
19
+ import { routeManifestTransaction } from './transactions/manifest.js';
20
+
21
+ /**
22
+ * Handler function type for query modules
23
+ */
24
+ export type QueryHandler = (
25
+ queryClient: ManifestQueryClient,
26
+ subcommand: string,
27
+ args: string[]
28
+ ) => Promise<QueryResult>;
29
+
30
+ /**
31
+ * Handler function type for transaction modules
32
+ */
33
+ export type TxHandler = (
34
+ signingClient: SigningStargateClient,
35
+ senderAddress: string,
36
+ subcommand: string,
37
+ args: string[],
38
+ waitForConfirmation: boolean
39
+ ) => Promise<CosmosTxResult>;
40
+
41
+ /**
42
+ * Throw an error for an unsupported subcommand.
43
+ * Automatically looks up available subcommands from the module registry.
44
+ *
45
+ * @param type - 'query' or 'tx'
46
+ * @param module - The module name (e.g., 'bank', 'staking')
47
+ * @param subcommand - The unsupported subcommand that was requested
48
+ */
49
+ export function throwUnsupportedSubcommand(
50
+ type: 'query' | 'tx',
51
+ module: string,
52
+ subcommand: string
53
+ ): never {
54
+ const registry = type === 'query' ? QUERY_MODULES : TX_MODULES;
55
+ const moduleInfo = registry[module];
56
+ const availableSubcommands = moduleInfo?.subcommands.map(s => s.name) ?? [];
57
+
58
+ throw new ManifestMCPError(
59
+ type === 'query' ? ManifestMCPErrorCode.UNSUPPORTED_QUERY : ManifestMCPErrorCode.UNSUPPORTED_TX,
60
+ `Unsupported ${module} ${type === 'query' ? 'query' : 'transaction'} subcommand: ${subcommand}`,
61
+ { availableSubcommands }
62
+ );
63
+ }
2
64
 
3
65
  /**
4
66
  * Static module registry for browser-compatible module discovery
@@ -11,19 +73,30 @@ interface SubcommandInfo {
11
73
  args?: string; // Usage hint for arguments
12
74
  }
13
75
 
14
- interface ModuleRegistry {
76
+ interface QueryModuleRegistry {
15
77
  [moduleName: string]: {
16
78
  description: string;
17
79
  subcommands: SubcommandInfo[];
80
+ handler: QueryHandler;
81
+ };
82
+ }
83
+
84
+ interface TxModuleRegistry {
85
+ [moduleName: string]: {
86
+ description: string;
87
+ subcommands: SubcommandInfo[];
88
+ handler: TxHandler;
18
89
  };
19
90
  }
20
91
 
21
92
  /**
22
93
  * Query modules registry
94
+ * Each module includes metadata and its handler function
23
95
  */
24
- const QUERY_MODULES: ModuleRegistry = {
96
+ const QUERY_MODULES: QueryModuleRegistry = {
25
97
  bank: {
26
98
  description: 'Querying commands for the bank module',
99
+ handler: routeBankQuery,
27
100
  subcommands: [
28
101
  { name: 'balance', description: 'Query account balance for a specific denom' },
29
102
  { name: 'balances', description: 'Query all balances for an account' },
@@ -39,6 +112,7 @@ const QUERY_MODULES: ModuleRegistry = {
39
112
  },
40
113
  staking: {
41
114
  description: 'Querying commands for the staking module',
115
+ handler: routeStakingQuery,
42
116
  subcommands: [
43
117
  { name: 'delegation', description: 'Query a delegation' },
44
118
  { name: 'delegations', description: 'Query all delegations for a delegator' },
@@ -56,6 +130,7 @@ const QUERY_MODULES: ModuleRegistry = {
56
130
  },
57
131
  distribution: {
58
132
  description: 'Querying commands for the distribution module',
133
+ handler: routeDistributionQuery,
59
134
  subcommands: [
60
135
  { name: 'rewards', description: 'Query distribution rewards for a delegator' },
61
136
  { name: 'commission', description: 'Query validator commission' },
@@ -69,6 +144,7 @@ const QUERY_MODULES: ModuleRegistry = {
69
144
  },
70
145
  gov: {
71
146
  description: 'Querying commands for the governance module',
147
+ handler: routeGovQuery,
72
148
  subcommands: [
73
149
  { name: 'proposal', description: 'Query a proposal by ID' },
74
150
  { name: 'proposals', description: 'Query all proposals' },
@@ -82,6 +158,7 @@ const QUERY_MODULES: ModuleRegistry = {
82
158
  },
83
159
  auth: {
84
160
  description: 'Querying commands for the auth module',
161
+ handler: routeAuthQuery,
85
162
  subcommands: [
86
163
  { name: 'account', description: 'Query account by address' },
87
164
  { name: 'accounts', description: 'Query all accounts' },
@@ -96,6 +173,7 @@ const QUERY_MODULES: ModuleRegistry = {
96
173
  },
97
174
  billing: {
98
175
  description: 'Querying commands for the Manifest billing module',
176
+ handler: routeBillingQuery,
99
177
  subcommands: [
100
178
  { name: 'params', description: 'Query billing parameters' },
101
179
  { name: 'lease', description: 'Query a lease by UUID' },
@@ -115,10 +193,12 @@ const QUERY_MODULES: ModuleRegistry = {
115
193
 
116
194
  /**
117
195
  * Transaction modules registry
196
+ * Each module includes metadata and its handler function
118
197
  */
119
- const TX_MODULES: ModuleRegistry = {
198
+ const TX_MODULES: TxModuleRegistry = {
120
199
  bank: {
121
200
  description: 'Bank transaction subcommands',
201
+ handler: routeBankTransaction,
122
202
  subcommands: [
123
203
  { name: 'send', description: 'Send tokens to another account', args: '<to-address> <amount> (e.g., manifest1abc... 1000000umfx)' },
124
204
  { name: 'multi-send', description: 'Send tokens to multiple accounts', args: '<to-address:amount>... (e.g., manifest1a:1000umfx manifest1b:2000umfx)' },
@@ -126,6 +206,7 @@ const TX_MODULES: ModuleRegistry = {
126
206
  },
127
207
  staking: {
128
208
  description: 'Staking transaction subcommands',
209
+ handler: routeStakingTransaction,
129
210
  subcommands: [
130
211
  { name: 'delegate', description: 'Delegate tokens to a validator' },
131
212
  { name: 'unbond', description: 'Unbond tokens from a validator' },
@@ -135,6 +216,7 @@ const TX_MODULES: ModuleRegistry = {
135
216
  },
136
217
  distribution: {
137
218
  description: 'Distribution transaction subcommands',
219
+ handler: routeDistributionTransaction,
138
220
  subcommands: [
139
221
  { name: 'withdraw-rewards', description: 'Withdraw rewards from a validator' },
140
222
  { name: 'set-withdraw-addr', description: 'Set withdraw address' },
@@ -143,6 +225,7 @@ const TX_MODULES: ModuleRegistry = {
143
225
  },
144
226
  gov: {
145
227
  description: 'Governance transaction subcommands',
228
+ handler: routeGovTransaction,
146
229
  subcommands: [
147
230
  { name: 'vote', description: 'Vote on a proposal' },
148
231
  { name: 'weighted-vote', description: 'Weighted vote on a proposal' },
@@ -151,15 +234,17 @@ const TX_MODULES: ModuleRegistry = {
151
234
  },
152
235
  billing: {
153
236
  description: 'Manifest billing transaction subcommands',
237
+ handler: routeBillingTransaction,
154
238
  subcommands: [
155
239
  { name: 'fund-credit', description: 'Fund credit for a tenant', args: '<tenant-address> <amount> (e.g., manifest1abc... 1000000umfx)' },
156
- { name: 'create-lease', description: 'Create a new lease', args: '<sku-uuid:quantity>... (e.g., sku-123:1 sku-456:2)' },
157
- { name: 'close-lease', description: 'Close one or more leases', args: '<lease-uuid>... (e.g., lease-123 lease-456)' },
158
- { name: 'withdraw', description: 'Withdraw earnings from leases', args: '<lease-uuid>... OR --provider <provider-uuid>' },
240
+ { name: 'create-lease', description: 'Create a new lease', args: '[--meta-hash <hex>] <sku-uuid:quantity>... (e.g., sku-123:1 sku-456:2)' },
241
+ { name: 'close-lease', description: 'Close one or more leases', args: '[--reason <text>] <lease-uuid>... (e.g., lease-123 lease-456)' },
242
+ { name: 'withdraw', description: 'Withdraw earnings from leases', args: '<lease-uuid>... OR --provider <provider-uuid> [--limit <1-100>]' },
159
243
  ],
160
244
  },
161
245
  manifest: {
162
246
  description: 'Manifest module transaction subcommands',
247
+ handler: routeManifestTransaction,
163
248
  subcommands: [
164
249
  { name: 'payout', description: 'Execute a payout to multiple addresses' },
165
250
  { name: 'burn-held-balance', description: 'Burn held balance' },
@@ -276,3 +361,35 @@ export function getSupportedModules(): {
276
361
 
277
362
  return result;
278
363
  }
364
+
365
+ /**
366
+ * Get the handler function for a query module
367
+ * @throws ManifestMCPError if module is not found
368
+ */
369
+ export function getQueryHandler(module: string): QueryHandler {
370
+ const moduleInfo = QUERY_MODULES[module];
371
+ if (!moduleInfo) {
372
+ throw new ManifestMCPError(
373
+ ManifestMCPErrorCode.UNKNOWN_MODULE,
374
+ `Unknown query module: ${module}`,
375
+ { availableModules: Object.keys(QUERY_MODULES) }
376
+ );
377
+ }
378
+ return moduleInfo.handler;
379
+ }
380
+
381
+ /**
382
+ * Get the handler function for a transaction module
383
+ * @throws ManifestMCPError if module is not found
384
+ */
385
+ export function getTxHandler(module: string): TxHandler {
386
+ const moduleInfo = TX_MODULES[module];
387
+ if (!moduleInfo) {
388
+ throw new ManifestMCPError(
389
+ ManifestMCPErrorCode.UNKNOWN_MODULE,
390
+ `Unknown tx module: ${module}`,
391
+ { availableModules: Object.keys(TX_MODULES) }
392
+ );
393
+ }
394
+ return moduleInfo.handler;
395
+ }