@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 +20 -1
- package/dist/tools/apiManager/index.js +5 -4
- package/dist/tools/apiManager/pera/asset.d.ts +3 -0
- package/dist/tools/apiManager/pera/asset.js +122 -0
- package/dist/tools/apiManager/pera/index.d.ts +3 -0
- package/dist/tools/apiManager/pera/index.js +17 -0
- package/dist/tools/utilityManager.js +1 -1
- package/package.json +1 -1
- package/dist/tools/apiManager/example/get-balance.d.ts +0 -11
- package/dist/tools/apiManager/example/get-balance.js +0 -32
- package/dist/tools/apiManager/example/index.d.ts +0 -6
- package/dist/tools/apiManager/example/index.js +0 -18
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
|
-
│ │
|
|
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
|
-
...
|
|
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
|
-
|
|
45
|
-
|
|
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,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,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.
|
|
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,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
|
-
}
|