@manifest-network/manifest-mcp-browser 0.1.7 → 0.1.8

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 (78) hide show
  1. package/README.md +5 -2
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +0 -10
  4. package/dist/config.js.map +1 -1
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -7
  8. package/dist/index.js.map +1 -1
  9. package/dist/queries/index.d.ts +1 -0
  10. package/dist/queries/index.d.ts.map +1 -1
  11. package/dist/queries/index.js +1 -0
  12. package/dist/queries/index.js.map +1 -1
  13. package/dist/transactions/bank.d.ts.map +1 -1
  14. package/dist/transactions/bank.js +7 -5
  15. package/dist/transactions/bank.js.map +1 -1
  16. package/dist/transactions/gov.d.ts.map +1 -1
  17. package/dist/transactions/gov.js +7 -5
  18. package/dist/transactions/gov.js.map +1 -1
  19. package/dist/transactions/index.d.ts +1 -0
  20. package/dist/transactions/index.d.ts.map +1 -1
  21. package/dist/transactions/index.js +1 -0
  22. package/dist/transactions/index.js.map +1 -1
  23. package/dist/types.d.ts +0 -2
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/types.js.map +1 -1
  26. package/package.json +5 -2
  27. package/.github/workflows/ci.yml +0 -37
  28. package/.github/workflows/publish.yml +0 -53
  29. package/CLAUDE.md +0 -113
  30. package/dist/config.test.d.ts +0 -2
  31. package/dist/config.test.d.ts.map +0 -1
  32. package/dist/config.test.js +0 -251
  33. package/dist/config.test.js.map +0 -1
  34. package/dist/modules.test.d.ts +0 -2
  35. package/dist/modules.test.d.ts.map +0 -1
  36. package/dist/modules.test.js +0 -161
  37. package/dist/modules.test.js.map +0 -1
  38. package/dist/queries/utils.test.d.ts +0 -2
  39. package/dist/queries/utils.test.d.ts.map +0 -1
  40. package/dist/queries/utils.test.js +0 -117
  41. package/dist/queries/utils.test.js.map +0 -1
  42. package/dist/transactions/utils.test.d.ts +0 -2
  43. package/dist/transactions/utils.test.d.ts.map +0 -1
  44. package/dist/transactions/utils.test.js +0 -567
  45. package/dist/transactions/utils.test.js.map +0 -1
  46. package/src/client.ts +0 -288
  47. package/src/config.test.ts +0 -299
  48. package/src/config.ts +0 -174
  49. package/src/cosmos.ts +0 -106
  50. package/src/index.ts +0 -478
  51. package/src/modules.test.ts +0 -191
  52. package/src/modules.ts +0 -470
  53. package/src/queries/auth.ts +0 -97
  54. package/src/queries/bank.ts +0 -99
  55. package/src/queries/billing.ts +0 -124
  56. package/src/queries/distribution.ts +0 -114
  57. package/src/queries/gov.ts +0 -104
  58. package/src/queries/group.ts +0 -146
  59. package/src/queries/index.ts +0 -17
  60. package/src/queries/sku.ts +0 -85
  61. package/src/queries/staking.ts +0 -154
  62. package/src/queries/utils.test.ts +0 -156
  63. package/src/queries/utils.ts +0 -121
  64. package/src/transactions/bank.ts +0 -86
  65. package/src/transactions/billing.ts +0 -286
  66. package/src/transactions/distribution.ts +0 -76
  67. package/src/transactions/gov.ts +0 -164
  68. package/src/transactions/group.ts +0 -458
  69. package/src/transactions/index.ts +0 -8
  70. package/src/transactions/manifest.ts +0 -67
  71. package/src/transactions/sku.ts +0 -232
  72. package/src/transactions/staking.ts +0 -85
  73. package/src/transactions/utils.test.ts +0 -626
  74. package/src/transactions/utils.ts +0 -417
  75. package/src/types.ts +0 -548
  76. package/src/wallet/index.ts +0 -2
  77. package/src/wallet/mnemonic.ts +0 -146
  78. package/tsconfig.json +0 -23
