@avakit/mcp 0.1.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.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/index.js +221 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AvaKit contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @avakit/mcp
|
|
2
|
+
|
|
3
|
+
The [AvaKit](https://github.com/mericcintosun/AvaKit) MCP server — scaffold, deploy, and read Avalanche from Claude Code / Cursor over the [Model Context Protocol](https://modelcontextprotocol.io).
|
|
4
|
+
|
|
5
|
+
Unlike docs-only servers, this exposes **actions**: it can create a dapp, deploy a contract, and read chain state.
|
|
6
|
+
|
|
7
|
+
## Add to your MCP client
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"avakit": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "@avakit/mcp"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Works with Claude Code, Cursor, and Claude Desktop.
|
|
21
|
+
|
|
22
|
+
## Tools
|
|
23
|
+
|
|
24
|
+
| Tool | Description |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `scaffold_app` | Create an Avalanche dapp from a template (minimal, nft-mint, token-gated-app) |
|
|
27
|
+
| `list_templates` | List available templates |
|
|
28
|
+
| `read_chain` | Read a balance, a transaction receipt, or a contract view function |
|
|
29
|
+
| `deploy_contract` | Deploy compiled bytecode (Fuji by default; mainnet requires `confirm: true`) |
|
|
30
|
+
| `get_context` | AvaKit + Avalanche coding context and doc links |
|
|
31
|
+
|
|
32
|
+
## Deploy key
|
|
33
|
+
|
|
34
|
+
`deploy_contract` signs with a private key from the `AVAKIT_DEPLOYER_KEY` environment variable. Use a **throwaway testnet key** — never a key holding real funds. Mainnet deploys require an explicit `confirm: true`.
|
|
35
|
+
|
|
36
|
+
MIT © AvaKit contributors
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { existsSync, readdirSync } from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import {
|
|
7
|
+
cChain,
|
|
8
|
+
fuji,
|
|
9
|
+
getBalance,
|
|
10
|
+
getPublicClient,
|
|
11
|
+
getTransactionReceipt,
|
|
12
|
+
readContract,
|
|
13
|
+
toViemChain
|
|
14
|
+
} from "@avakit/core";
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
+
import { listTemplates, scaffoldApp } from "create-avalanche-app/api";
|
|
18
|
+
import { createWalletClient, http } from "viem";
|
|
19
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
function chainFrom(id) {
|
|
22
|
+
return id === "c-chain" ? cChain : fuji;
|
|
23
|
+
}
|
|
24
|
+
function toJson(value) {
|
|
25
|
+
return JSON.stringify(value, (_key, val) => typeof val === "bigint" ? val.toString() : val, 2);
|
|
26
|
+
}
|
|
27
|
+
function text(body, isError = false) {
|
|
28
|
+
return { content: [{ type: "text", text: body }], isError };
|
|
29
|
+
}
|
|
30
|
+
var server = new McpServer({ name: "avakit-mcp", version: "0.1.0" });
|
|
31
|
+
server.registerTool(
|
|
32
|
+
"list_templates",
|
|
33
|
+
{
|
|
34
|
+
title: "List templates",
|
|
35
|
+
description: "List the Avalanche dapp templates available to scaffold_app.",
|
|
36
|
+
inputSchema: {}
|
|
37
|
+
},
|
|
38
|
+
async () => text(toJson(listTemplates()))
|
|
39
|
+
);
|
|
40
|
+
server.registerTool(
|
|
41
|
+
"scaffold_app",
|
|
42
|
+
{
|
|
43
|
+
title: "Scaffold an Avalanche dapp",
|
|
44
|
+
description: "Create a new Avalanche dapp from a template (minimal, nft-mint, token-gated-app). Wraps create-avalanche-app. Returns the created files and next steps.",
|
|
45
|
+
inputSchema: {
|
|
46
|
+
name: z.string().describe("Project directory name, e.g. my-avax-app"),
|
|
47
|
+
template: z.enum(["minimal", "nft-mint", "token-gated-app", "erc20-token"]).default("minimal"),
|
|
48
|
+
chain: z.enum(["fuji", "c-chain"]).default("fuji"),
|
|
49
|
+
wallet: z.enum(["web3auth", "injected"]).default("web3auth"),
|
|
50
|
+
directory: z.string().optional().describe("Parent directory (default: cwd)"),
|
|
51
|
+
local: z.boolean().optional().describe("Link @avakit/* via workspace (repo dev only)")
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async ({ name, template, chain, wallet, directory, local }) => {
|
|
55
|
+
const parent = directory ? path.resolve(directory) : process.cwd();
|
|
56
|
+
const targetDir = path.resolve(parent, name);
|
|
57
|
+
if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {
|
|
58
|
+
return text(`Directory "${targetDir}" already exists and is not empty.`, true);
|
|
59
|
+
}
|
|
60
|
+
const { files } = await scaffoldApp({
|
|
61
|
+
projectName: name,
|
|
62
|
+
targetDir,
|
|
63
|
+
template,
|
|
64
|
+
chain,
|
|
65
|
+
wallet,
|
|
66
|
+
local
|
|
67
|
+
});
|
|
68
|
+
const nextSteps = [
|
|
69
|
+
`cd ${name}`,
|
|
70
|
+
"pnpm install",
|
|
71
|
+
...wallet === "web3auth" ? ["cp .env.example .env.local # add Web3Auth client ID"] : [],
|
|
72
|
+
"pnpm dev"
|
|
73
|
+
];
|
|
74
|
+
return text(toJson({ path: targetDir, filesCreated: files.length, files, nextSteps }));
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
server.registerTool(
|
|
78
|
+
"read_chain",
|
|
79
|
+
{
|
|
80
|
+
title: "Read Avalanche chain data",
|
|
81
|
+
description: "Read a native AVAX balance, a transaction receipt, or a contract view/pure function over RPC.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
action: z.enum(["balance", "txReceipt", "contractRead"]),
|
|
84
|
+
chain: z.enum(["fuji", "c-chain"]).default("fuji"),
|
|
85
|
+
address: z.string().optional().describe("Address for balance / contractRead"),
|
|
86
|
+
hash: z.string().optional().describe("Tx hash for txReceipt"),
|
|
87
|
+
abi: z.array(z.any()).optional().describe("Contract ABI for contractRead"),
|
|
88
|
+
functionName: z.string().optional().describe("View function for contractRead"),
|
|
89
|
+
args: z.array(z.any()).optional()
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
async ({ action, chain, address, hash, abi, functionName, args }) => {
|
|
93
|
+
const c = chainFrom(chain);
|
|
94
|
+
try {
|
|
95
|
+
if (action === "balance") {
|
|
96
|
+
if (!address) return text("balance requires 'address'.", true);
|
|
97
|
+
const wei = await getBalance(address, c);
|
|
98
|
+
return text(toJson({ address, chain: c.name, wei, avax: (Number(wei) / 1e18).toString() }));
|
|
99
|
+
}
|
|
100
|
+
if (action === "txReceipt") {
|
|
101
|
+
if (!hash) return text("txReceipt requires 'hash'.", true);
|
|
102
|
+
return text(toJson(await getTransactionReceipt(hash, c)));
|
|
103
|
+
}
|
|
104
|
+
if (!address || !abi || !functionName) {
|
|
105
|
+
return text("contractRead requires 'address', 'abi', and 'functionName'.", true);
|
|
106
|
+
}
|
|
107
|
+
const result = await readContract(c, {
|
|
108
|
+
address,
|
|
109
|
+
abi,
|
|
110
|
+
functionName,
|
|
111
|
+
args
|
|
112
|
+
});
|
|
113
|
+
return text(toJson(result));
|
|
114
|
+
} catch (e) {
|
|
115
|
+
return text(`read_chain failed: ${e instanceof Error ? e.message : String(e)}`, true);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
server.registerTool(
|
|
120
|
+
"deploy_contract",
|
|
121
|
+
{
|
|
122
|
+
title: "Deploy a contract",
|
|
123
|
+
description: "Deploy compiled bytecode to Avalanche using a deployer key from the AVAKIT_DEPLOYER_KEY env var. Fuji testnet by default; mainnet (c-chain) requires confirm:true.",
|
|
124
|
+
inputSchema: {
|
|
125
|
+
abi: z.array(z.any()),
|
|
126
|
+
bytecode: z.string().describe("Creation bytecode (0x-prefixed)"),
|
|
127
|
+
args: z.array(z.any()).optional(),
|
|
128
|
+
chain: z.enum(["fuji", "c-chain"]).default("fuji"),
|
|
129
|
+
confirm: z.boolean().optional().describe("Required to deploy to mainnet")
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async ({ abi, bytecode, args, chain, confirm }) => {
|
|
133
|
+
const c = chainFrom(chain);
|
|
134
|
+
if (!c.testnet && !confirm) {
|
|
135
|
+
return text(`Refusing to deploy to ${c.name} (mainnet) without confirm:true.`, true);
|
|
136
|
+
}
|
|
137
|
+
const key = process.env.AVAKIT_DEPLOYER_KEY;
|
|
138
|
+
if (!key) {
|
|
139
|
+
return text(
|
|
140
|
+
"No deployer key found. Set AVAKIT_DEPLOYER_KEY to a 0x private key (use a throwaway testnet key \u2014 never a key holding real funds).",
|
|
141
|
+
true
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const account = privateKeyToAccount(key);
|
|
146
|
+
const viemChain = toViemChain(c);
|
|
147
|
+
const wallet = createWalletClient({ account, chain: viemChain, transport: http(c.rpcUrl) });
|
|
148
|
+
const publicClient = getPublicClient(c);
|
|
149
|
+
const bc = bytecode.startsWith("0x") ? bytecode : `0x${bytecode}`;
|
|
150
|
+
const txHash = await wallet.deployContract({
|
|
151
|
+
abi,
|
|
152
|
+
bytecode: bc,
|
|
153
|
+
args,
|
|
154
|
+
account,
|
|
155
|
+
chain: viemChain
|
|
156
|
+
});
|
|
157
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
158
|
+
if (!receipt.contractAddress) {
|
|
159
|
+
return text("Deployment did not return a contract address.", true);
|
|
160
|
+
}
|
|
161
|
+
return text(
|
|
162
|
+
toJson({
|
|
163
|
+
address: receipt.contractAddress,
|
|
164
|
+
txHash,
|
|
165
|
+
explorerUrl: `${c.explorerUrl}/address/${receipt.contractAddress}`
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
return text(`deploy failed: ${e instanceof Error ? e.message : String(e)}`, true);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
var AVAKIT_CONTEXT = `# AvaKit context
|
|
174
|
+
|
|
175
|
+
AvaKit is an open-source, AI-native Avalanche developer toolkit.
|
|
176
|
+
|
|
177
|
+
## Scaffolding
|
|
178
|
+
- \`scaffold_app\` (this MCP) or \`npm create avalanche-app@latest\`
|
|
179
|
+
- Templates: minimal, nft-mint, token-gated-app
|
|
180
|
+
- Each app ships shadcn/ui (black & white + dark/light), social-login wallet, and CLAUDE.md/llms.txt/.cursor rules.
|
|
181
|
+
|
|
182
|
+
## @avakit/react
|
|
183
|
+
- \`<AvaKitProvider chains={[...]} adapters={[...]}>\`, \`<ConnectAvalanche />\`
|
|
184
|
+
- Hooks: useAvaAccount, useAvaChain, useBalance, useContract, useAvaDeploy, useAvaKit
|
|
185
|
+
|
|
186
|
+
## @avakit/core
|
|
187
|
+
- Chains: fuji, cChain, defineChain (from @avakit/core/chains)
|
|
188
|
+
- Adapters: injectedAdapter(), web3authAdapter({ clientId }) (from @avakit/core/web3auth)
|
|
189
|
+
- getPublicClient, getWalletClient, ensureChain, deployContract, getBalance, readContract
|
|
190
|
+
|
|
191
|
+
## Conventions
|
|
192
|
+
- UI: shadcn/ui only. Black & white until brand colors are added; dark/light from day one.
|
|
193
|
+
- Chains: Fuji testnet by default; mainnet is explicit opt-in.
|
|
194
|
+
- Secrets: never in code. Web3Auth client ID (free) in NEXT_PUBLIC_WEB3AUTH_CLIENT_ID.
|
|
195
|
+
|
|
196
|
+
## Docs
|
|
197
|
+
- Avalanche Builder Hub: https://build.avax.network/llms.txt
|
|
198
|
+
- Web3Auth dashboard: https://dashboard.web3auth.io
|
|
199
|
+
- Fuji faucet: https://core.app/tools/testnet-faucet`;
|
|
200
|
+
server.registerTool(
|
|
201
|
+
"get_context",
|
|
202
|
+
{
|
|
203
|
+
title: "Get AvaKit context",
|
|
204
|
+
description: "Return AvaKit + Avalanche context for coding: the API surface, conventions, and doc links.",
|
|
205
|
+
inputSchema: { topic: z.string().optional().describe("Optional focus topic") }
|
|
206
|
+
},
|
|
207
|
+
async ({ topic }) => text(topic ? `${AVAKIT_CONTEXT}
|
|
208
|
+
|
|
209
|
+
(Requested focus: ${topic})` : AVAKIT_CONTEXT)
|
|
210
|
+
);
|
|
211
|
+
async function main() {
|
|
212
|
+
const transport = new StdioServerTransport();
|
|
213
|
+
await server.connect(transport);
|
|
214
|
+
process.stderr.write("avakit-mcp running on stdio\n");
|
|
215
|
+
}
|
|
216
|
+
main().catch((error) => {
|
|
217
|
+
process.stderr.write(`avakit-mcp fatal: ${String(error)}
|
|
218
|
+
`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
});
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @avakit/mcp — AvaKit MCP server (stdio).\n *\n * Exposes Avalanche *actions* (not just docs) to AI coding agents:\n * • scaffold_app — create a dapp from a template (wraps create-avalanche-app)\n * • list_templates — available templates\n * • read_chain — balance / tx receipt / contract view\n * • deploy_contract — deploy compiled bytecode (testnet-first, mainnet needs confirm)\n * • get_context — AvaKit + Avalanche coding context\n *\n * See docs/09-spec-mcp.md. Guardrails: private keys only ever come from the\n * AVAKIT_DEPLOYER_KEY env var, are never logged, and mainnet deploys require\n * explicit confirmation.\n */\n\nimport { existsSync, readdirSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n type AvaChain,\n cChain,\n fuji,\n getBalance,\n getPublicClient,\n getTransactionReceipt,\n readContract,\n toViemChain,\n} from \"@avakit/core\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { listTemplates, scaffoldApp } from \"create-avalanche-app/api\";\nimport { type Abi, type Address, createWalletClient, type Hex, http } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { z } from \"zod\";\n\nfunction chainFrom(id: string | undefined): AvaChain {\n return id === \"c-chain\" ? cChain : fuji;\n}\n\nfunction toJson(value: unknown): string {\n return JSON.stringify(value, (_key, val) => (typeof val === \"bigint\" ? val.toString() : val), 2);\n}\n\nfunction text(body: string, isError = false) {\n return { content: [{ type: \"text\" as const, text: body }], isError };\n}\n\nconst server = new McpServer({ name: \"avakit-mcp\", version: \"0.1.0\" });\n\nserver.registerTool(\n \"list_templates\",\n {\n title: \"List templates\",\n description: \"List the Avalanche dapp templates available to scaffold_app.\",\n inputSchema: {},\n },\n async () => text(toJson(listTemplates())),\n);\n\nserver.registerTool(\n \"scaffold_app\",\n {\n title: \"Scaffold an Avalanche dapp\",\n description:\n \"Create a new Avalanche dapp from a template (minimal, nft-mint, token-gated-app). Wraps create-avalanche-app. Returns the created files and next steps.\",\n inputSchema: {\n name: z.string().describe(\"Project directory name, e.g. my-avax-app\"),\n template: z\n .enum([\"minimal\", \"nft-mint\", \"token-gated-app\", \"erc20-token\"])\n .default(\"minimal\"),\n chain: z.enum([\"fuji\", \"c-chain\"]).default(\"fuji\"),\n wallet: z.enum([\"web3auth\", \"injected\"]).default(\"web3auth\"),\n directory: z.string().optional().describe(\"Parent directory (default: cwd)\"),\n local: z.boolean().optional().describe(\"Link @avakit/* via workspace (repo dev only)\"),\n },\n },\n async ({ name, template, chain, wallet, directory, local }) => {\n const parent = directory ? path.resolve(directory) : process.cwd();\n const targetDir = path.resolve(parent, name);\n if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n return text(`Directory \"${targetDir}\" already exists and is not empty.`, true);\n }\n const { files } = await scaffoldApp({\n projectName: name,\n targetDir,\n template,\n chain,\n wallet,\n local,\n });\n const nextSteps = [\n `cd ${name}`,\n \"pnpm install\",\n ...(wallet === \"web3auth\" ? [\"cp .env.example .env.local # add Web3Auth client ID\"] : []),\n \"pnpm dev\",\n ];\n return text(toJson({ path: targetDir, filesCreated: files.length, files, nextSteps }));\n },\n);\n\nserver.registerTool(\n \"read_chain\",\n {\n title: \"Read Avalanche chain data\",\n description:\n \"Read a native AVAX balance, a transaction receipt, or a contract view/pure function over RPC.\",\n inputSchema: {\n action: z.enum([\"balance\", \"txReceipt\", \"contractRead\"]),\n chain: z.enum([\"fuji\", \"c-chain\"]).default(\"fuji\"),\n address: z.string().optional().describe(\"Address for balance / contractRead\"),\n hash: z.string().optional().describe(\"Tx hash for txReceipt\"),\n abi: z.array(z.any()).optional().describe(\"Contract ABI for contractRead\"),\n functionName: z.string().optional().describe(\"View function for contractRead\"),\n args: z.array(z.any()).optional(),\n },\n },\n async ({ action, chain, address, hash, abi, functionName, args }) => {\n const c = chainFrom(chain);\n try {\n if (action === \"balance\") {\n if (!address) return text(\"balance requires 'address'.\", true);\n const wei = await getBalance(address as Address, c);\n return text(toJson({ address, chain: c.name, wei, avax: (Number(wei) / 1e18).toString() }));\n }\n if (action === \"txReceipt\") {\n if (!hash) return text(\"txReceipt requires 'hash'.\", true);\n return text(toJson(await getTransactionReceipt(hash as Hex, c)));\n }\n if (!address || !abi || !functionName) {\n return text(\"contractRead requires 'address', 'abi', and 'functionName'.\", true);\n }\n const result = await readContract(c, {\n address: address as Address,\n abi: abi as Abi,\n functionName: functionName as never,\n args,\n });\n return text(toJson(result));\n } catch (e) {\n return text(`read_chain failed: ${e instanceof Error ? e.message : String(e)}`, true);\n }\n },\n);\n\nserver.registerTool(\n \"deploy_contract\",\n {\n title: \"Deploy a contract\",\n description:\n \"Deploy compiled bytecode to Avalanche using a deployer key from the AVAKIT_DEPLOYER_KEY env var. Fuji testnet by default; mainnet (c-chain) requires confirm:true.\",\n inputSchema: {\n abi: z.array(z.any()),\n bytecode: z.string().describe(\"Creation bytecode (0x-prefixed)\"),\n args: z.array(z.any()).optional(),\n chain: z.enum([\"fuji\", \"c-chain\"]).default(\"fuji\"),\n confirm: z.boolean().optional().describe(\"Required to deploy to mainnet\"),\n },\n },\n async ({ abi, bytecode, args, chain, confirm }) => {\n const c = chainFrom(chain);\n if (!c.testnet && !confirm) {\n return text(`Refusing to deploy to ${c.name} (mainnet) without confirm:true.`, true);\n }\n const key = process.env.AVAKIT_DEPLOYER_KEY;\n if (!key) {\n return text(\n \"No deployer key found. Set AVAKIT_DEPLOYER_KEY to a 0x private key (use a throwaway testnet key — never a key holding real funds).\",\n true,\n );\n }\n try {\n const account = privateKeyToAccount(key as Hex);\n const viemChain = toViemChain(c);\n const wallet = createWalletClient({ account, chain: viemChain, transport: http(c.rpcUrl) });\n const publicClient = getPublicClient(c);\n const bc = bytecode.startsWith(\"0x\") ? (bytecode as Hex) : (`0x${bytecode}` as Hex);\n const txHash = await wallet.deployContract({\n abi: abi as Abi,\n bytecode: bc,\n args,\n account,\n chain: viemChain,\n } as never);\n const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });\n if (!receipt.contractAddress) {\n return text(\"Deployment did not return a contract address.\", true);\n }\n return text(\n toJson({\n address: receipt.contractAddress,\n txHash,\n explorerUrl: `${c.explorerUrl}/address/${receipt.contractAddress}`,\n }),\n );\n } catch (e) {\n return text(`deploy failed: ${e instanceof Error ? e.message : String(e)}`, true);\n }\n },\n);\n\nconst AVAKIT_CONTEXT = `# AvaKit context\n\nAvaKit is an open-source, AI-native Avalanche developer toolkit.\n\n## Scaffolding\n- \\`scaffold_app\\` (this MCP) or \\`npm create avalanche-app@latest\\`\n- Templates: minimal, nft-mint, token-gated-app\n- Each app ships shadcn/ui (black & white + dark/light), social-login wallet, and CLAUDE.md/llms.txt/.cursor rules.\n\n## @avakit/react\n- \\`<AvaKitProvider chains={[...]} adapters={[...]}>\\`, \\`<ConnectAvalanche />\\`\n- Hooks: useAvaAccount, useAvaChain, useBalance, useContract, useAvaDeploy, useAvaKit\n\n## @avakit/core\n- Chains: fuji, cChain, defineChain (from @avakit/core/chains)\n- Adapters: injectedAdapter(), web3authAdapter({ clientId }) (from @avakit/core/web3auth)\n- getPublicClient, getWalletClient, ensureChain, deployContract, getBalance, readContract\n\n## Conventions\n- UI: shadcn/ui only. Black & white until brand colors are added; dark/light from day one.\n- Chains: Fuji testnet by default; mainnet is explicit opt-in.\n- Secrets: never in code. Web3Auth client ID (free) in NEXT_PUBLIC_WEB3AUTH_CLIENT_ID.\n\n## Docs\n- Avalanche Builder Hub: https://build.avax.network/llms.txt\n- Web3Auth dashboard: https://dashboard.web3auth.io\n- Fuji faucet: https://core.app/tools/testnet-faucet`;\n\nserver.registerTool(\n \"get_context\",\n {\n title: \"Get AvaKit context\",\n description:\n \"Return AvaKit + Avalanche context for coding: the API surface, conventions, and doc links.\",\n inputSchema: { topic: z.string().optional().describe(\"Optional focus topic\") },\n },\n async ({ topic }) =>\n text(topic ? `${AVAKIT_CONTEXT}\\n\\n(Requested focus: ${topic})` : AVAKIT_CONTEXT),\n);\n\nasync function main(): Promise<void> {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n process.stderr.write(\"avakit-mcp running on stdio\\n\");\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(`avakit-mcp fatal: ${String(error)}\\n`);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@avakit/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AvaKit MCP server — scaffold, deploy, and read Avalanche from Claude Code / Cursor.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"avakit-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
18
|
+
"viem": "2.54.1",
|
|
19
|
+
"zod": "4.4.3",
|
|
20
|
+
"@avakit/core": "0.1.0",
|
|
21
|
+
"create-avalanche-app": "0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "26.0.1",
|
|
25
|
+
"tsup": "8.5.1",
|
|
26
|
+
"typescript": "6.0.3",
|
|
27
|
+
"vitest": "4.1.9"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"avalanche",
|
|
31
|
+
"avax",
|
|
32
|
+
"mcp",
|
|
33
|
+
"model-context-protocol",
|
|
34
|
+
"ai",
|
|
35
|
+
"claude",
|
|
36
|
+
"cursor",
|
|
37
|
+
"web3",
|
|
38
|
+
"avakit"
|
|
39
|
+
],
|
|
40
|
+
"author": "AvaKit contributors",
|
|
41
|
+
"homepage": "https://github.com/mericcintosun/AvaKit#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/mericcintosun/AvaKit/issues"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/mericcintosun/AvaKit.git",
|
|
48
|
+
"directory": "packages/mcp"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20.11"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"dev": "tsup --watch",
|
|
56
|
+
"start": "node dist/index.js",
|
|
57
|
+
"test": "vitest run --passWithNoTests",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"clean": "rm -rf dist .turbo"
|
|
60
|
+
}
|
|
61
|
+
}
|