@goplausible/algorand-mcp 3.1.1 → 3.2.1

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 CHANGED
@@ -501,6 +501,24 @@ See [Secure Wallet](#secure-wallet) for full architecture details.
501
501
  | `api_tinyman_get_validator_optin_quote` | Get quote for validator opt-in |
502
502
  | `api_tinyman_get_validator_optout_quote` | Get quote for validator opt-out |
503
503
 
504
+ ### Haystack Router Tools (3 tools)
505
+
506
+ | Tool | Description |
507
+ |---|---|
508
+ | `api_haystack_get_swap_quote` | Get optimized swap quote with routing across Tinyman V2, Pact, Folks, and LST protocols |
509
+ | `api_haystack_execute_swap` | All-in-one swap: quote → sign (via wallet) → submit → confirm |
510
+ | `api_haystack_needs_optin` | Check if address needs asset opt-in before swapping |
511
+
512
+ ### Pera Wallet Tools (3 tools)
513
+
514
+ | Tool | Description |
515
+ |---|---|
516
+ | `api_pera_asset_verification_status` | Get verification status of a mainnet asset (verified, trusted, suspicious, unknown) |
517
+ | `api_pera_verified_asset_details` | Get detailed asset info from Pera (name, unit, logo, decimals, verification) |
518
+ | `api_pera_verified_asset_search` | Search Pera verified assets by name, unit name, or keyword |
519
+
520
+ > Pera Wallet tools are **mainnet only** — the Pera public API does not support testnet or localnet.
521
+
504
522
  ### ARC-26 URI Tools (1 tool)
505
523
 
506
524
  | Tool | Description |
@@ -567,7 +585,8 @@ algorand-mcp/
567
585
  │ │ ├── indexer/ # Indexer API
568
586
  │ │ ├── nfd/ # NFDomains
569
587
  │ │ ├── tinyman/ # Tinyman AMM
570
- │ │ └── example/ # Example tools
588
+ │ │ ├── hayrouter/ # Haystack Router DEX aggregator
589
+ │ │ └── pera/ # Pera Wallet verified assets
571
590
  │ └── utils/
572
591
  │ └── responseProcessor.ts # Pagination and formatting
573
592
  ├── tests/ # Test suite
@@ -4,8 +4,8 @@ import { nfdTools, handleNFDTools } from './nfd/index.js';
4
4
  // import { vestigeTools, handleVestigeTools } from './vestige/index.js';
5
5
  import { tinymanTools, handleTinymanTools } from './tinyman/index.js';
6
6
  // import { ultradeTools, handleUltradeTools } from './ultrade/index.js';
7
- import { exampleTools, handleExampleTools } from './example/index.js';
8
7
  import { haystackTools, handleHaystackTools } from './hayrouter/index.js';
8
+ import { peraTools, handlePeraTools } from './pera/index.js';
9
9
  import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
10
10
  import { ResponseProcessor } from '../../utils/responseProcessor.js';
11
11
  // Combine all API tools
@@ -15,7 +15,7 @@ export const apiManager = [
15
15
  ...nfdTools,
16
16
  ...tinymanTools,
17
17
  ...haystackTools,
18
- ...exampleTools
18
+ ...peraTools
19
19
  ];
20
20
  // Handle all API tools
21
21
  export async function handleApiManager(name, args) {
@@ -41,8 +41,9 @@ export async function handleApiManager(name, args) {
41
41
  else if (name.startsWith('api_haystack_')) {
42
42
  response = await handleHaystackTools(name, args);
43
43
  }
44
- else if (name.startsWith('api_example_')) {
45
- response = await handleExampleTools(name, args);
44
+ // Pera Wallet tools
45
+ else if (name.startsWith('api_pera_')) {
46
+ response = await handlePeraTools(name, args);
46
47
  }
47
48
  else {
48
49
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const peraAssetTools: Tool[];
3
+ export declare function handlePeraAssetTools(args: any): Promise<any>;
@@ -0,0 +1,122 @@
1
+ import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
2
+ const PERA_API_BASE = 'https://mainnet.api.perawallet.app/v1/public';
3
+ export const peraAssetTools = [
4
+ {
5
+ name: 'api_pera_asset_verification_status',
6
+ description: 'Get the verification status of an Algorand mainnet asset from Pera Wallet. Returns verification tier (verified, trusted, suspicious, unverified) and explorer URL.',
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ assetId: {
11
+ type: 'integer',
12
+ description: 'Asset ID to check verification status',
13
+ },
14
+ },
15
+ required: ['assetId'],
16
+ },
17
+ },
18
+ {
19
+ name: 'api_pera_verified_asset_details',
20
+ description: 'Get detailed information about an Algorand mainnet asset from Pera Wallet, including name, unit name, decimals, total supply, USD value, logo, verification tier, and collectible status.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ assetId: {
25
+ type: 'integer',
26
+ description: 'Asset ID to get detailed information',
27
+ },
28
+ },
29
+ required: ['assetId'],
30
+ },
31
+ },
32
+ {
33
+ name: 'api_pera_verified_asset_search',
34
+ description: 'Search Pera Wallet verified Algorand mainnet assets by name, unit name, or keyword. Returns matching assets with verification status, USD value, and logo.',
35
+ inputSchema: {
36
+ type: 'object',
37
+ properties: {
38
+ query: {
39
+ type: 'string',
40
+ description: 'Search query — asset name, unit name, or keyword',
41
+ },
42
+ verifiedOnly: {
43
+ type: 'boolean',
44
+ description: 'If true, only return assets with "verified" or "trusted" tier (default: false)',
45
+ },
46
+ },
47
+ required: ['query'],
48
+ },
49
+ },
50
+ ];
51
+ export async function handlePeraAssetTools(args) {
52
+ const name = args.name;
53
+ switch (name) {
54
+ case 'api_pera_asset_verification_status': {
55
+ const { assetId } = args;
56
+ if (!assetId && assetId !== 0) {
57
+ throw new McpError(ErrorCode.InvalidParams, 'assetId is required');
58
+ }
59
+ const response = await fetch(`${PERA_API_BASE}/asset-verifications/${assetId}/`);
60
+ if (!response.ok) {
61
+ if (response.status === 404) {
62
+ return {
63
+ asset_id: assetId,
64
+ verification_tier: 'unverified',
65
+ explorer_url: `https://explorer.perawallet.app/asset/${assetId}/`,
66
+ message: 'Asset not found in Pera verification database',
67
+ };
68
+ }
69
+ throw new McpError(ErrorCode.InternalError, `Pera API request failed with status: ${response.status}`);
70
+ }
71
+ const data = await response.json();
72
+ return {
73
+ asset_id: data.asset_id,
74
+ verification_tier: data.verification_tier,
75
+ explorer_url: data.explorer_url,
76
+ };
77
+ }
78
+ case 'api_pera_verified_asset_details': {
79
+ const { assetId } = args;
80
+ if (!assetId && assetId !== 0) {
81
+ throw new McpError(ErrorCode.InvalidParams, 'assetId is required');
82
+ }
83
+ const response = await fetch(`${PERA_API_BASE}/assets/${assetId}/`);
84
+ if (!response.ok) {
85
+ if (response.status === 404) {
86
+ throw new McpError(ErrorCode.InvalidParams, `Asset with ID ${assetId} not found in Pera Wallet database`);
87
+ }
88
+ throw new McpError(ErrorCode.InternalError, `Pera API request failed with status: ${response.status}`);
89
+ }
90
+ return await response.json();
91
+ }
92
+ case 'api_pera_verified_asset_search': {
93
+ const { query, verifiedOnly } = args;
94
+ if (!query) {
95
+ throw new McpError(ErrorCode.InvalidParams, 'query is required');
96
+ }
97
+ const url = `${PERA_API_BASE}/assets/?search=${encodeURIComponent(query)}&limit=50&has_collectible=false`;
98
+ const response = await fetch(url);
99
+ if (!response.ok) {
100
+ throw new McpError(ErrorCode.InternalError, `Pera API search failed with status: ${response.status}`);
101
+ }
102
+ const data = await response.json();
103
+ let results = data.results || [];
104
+ if (verifiedOnly) {
105
+ results = results.filter((a) => a.verification_tier === 'verified' || a.verification_tier === 'trusted');
106
+ }
107
+ return results.map((a) => ({
108
+ asset_id: a.asset_id,
109
+ name: a.name,
110
+ unit_name: a.unit_name,
111
+ decimals: a.fraction_decimals,
112
+ verification_tier: a.verification_tier,
113
+ usd_value: a.usd_value,
114
+ logo: a.logo,
115
+ creator_address: a.creator_address,
116
+ is_deleted: a.is_deleted,
117
+ }));
118
+ }
119
+ default:
120
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown Pera tool: ${name}`);
121
+ }
122
+ }
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const peraTools: Tool[];
3
+ export declare function handlePeraTools(name: string, args: any): Promise<any>;
@@ -0,0 +1,17 @@
1
+ import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
2
+ import { peraAssetTools, handlePeraAssetTools } from './asset.js';
3
+ export const peraTools = [
4
+ ...peraAssetTools,
5
+ ];
6
+ export async function handlePeraTools(name, args) {
7
+ try {
8
+ const combinedArgs = { name, ...args };
9
+ return handlePeraAssetTools(combinedArgs);
10
+ }
11
+ catch (error) {
12
+ if (error instanceof McpError) {
13
+ throw error;
14
+ }
15
+ throw new McpError(ErrorCode.InternalError, `Failed to handle Pera tool: ${error instanceof Error ? error.message : String(error)}`);
16
+ }
17
+ }
@@ -86,7 +86,7 @@ export class UtilityManager {
86
86
  type: 'text',
87
87
  text: JSON.stringify({
88
88
  name: 'Algorand MCP Server',
89
- version: '3.1.1',
89
+ version: '3.2.1',
90
90
  builder: 'GoPlausible',
91
91
  description: 'A Model Context Protocol (MCP) server providing comprehensive access to the Algorand blockchain. Supports account management, transaction building and signing, smart contract interaction, asset operations, ARC-26 URI generation, and deep integration with Algorand ecosystem services including NFDomains, Tinyman, Vestige, and Ultrade.',
92
92
  blockchain: 'Algorand — a carbon-negative, pure proof-of-stake Layer 1 blockchain delivering instant finality, low fees, and advanced smart contract capabilities via AVM (Algorand Virtual Machine).',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goplausible/algorand-mcp",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,11 +0,0 @@
1
- export declare const getBalanceToolSchema: {
2
- type: string;
3
- properties: {
4
- address: {
5
- type: string;
6
- description: string;
7
- };
8
- };
9
- required: string[];
10
- };
11
- export declare const getBalanceTool: (args: Record<string, unknown>) => Promise<import("algosdk/dist/types/client/v2/algod/models/types.js").Account>;
@@ -1,32 +0,0 @@
1
- import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
2
- import { getAlgodClient, extractNetwork } from '../../../algorand-client.js';
3
- export const getBalanceToolSchema = {
4
- type: 'object',
5
- properties: {
6
- address: {
7
- type: 'string',
8
- description: 'Algorand address in standard format (58 characters)',
9
- },
10
- },
11
- required: ['address'],
12
- };
13
- export const getBalanceTool = async (args) => {
14
- try {
15
- if (!args.address) {
16
- throw new McpError(ErrorCode.InvalidParams, 'Missing required parameter: address');
17
- }
18
- if (!/^[A-Z2-7]{58}$/.test(args.address)) {
19
- throw new McpError(ErrorCode.InvalidParams, 'Invalid Algorand address format');
20
- }
21
- const network = extractNetwork(args);
22
- const algodClient = getAlgodClient(network);
23
- const accountInfo = await algodClient.accountInformation(args.address).do();
24
- return accountInfo;
25
- }
26
- catch (error) {
27
- if (error instanceof McpError)
28
- throw error;
29
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
30
- throw new McpError(ErrorCode.InternalError, `Failed to get account balance: ${errorMessage}`);
31
- }
32
- };
@@ -1,6 +0,0 @@
1
- export declare const exampleTools: {
2
- name: string;
3
- description: string;
4
- inputSchema: any;
5
- }[];
6
- export declare function handleExampleTools(name: string, args: Record<string, unknown>): Promise<import("algosdk/dist/types/client/v2/algod/models/types.js").Account>;
@@ -1,18 +0,0 @@
1
- import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
2
- import { getBalanceTool, getBalanceToolSchema } from './get-balance.js';
3
- import { withCommonParams } from '../../commonParams.js';
4
- export const exampleTools = [
5
- {
6
- name: 'api_example_get_balance',
7
- description: 'Get account balance and assets',
8
- inputSchema: withCommonParams(getBalanceToolSchema),
9
- },
10
- ];
11
- export async function handleExampleTools(name, args) {
12
- switch (name) {
13
- case 'api_example_get_balance':
14
- return getBalanceTool(args);
15
- default:
16
- throw new McpError(ErrorCode.MethodNotFound, `Unknown example tool: ${name}`);
17
- }
18
- }