package/src/index.ts DELETED
@@ -1,478 +0,0 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import {
3
- ListToolsRequestSchema,
4
- CallToolRequestSchema,
5
- Tool,
6
- } from '@modelcontextprotocol/sdk/types.js';
7
- import { CosmosClientManager } from './client.js';
8
- import { cosmosQuery, cosmosTx } from './cosmos.js';
9
- import { getAvailableModules, getModuleSubcommands } from './modules.js';
10
- import {
11
- ManifestMCPConfig,
12
- WalletProvider,
13
- AccountInfo,
14
- ManifestMCPError,
15
- ManifestMCPErrorCode,
16
- } from './types.js';
17
- import { createValidatedConfig } from './config.js';
18
-
19
- /**
20
- * Sensitive field names that should be redacted from error responses
21
- */
22
- const SENSITIVE_FIELDS = new Set([
23
- 'mnemonic',
24
- 'privatekey',
25
- 'private_key',
26
- 'secret',
27
- 'password',
28
- 'seed',
29
- 'key',
30
- 'token',
31
- 'apikey',
32
- 'api_key',
33
- ]);
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
-
49
- /**
50
- * Recursively sanitize an object by redacting sensitive fields
51
- */
52
- function sanitizeForLogging(obj: unknown, depth = 0): unknown {
53
- // Prevent infinite recursion
54
- if (depth > 10) {
55
- return '[max depth exceeded]';
56
- }
57
-
58
- if (obj === null || obj === undefined) {
59
- return obj;
60
- }
61
-
62
- if (typeof obj === 'string') {
63
- // Redact strings that look like mnemonics (12 or 24 words)
64
- const wordCount = obj.trim().split(/\s+/).length;
65
- if (wordCount === 12 || wordCount === 24) {
66
- return '[REDACTED - possible mnemonic]';
67
- }
68
- return obj;
69
- }
70
-
71
- if (Array.isArray(obj)) {
72
- return obj.map(item => sanitizeForLogging(item, depth + 1));
73
- }
74
-
75
- if (typeof obj === 'object') {
76
- const sanitized: Record<string, unknown> = {};
77
- for (const [key, value] of Object.entries(obj)) {
78
- const lowerKey = key.toLowerCase();
79
- if (SENSITIVE_FIELDS.has(lowerKey)) {
80
- sanitized[key] = '[REDACTED]';
81
- } else {
82
- sanitized[key] = sanitizeForLogging(value, depth + 1);
83
- }
84
- }
85
- return sanitized;
86
- }
87
-
88
- return obj;
89
- }
90
-
91
- // Re-export types and utilities
92
- export * from './types.js';
93
- export { createConfig, createValidatedConfig, validateConfig } from './config.js';
94
- export { CosmosClientManager } from './client.js';
95
- export { cosmosQuery, cosmosTx } from './cosmos.js';
96
- export { getAvailableModules, getModuleSubcommands, getSubcommandUsage, getSupportedModules, isSubcommandSupported } from './modules.js';
97
- export { MnemonicWalletProvider } from './wallet/index.js';
98
-
99
- /**
100
- * Tool definitions for the MCP server
101
- */
102
- const tools: Tool[] = [
103
- {
104
- name: 'get_account_info',
105
- description: 'Get account address and key name for the configured key',
106
- inputSchema: {
107
- type: 'object',
108
- properties: {},
109
- required: [],
110
- },
111
- },
112
- {
113
- name: 'cosmos_query',
114
- description:
115
- 'Execute any Cosmos SDK query command. Use list_modules and list_module_subcommands to discover available options.',
116
- inputSchema: {
117
- type: 'object',
118
- properties: {
119
- module: {
120
- type: 'string',
121
- description:
122
- 'The module name (e.g., "bank", "staking", "distribution", "gov", "auth")',
123
- },
124
- subcommand: {
125
- type: 'string',
126
- description:
127
- 'The subcommand (e.g., "balance", "balances", "delegations", "rewards", "proposals")',
128
- },
129
- args: {
130
- type: 'array',
131
- items: { type: 'string' },
132
- description:
133
- 'Additional arguments as an array of strings (e.g., ["<address>", "umfx"] for bank balance). Use array to preserve arguments with spaces.',
134
- },
135
- },
136
- required: ['module', 'subcommand'],
137
- },
138
- },
139
- {
140
- name: 'cosmos_tx',
141
- description:
142
- 'Execute any Cosmos SDK transaction. Automatically signs with the configured key and estimates gas. Use list_modules and list_module_subcommands to discover available options.',
143
- inputSchema: {
144
- type: 'object',
145
- properties: {
146
- module: {
147
- type: 'string',
148
- description: 'The module name (e.g., "bank", "staking", "gov")',
149
- },
150
- subcommand: {
151
- type: 'string',
152
- description: 'The subcommand (e.g., "send", "delegate", "unbond", "vote")',
153
- },
154
- args: {
155
- type: 'array',
156
- items: { type: 'string' },
157
- description:
158
- 'Arguments to the transaction as an array of strings (e.g., ["<to_address>", "1000umfx"] for bank send). Use array to preserve arguments with spaces.',
159
- },
160
- wait_for_confirmation: {
161
- type: 'boolean',
162
- description:
163
- 'If true, wait for the transaction to be included in a block before returning. Defaults to false (broadcast only).',
164
- },
165
- },
166
- required: ['module', 'subcommand', 'args'],
167
- },
168
- },
169
- {
170
- name: 'list_modules',
171
- description:
172
- 'List all available query and transaction modules supported by the chain',
173
- inputSchema: {
174
- type: 'object',
175
- properties: {},
176
- required: [],
177
- },
178
- },
179
- {
180
- name: 'list_module_subcommands',
181
- description:
182
- 'List all available subcommands for a specific module (query or tx)',
183
- inputSchema: {
184
- type: 'object',
185
- properties: {
186
- type: {
187
- type: 'string',
188
- enum: ['query', 'tx'],
189
- description: 'Whether to list query or transaction subcommands',
190
- },
191
- module: {
192
- type: 'string',
193
- description: 'The module name (e.g., "bank", "staking")',
194
- },
195
- },
196
- required: ['type', 'module'],
197
- },
198
- },
199
- ];
200
-
201
- /**
202
- * Options for creating a ManifestMCPServer
203
- */
204
- export interface ManifestMCPServerOptions {
205
- config: ManifestMCPConfig;
206
- walletProvider: WalletProvider;
207
- }
208
-
209
- /**
210
- * ManifestMCPServer class for browser-compatible MCP server
211
- */
212
- export class ManifestMCPServer {
213
- private server: Server;
214
- private clientManager: CosmosClientManager;
215
- private walletProvider: WalletProvider;
216
- private config: ManifestMCPConfig;
217
-
218
- constructor(options: ManifestMCPServerOptions) {
219
- this.config = createValidatedConfig(options.config);
220
- this.walletProvider = options.walletProvider;
221
- this.clientManager = CosmosClientManager.getInstance(this.config, this.walletProvider);
222
-
223
- // Note: Keep version in sync with package.json
224
- this.server = new Server(
225
- {
226
- name: '@manifest-network/manifest-mcp-browser',
227
- version: '0.1.1',
228
- },
229
- {
230
- capabilities: {
231
- tools: {},
232
- },
233
- }
234
- );
235
-
236
- this.setupHandlers();
237
- }
238
-
239
- /**
240
- * Set up the MCP request handlers
241
- */
242
- private setupHandlers(): void {
243
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
244
- tools,
245
- }));
246
-
247
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
248
- const toolName = request.params.name;
249
- const toolInput = request.params.arguments || {};
250
-
251
- try {
252
- return await this.handleToolCall(toolName, toolInput);
253
- } catch (error) {
254
- // Build detailed error response with sanitized inputs
255
- let errorResponse: Record<string, unknown> = {
256
- error: true,
257
- tool: toolName,
258
- input: sanitizeForLogging(toolInput),
259
- };
260
-
261
- if (error instanceof ManifestMCPError) {
262
- errorResponse = {
263
- ...errorResponse,
264
- code: error.code,
265
- message: error.message,
266
- details: sanitizeForLogging(error.details),
267
- };
268
- } else {
269
- errorResponse = {
270
- ...errorResponse,
271
- message: error instanceof Error ? error.message : String(error),
272
- };
273
- }
274
-
275
- return {
276
- content: [
277
- {
278
- type: 'text',
279
- text: JSON.stringify(errorResponse, null, 2),
280
- },
281
- ],
282
- isError: true,
283
- };
284
- }
285
- });
286
- }
287
-
288
- /**
289
- * Handle a tool call
290
- */
291
- private async handleToolCall(
292
- toolName: string,
293
- toolInput: Record<string, unknown>
294
- ): Promise<{ content: Array<{ type: string; text: string }>; isError?: boolean }> {
295
- switch (toolName) {
296
- case 'get_account_info': {
297
- const address = await this.walletProvider.getAddress();
298
- const accountInfo: AccountInfo = {
299
- address,
300
- };
301
- return {
302
- content: [
303
- {
304
- type: 'text',
305
- text: JSON.stringify(accountInfo, null, 2),
306
- },
307
- ],
308
- };
309
- }
310
-
311
- case 'cosmos_query': {
312
- const module = toolInput.module as string;
313
- const subcommand = toolInput.subcommand as string;
314
- const args = parseArgs(toolInput.args);
315
-
316
- if (!module || !subcommand) {
317
- throw new ManifestMCPError(
318
- ManifestMCPErrorCode.QUERY_FAILED,
319
- 'module and subcommand are required'
320
- );
321
- }
322
-
323
- const result = await cosmosQuery(this.clientManager, module, subcommand, args);
324
-
325
- return {
326
- content: [
327
- {
328
- type: 'text',
329
- text: JSON.stringify(result, null, 2),
330
- },
331
- ],
332
- };
333
- }
334
-
335
- case 'cosmos_tx': {
336
- const module = toolInput.module as string;
337
- const subcommand = toolInput.subcommand as string;
338
- const args = parseArgs(toolInput.args);
339
- const waitForConfirmation = (toolInput.wait_for_confirmation as boolean) || false;
340
-
341
- if (!module || !subcommand || args.length === 0) {
342
- throw new ManifestMCPError(
343
- ManifestMCPErrorCode.TX_FAILED,
344
- 'module, subcommand, and args are required'
345
- );
346
- }
347
-
348
- const result = await cosmosTx(
349
- this.clientManager,
350
- module,
351
- subcommand,
352
- args,
353
- waitForConfirmation
354
- );
355
-
356
- return {
357
- content: [
358
- {
359
- type: 'text',
360
- text: JSON.stringify(result, null, 2),
361
- },
362
- ],
363
- };
364
- }
365
-
366
- case 'list_modules': {
367
- const modules = getAvailableModules();
368
- return {
369
- content: [
370
- {
371
- type: 'text',
372
- text: JSON.stringify(modules, null, 2),
373
- },
374
- ],
375
- };
376
- }
377
-
378
- case 'list_module_subcommands': {
379
- const type = toolInput.type as string;
380
- const module = toolInput.module as string;
381
-
382
- if (!type || !module) {
383
- throw new ManifestMCPError(
384
- ManifestMCPErrorCode.QUERY_FAILED,
385
- 'type and module are required'
386
- );
387
- }
388
-
389
- if (type !== 'query' && type !== 'tx') {
390
- throw new ManifestMCPError(
391
- ManifestMCPErrorCode.QUERY_FAILED,
392
- 'type must be either "query" or "tx"'
393
- );
394
- }
395
-
396
- const subcommands = getModuleSubcommands(type as 'query' | 'tx', module);
397
- return {
398
- content: [
399
- {
400
- type: 'text',
401
- text: JSON.stringify(
402
- {
403
- type,
404
- module,
405
- subcommands,
406
- },
407
- null,
408
- 2
409
- ),
410
- },
411
- ],
412
- };
413
- }
414
-
415
- default:
416
- throw new ManifestMCPError(
417
- ManifestMCPErrorCode.UNKNOWN_ERROR,
418
- `Unknown tool: ${toolName}`
419
- );
420
- }
421
- }
422
-
423
- /**
424
- * Get the underlying MCP server instance
425
- */
426
- getServer(): Server {
427
- return this.server;
428
- }
429
-
430
- /**
431
- * Get the client manager
432
- */
433
- getClientManager(): CosmosClientManager {
434
- return this.clientManager;
435
- }
436
-
437
- /**
438
- * Disconnect and clean up resources
439
- */
440
- disconnect(): void {
441
- this.clientManager.disconnect();
442
- }
443
- }
444
-
445
- /**
446
- * Create a ManifestMCPServer with mnemonic wallet (for testing or non-interactive use)
447
- *
448
- * @example
449
- * ```typescript
450
- * import { createMnemonicServer } from '@manifest-network/manifest-mcp-browser';
451
- *
452
- * const server = await createMnemonicServer({
453
- * chainId: 'manifest-ledger-testnet',
454
- * rpcUrl: 'https://nodes.chandrastation.com/rpc/manifest/',
455
- * gasPrice: '1.0umfx',
456
- * mnemonic: 'your twelve word mnemonic phrase here...',
457
- * });
458
- * ```
459
- */
460
- export async function createMnemonicServer(config: {
461
- chainId: string;
462
- rpcUrl: string;
463
- gasPrice: string;
464
- gasAdjustment?: number;
465
- addressPrefix?: string;
466
- mnemonic: string;
467
- }): Promise<ManifestMCPServer> {
468
- const { MnemonicWalletProvider } = await import('./wallet/mnemonic.js');
469
-
470
- const { mnemonic, ...mcpConfig } = config;
471
- const walletProvider = new MnemonicWalletProvider(mcpConfig, mnemonic);
472
- await walletProvider.connect();
473
-
474
- return new ManifestMCPServer({
475
- config: mcpConfig,
476
- walletProvider,
477
- });
478
- }
@@ -1,191 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- getAvailableModules,
4
- getModuleSubcommands,
5
- isSubcommandSupported,
6
- getSupportedModules,
7
- throwUnsupportedSubcommand,
8
- } from './modules.js';
9
- import { ManifestMCPError, ManifestMCPErrorCode } from './types.js';
10
-
11
- describe('getAvailableModules', () => {
12
- it('should return query and tx modules', () => {
13
- const modules = getAvailableModules();
14
-
15
- expect(modules.queryModules).toBeDefined();
16
- expect(modules.txModules).toBeDefined();
17
- expect(modules.queryModules.length).toBeGreaterThan(0);
18
- expect(modules.txModules.length).toBeGreaterThan(0);
19
- });
20
-
21
- it('should include expected query modules', () => {
22
- const modules = getAvailableModules();
23
- const queryNames = modules.queryModules.map(m => m.name);
24
-
25
- expect(queryNames).toContain('bank');
26
- expect(queryNames).toContain('staking');
27
- expect(queryNames).toContain('distribution');
28
- expect(queryNames).toContain('gov');
29
- expect(queryNames).toContain('auth');
30
- expect(queryNames).toContain('billing');
31
- expect(queryNames).toContain('sku');
32
- expect(queryNames).toContain('group');
33
- });
34
-
35
- it('should include expected tx modules', () => {
36
- const modules = getAvailableModules();
37
- const txNames = modules.txModules.map(m => m.name);
38
-
39
- expect(txNames).toContain('bank');
40
- expect(txNames).toContain('staking');
41
- expect(txNames).toContain('distribution');
42
- expect(txNames).toContain('gov');
43
- expect(txNames).toContain('billing');
44
- expect(txNames).toContain('manifest');
45
- expect(txNames).toContain('sku');
46
- expect(txNames).toContain('group');
47
- });
48
- });
49
-
50
- describe('getModuleSubcommands', () => {
51
- it('should return subcommands for valid query module', () => {
52
- const subcommands = getModuleSubcommands('query', 'bank');
53
-
54
- expect(subcommands.length).toBeGreaterThan(0);
55
- expect(subcommands.some(s => s.name === 'balance')).toBe(true);
56
- expect(subcommands.some(s => s.name === 'balances')).toBe(true);
57
- });
58
-
59
- it('should return subcommands for valid tx module', () => {
60
- const subcommands = getModuleSubcommands('tx', 'bank');
61
-
62
- expect(subcommands.length).toBeGreaterThan(0);
63
- expect(subcommands.some(s => s.name === 'send')).toBe(true);
64
- });
65
-
66
- it('should throw ManifestMCPError for unknown module', () => {
67
- expect(() => getModuleSubcommands('query', 'unknown')).toThrow(ManifestMCPError);
68
- });
69
-
70
- it('should have UNKNOWN_MODULE error code', () => {
71
- try {
72
- getModuleSubcommands('query', 'unknown');
73
- } catch (error) {
74
- expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.UNKNOWN_MODULE);
75
- }
76
- });
77
-
78
- it('should include aliases in subcommands', () => {
79
- const bankSubcommands = getModuleSubcommands('query', 'bank');
80
- expect(bankSubcommands.some(s => s.name === 'total')).toBe(true);
81
-
82
- const stakingSubcommands = getModuleSubcommands('tx', 'staking');
83
- expect(stakingSubcommands.some(s => s.name === 'undelegate')).toBe(true);
84
- });
85
- });
86
-
87
- describe('isSubcommandSupported', () => {
88
- it('should return true for supported query subcommands', () => {
89
- expect(isSubcommandSupported('query', 'bank', 'balance')).toBe(true);
90
- expect(isSubcommandSupported('query', 'staking', 'delegation')).toBe(true);
91
- });
92
-
93
- it('should return true for supported tx subcommands', () => {
94
- expect(isSubcommandSupported('tx', 'bank', 'send')).toBe(true);
95
- expect(isSubcommandSupported('tx', 'staking', 'delegate')).toBe(true);
96
- });
97
-
98
- it('should return false for unsupported subcommands', () => {
99
- expect(isSubcommandSupported('query', 'bank', 'unknown')).toBe(false);
100
- expect(isSubcommandSupported('tx', 'bank', 'unknown')).toBe(false);
101
- });
102
-
103
- it('should return false for unknown modules', () => {
104
- expect(isSubcommandSupported('query', 'unknown', 'balance')).toBe(false);
105
- expect(isSubcommandSupported('tx', 'unknown', 'send')).toBe(false);
106
- });
107
-
108
- it('should support aliases', () => {
109
- expect(isSubcommandSupported('query', 'bank', 'total')).toBe(true);
110
- expect(isSubcommandSupported('tx', 'staking', 'undelegate')).toBe(true);
111
- });
112
- });
113
-
114
- describe('getSupportedModules', () => {
115
- it('should return query and tx module maps', () => {
116
- const modules = getSupportedModules();
117
-
118
- expect(modules.query).toBeDefined();
119
- expect(modules.tx).toBeDefined();
120
- });
121
-
122
- it('should include subcommand arrays for each module', () => {
123
- const modules = getSupportedModules();
124
-
125
- expect(Array.isArray(modules.query.bank)).toBe(true);
126
- expect(modules.query.bank).toContain('balance');
127
- expect(modules.query.bank).toContain('balances');
128
-
129
- expect(Array.isArray(modules.tx.bank)).toBe(true);
130
- expect(modules.tx.bank).toContain('send');
131
- });
132
- });
133
-
134
- describe('throwUnsupportedSubcommand', () => {
135
- it('should throw ManifestMCPError for unsupported query subcommand', () => {
136
- expect(() => throwUnsupportedSubcommand('query', 'bank', 'unknown')).toThrow(ManifestMCPError);
137
- });
138
-
139
- it('should throw ManifestMCPError for unsupported tx subcommand', () => {
140
- expect(() => throwUnsupportedSubcommand('tx', 'bank', 'unknown')).toThrow(ManifestMCPError);
141
- });
142
-
143
- it('should use UNSUPPORTED_QUERY error code for queries', () => {
144
- try {
145
- throwUnsupportedSubcommand('query', 'bank', 'unknown');
146
- } catch (error) {
147
- expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.UNSUPPORTED_QUERY);
148
- }
149
- });
150
-
151
- it('should use UNSUPPORTED_TX error code for transactions', () => {
152
- try {
153
- throwUnsupportedSubcommand('tx', 'bank', 'unknown');
154
- } catch (error) {
155
- expect((error as ManifestMCPError).code).toBe(ManifestMCPErrorCode.UNSUPPORTED_TX);
156
- }
157
- });
158
-
159
- it('should include module and subcommand in error message', () => {
160
- try {
161
- throwUnsupportedSubcommand('query', 'staking', 'badcmd');
162
- } catch (error) {
163
- const message = (error as ManifestMCPError).message;
164
- expect(message).toContain('staking');
165
- expect(message).toContain('badcmd');
166
- expect(message).toContain('query');
167
- }
168
- });
169
-
170
- it('should include availableSubcommands in error details', () => {
171
- try {
172
- throwUnsupportedSubcommand('tx', 'bank', 'unknown');
173
- } catch (error) {
174
- const details = (error as ManifestMCPError).details;
175
- expect(details?.availableSubcommands).toBeDefined();
176
- expect(details?.availableSubcommands).toContain('send');
177
- expect(details?.availableSubcommands).toContain('multi-send');
178
- }
179
- });
180
-
181
- it('should include correct subcommands for each module', () => {
182
- try {
183
- throwUnsupportedSubcommand('query', 'gov', 'unknown');
184
- } catch (error) {
185
- const details = (error as ManifestMCPError).details;
186
- expect(details?.availableSubcommands).toContain('proposal');
187
- expect(details?.availableSubcommands).toContain('proposals');
188
- expect(details?.availableSubcommands).toContain('vote');
189
- }
190
- });
191
- });