읽는 데 29분 소요
개요
모델 컨텍스트 프로토콜(MCP) 을 사용하면 외부 데이터 소스 및 서비스와 연동되는 사용자 지정 도구를 통해 Claude와 같은 AI 어시스턴트의 기능을 확장할 수 있습니다. 이 가이드에서는 Claude Desktop(또는 Cursor)과 같은 도구가 Solana 블록체인을 직접 쿼리할 수 있도록 해주는 Solana MCP 서버를 구축해 보겠습니다. 이 통합을 통해 Claude는 지갑 잔액 확인, 토큰 계정 조회, 거래 내역 조회, 계정 정보 분석 등의 작업을 수행할 수 있게 되며, 사용자는 이러한 상호작용을 완전히 제어할 수 있습니다. Goat SDK나 SendAI.fun과 같이 AI와 솔라나를 연결해 주는 훌륭한 도구가 많이 있지만, 직접 도구를 구축하고 싶다면 이 가이드가 도움이 될 것입니다! 이 튜토리얼을 마치면 클로드 데스크톱에 연결할 수 있는 완벽하게 작동하는 솔라나 MCP 서버를 갖게 되어, 자연어를 통해 원활한 블록체인 상호작용이 가능해집니다:

주요 업무
- TypeScript와 MCP SDK를 사용하여 Solana MCP 서버 설정하기
- Solana Kit을 사용하여 Solana 전용 기능을 구현하세요
- Claude Desktop으로 서버를 테스트해 보세요
- 토큰 계정 조회 및 거래 내역 조회와 같은 점점 더 복잡해지는 기능을 추가합니다
- AI가 여러분의 도구를 효과적으로 사용할 수 있도록 유용한 프롬프트를 작성하세요
준비물
- TypeScript에 대한 기초적인 경험
- Solana Basics 및 Solana Kit 사용 경험
- Node.js
- 컴퓨터에 설치된 Claude Desktop
- 솔라나 RPC 엔드포인트 ( 여기에서 무료로 받을 수 있습니다)
| 의존성 | 버전 |
|---|---|
| 노드 | >=23.0.0 |
| @modelcontextprotocol/sdk | ^1.9.0 |
| @solana/kit | ^2.1.0 |
| zod | ^3.24.2 |
| 타입스크립트 | ^5.8.3 |
| 클로드 데스크톱 | 0.9.2 |
MCP 이해하기
모델 컨텍스트 프로토콜(MCP)은 AI 모델과 외부 데이터 소스 또는 도구 간의 간극을 해소하는 개방형 프로토콜입니다. 이 프로토콜은 애플리케이션이 대규모 언어 모델(LLM)에 컨텍스트를 제공할 수 있는 표준화된 방식을 마련하여, LLM이 실시간 정보에 접근하고 훈련 데이터를 넘어서는 작업을 수행할 수 있도록 지원합니다. MCP를 AI 모델이 다양한 데이터 소스, API 및 기능과 안전하고 보안적으로 상호 작용할 수 있게 해주는 범용 어댑터라고 생각하면 됩니다. 기본적으로 MCP는 클라이언트-서버 아키텍처를 따르며, Claude와 같은 AI 애플리케이션이 MCP 서버에 연결되는 클라이언트 역할을 합니다. 이러한 서버는 다음 세 가지 주요 기능을 제공합니다:
- 도구: AI가 특정 작업(예: 지갑 잔액 확인)을 수행하기 위해 호출할 수 있는 함수
- 리소스: AI가 읽을 수 있는 파일 형태의 데이터(예: 문서)
- 프롬프트: AI가 사용자의 도구와 상호작용할 때 지침이 되는 미리 작성된 템플릿
데이터 시각화 도구, 코드 분석기, 또는 외부 시스템과의 연동 인터페이스를 구축하든 간에, MCP는 AI 기능을 확장할 수 있는 체계적이고 안전한 프레임워크를 제공합니다. 이는 특히 블록체인 데이터에 대한 접근성을 높이고 활용을 용이하게 하는 데 매우 유용할 수 있습니다.
MCP와 솔라나
모델 컨텍스트 프로토콜(Model Context Protocol)은 AI 어시스턴트와 Quicknode와 같은 외부 서비스 간의 안전한 통신을 가능하게 하여, 솔라나(또는 기타 블록체인) 데이터에 접근할 수 있게 합니다:

이번 솔라나 MCP 프로젝트에서는 주로 RPC 호출을 사용하는 도구에 중점을 둘 예정이지만, 완전한 통합을 보여주기 위해 리소스와 몇 가지 프롬프트도 구현해 보겠습니다. 그럼 시작해 봅시다!
환경 설정하기
먼저 새 프로젝트를 생성하고 필요한 종속성을 설치해 봅시다:
mkdir solana-mcp && cd solana-mcp
새로운 npm 프로젝트 초기화하기
npm init -y
의존성 설치
npm 설치 @modelcontextprotocol/sdk @solana/kit zod
npm 설치 --save-dev typescript @types/node
만들기 tsconfig.json 다음과 같은 구성 설정이 포함된 파일:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"strict": true,
"outDir": "./build",
"rootDir": "./",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["*.ts", "src/**/*.ts"],
"exclude": ["node_modules", "build"]
}
다음 스크립트가 귀하의 package.json:
"scripts": {
"build": "tsc",
"start": "node build/index.js"
}
새 디렉터리를 만들고, src 그리고 index.ts 그 안에 있는 파일:
mkdir src && touch src/index.ts
MCP 서버 구축하기
먼저, 클라이언트가 지갑의 SOL 잔액을 조회할 수 있게 해주는 단일 도구를 구현해 봅시다.
의존성 가져오기
열기 src/index.ts 그리고 다음 코드를 추가하세요:
import {
McpServer,
} from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import {
createSolanaRpc,
address,
isSolanaError,
assertIsAddress,
assertIsSignature,
} from "@solana/kit";
여기서는 MCP 서버를 생성하는 데 필요한 종속성을 가져오고 있습니다. 이 @modelcontextprotocol/sdk 이 패키지는 MCP 서버를 구축하기 위한 핵심 기능을 제공하며, 한편 @solana/kit Solana RPC 호출을 처리하는 데 필요한 유틸리티를 제공합니다. 또한 다음을 임포트합니다. zod 서버가 입력값과 출력값을 유효성 검사하는 데 도움이 되는 스키마 유효성 검사를 위해.
상수 정의
다음으로, 서버에 사용할 몇 가지 상수를 정의해야 합니다. 여기에는 RPC 엔드포인트와 SPL 프로그램 키가 포함됩니다. 다음 코드를 src/index.ts:
const CONFIG = {
rpcEndpoint:
process.env.SOLANA_RPC_ENDPOINT || "https://api.mainnet-beta.solana.com",
};
const SPL_PROGRAM_KEYS = {
TOKEN_PROGRAM: address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
TOKEN_2022_PROGRAM: address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
};
const solanaRpc = createSolanaRpc(CONFIG.rpcEndpoint);
아시다시피, 저희는 다음과 같은 라이브러리를 사용하지 않고 환경 변수를 참조하고 있습니다. dotenv. MCP 서버는 클라이언트에서 설정한 대로 환경 변수를 불러옵니다(예: claude_desktop_config.json). 그 부분은 나중에 설정하겠습니다.
MCP 서버 생성
자, 이제 MCP 서버를 만들어 보겠습니다. 이 서버는 클라이언트로부터 들어오는 요청을 처리하고 적절한 데이터로 응답할 것입니다. 다음 코드를 src/index.ts:
const server = new McpServer({
name: "SolanaMCP",
version: "1.0.0",
});
새로운 변수인, 서버 의 새로운 인스턴스를 생성합니다. McpServer 클래스. The 이름 그리고 버전 속성은 서버와 그 버전을 식별하는 데 사용됩니다. 이제 남은 일은 서버가 클라이언트에 제공할 도구, 리소스 및 프롬프트를 정의하는 것뿐입니다. 이를 위해서는 단순히 server.tool() 메서드 (또는 .resource() 또는 .prompt() (필요한 경우).
균형 도구 만들기
먼저 만들 도구는 간단한 잔액 확인 도구입니다. 이 도구는 솔라나 주소를 입력으로 받아 해당 주소의 잔액을 반환합니다. 다음 코드를 src/index.ts:
server.tool(
"getBalance",
{
walletAddress: z
.string()
.describe("Solana wallet address to check the balance for"),
},
async (args: { walletAddress: string }) => {
try {
assertIsAddress(args.walletAddress);
const accountAddress = address(args.walletAddress);
const { value: lamports } = await solanaRpc
.getBalance(accountAddress)
.send();
const solBalance = Number(lamports) / 1_000_000_000;
return {
content: [
{
type: "text" as const,
text: `Balance for ${args.walletAddress}: ${solBalance} SOL (${lamports.toString()} lamports)`,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error while getting balance: ${isSolanaError(error) ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
},
);
이 코드는 다음과 같은 새로운 도구를 정의합니다. getBalance. 이 도구는 하나의 인수를 받으며, 지갑 주소, 이는 잔액을 확인할 솔라나 주소를 나타내는 문자열입니다. 이 tool() 이 메서드는 세 개의 인자를 받습니다:
- 도구의 이름,
- zod 입력 스키마, 그리고
- 도구가 호출될 때 실행할 콜백 함수.
콜백 함수는 assertIsAddress ~에서 유래한 함수 @solana/kit 주소 형식을 검증하기 위해. 주소가 유효하면, 다음을 호출합니다. getBalance Solana RPC 클라이언트의 메서드로, SOL 및 lamports 단위의 잔액을 반환합니다. 오류가 발생하면 오류 메시지를 반환합니다.
서버 초기화
좋아요! 이제 서버 설정의 기본은 완료되었습니다. 다음으로, 서버를 초기화하고 들어오는 요청을 수신 대기하도록 해야 합니다. 다음 코드를 src/index.ts:
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
runServer().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
저희는 들어오는 요청을 처리하기 위해 표준 입출력 클래스를 사용하고 있습니다(로컬 통합의 경우 권장됨). 이 전송 방식을 통해 서버는 표준 입출력을 통해 클라이언트와 통신할 수 있습니다. 이 connect() 이 메서드는 서버를 시작하고 들어오는 요청을 수신 대기합니다. MCP를 사용하여 개발을 진행해 나가면서 추가적인 전송 옵션이 필요할 수 있습니다. 이 경우 다음을 참조하십시오. MCP SDK 설명서 자세한 내용은 다음을 참조하십시오.
서버 구축하기
서버 설정이 완료되었으니, 이제 서버를 빌드하고 실행해 봅시다. 터미널에서 다음 명령어를 실행하세요:
npm run build
그러면 TypeScript 코드가 JavaScript로 컴파일되고, 그 결과물이 빌드 디렉터리. 이제 서버를 실행할 수 있지만, Claude Desktop을 사용하는 경우에는 서버가 자동으로 초기화되므로 굳이 직접 실행할 필요는 없습니다.
클로드 데스크톱 설정
MCP 서버를 컴파일했으니, 이제 Claude가 해당 서버를 찾을 수 있고 이를 사용하도록 설정되어 있는지 확인해야 합니다. Claude Desktop이 설치되어 있는지 확인하세요. 앱에서 “Claude” → “설정”으로 이동한 다음 “개발자”를 클릭하세요. “구성 편집”을 클릭하세요:

그러면 다음이 열릴 것입니다. claude_desktop_config.json 파일(또는 그 상위 디렉터리). 파일이 보이지 않으면 최신 버전을 확인해 보세요. 참조 문서 어디에 있는지 확인하려면.
MCP 서버에 대한 JSON 객체가 표시되어야 합니다. 이번이 첫 번째 MCP라면, 해당 객체는 비어 있어야 합니다. 이제 새로운 솔라나 ~에 반대하다 mcpServers 객체. 이 객체에는 Solana MCP 서버의 구성 정보가 포함됩니다. 업데이트 claude_desktop_config.json 출연:
{
"mcpServers": {
"solana": {
"command": "node",
"args": [
"/absolute/path/to/build/index.js"
],
"env": {
"SOLANA_RPC_ENDPOINT": "https://example.solana-mainnet.quiknode.pro/123456/"
}
}
// other MCP servers that you already have configured...
}
}
다음 사항을 반드시 확인하십시오:
- 바꾸다
/빌드/디렉토리의/절대/경로/index.js다음의 절대 경로와 함께build/index.js파일. 다음 명령을 실행하면 이 파일을 찾을 수 있습니다.pwd터미널에서. - 바꾸다
https://example.solana-mainnet.quiknode.pro/123456/자신만의 솔라나 RPC 엔드포인트를 사용하세요. 만약 가지고 계시지 않다면, 무료로 하나 얻을 수 있습니다. 여기. 반드시 다음을 사용하십시오.https엔드포인트.
참고: 바로 이 부분이 SOLANA_RPC_ENDPOINT 환경 변수가 정의되고 있습니다. MCP 서버의 환경 변수에 대한 자세한 내용은 다음을 참조하십시오. 공식 문서.
파일을 저장하고 닫으세요. 이 가이드를 진행하는 데 있어 이 파일을 더 이상 편집할 필요는 없습니다.
MCP 서버 테스트하기
Claude Config를 업데이트했으므로, Claude Desktop을 닫았다가 다시 실행해야 합니다. 그렇게 하면, Claude Desktop이 다시 시작될 때 MCP 서버가 자동으로 실행될 것입니다. 시작하면 다음과 같은 화면이 표시될 것입니다:

“🔨 도구” 버튼을 클릭하면 사용할 수 있는 도구들이 표시됩니다(이 경우, getBalance) 👀:

한 번 테스트해 봅시다. 클로드에게 지갑 잔액을 조회해 달라고 요청해 보세요(예: “CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM의 잔액은 얼마인가요?”). 잠시 생각한 후, 클로드가 MCP 도구 사용 허가를 요청할 것입니다:

클릭하여 도구 사용을 허용하면, Claude가 블록체인에서 데이터를 가져와 응답에 포함시켜 줄 것입니다:

축하합니다! 기본 Solana MCP 서버를 성공적으로 생성하고 Claude Desktop과 연동했습니다.
MCP 서버 성능 향상
기본 통합이 정상적으로 작동하는 만큼, 이제 서버에 더 많은 기능을 추가해 보겠습니다. 다음을 추가할 것입니다:
- 토큰 계정을 조회하는 도구
- 네트워크 상태를 확인하는 도구
- 거래 내역을 확인하는 도구
- 계정 정보를 조회하는 도구
- 간단한 리소스 예시
- 자주 수행하는 작업에 유용한 안내문
이것들을 추가하는 방법은 간단합니다. 각 항목을 메서드 호출 한 번으로 등록하기만 하면 됩니다. 하나씩 살펴보겠습니다. 원하시는 부분만 골라서 구현하셔도 됩니다.
토큰 계정 도구
사용자의 SOL 잔액을 확인하는 도구는 이미 있지만, 토큰 잔액도 함께 확인하고 싶다면 어떻게 해야 할까요? 토큰 계정 도구를 사용하면 지정된 지갑 주소에 대한 모든 토큰 계정을 조회할 수 있습니다. 다음 코드를 src/index.ts:
server.tool(
"getTokenAccounts",
{
walletAddress: z
.string()
.describe("Solana wallet address to check token accounts for"),
},
async ({ walletAddress }) => {
try {
assertIsAddress(walletAddress);
const accounts = await Promise.all([
solanaRpc
.getTokenAccountsByOwner(
walletAddress,
{ programId: SPL_PROGRAM_KEYS.TOKEN_PROGRAM },
{ encoding: "jsonParsed" },
)
.send(),
solanaRpc
.getTokenAccountsByOwner(
walletAddress,
{ programId: SPL_PROGRAM_KEYS.TOKEN_2022_PROGRAM },
{ encoding: "jsonParsed" },
)
.send(),
]);
const tokenAccounts = accounts.flat();
const tokenAccountDetails = tokenAccounts.flatMap((account) => {
return account.value.map((account) => {
const address = account.pubkey;
const mint = account.account.data.parsed.info.mint;
const amount = account.account.data.parsed.info.tokenAmount.uiAmount;
const decimals =
account.account.data.parsed.info.tokenAmount.decimals;
return { address, mint, amount, decimals };
});
});
// Format data as a markdown table
let markdownTable = "| Token Address | Mint | Amount | Decimals |\n";
markdownTable += "|-------------|------|--------|----------|\n";
tokenAccountDetails
.filter((account) => account.amount !== null)
.filter((account) => account.amount !== 0)
.filter((account) => account.amount !== 1) // removing possible NFTs
.sort((a, b) => b.amount! - a.amount!) // we already removed null and 0 amounts
.forEach((account) => {
markdownTable += `| ${account.address} | ${account.mint} | ${account.amount} | ${account.decimals} |\n`;
});
return {
content: [
{
type: "text",
text: `Found ${tokenAccountDetails.length} token accounts for ${walletAddress}`,
},
{
type: "text",
text: markdownTable,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error while getting balance: ${isSolanaError(error) ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
},
);
이는 구조적으로 다음과 매우 유사합니다. getBalance 도구. 가장 큰 차이점은 우리가 getTokenAccountsByOwner 주어진 지갑 주소에 해당하는 모든 토큰 계정을 가져오는 방법입니다. 기존 SPL 토큰 프로그램과 토큰 2022 프로그램 모두를 지원합니다. 응답 데이터의 양이 상당히 많을 수 있으므로, 잔액이 0이거나 1인 계정(대개 NFT일 가능성이 높음)은 필터링하여 제외하고, 데이터의 일부를 마크다운 테이블 형식으로 변환하는 처리를 수행합니다. 사용 사례에 가장 적합한 방식을 찾기 위해 다양한 응답 구조를 자유롭게 실험해 보시기 바랍니다.
네트워크 상태 확인 도구
다음으로, 네트워크 상태를 확인하는 도구를 추가해 보겠습니다. 이 도구는 현재 에포크, 블록 높이, 슬롯 번호를 반환합니다. 다음 코드를 src/index.ts:
server.tool("networkStatus", {}, async () => {
try {
await solanaRpc.getHealth().send();
} catch (error) {
return {
content: [
{
type: "text",
text: `Network is down`,
},
],
};
}
try {
const { epoch, blockHeight, absoluteSlot } = await solanaRpc
.getEpochInfo()
.send();
const status = {
health: "okay",
currentEpoch: epoch.toString(),
blockHeight: blockHeight.toString(),
currentSlot: absoluteSlot.toString(),
};
return {
content: [
{
type: "text",
text: JSON.stringify(status, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error while getting network status: ${isSolanaError(error) ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
});
여기서는 실제로 두 번의 RPC 호출을 수행하고 있습니다. 첫 번째는 네트워크가 연결되어 있는지 확인하는 간단한 상태 확인입니다. 이 호출에서 오류가 반환되면, 네트워크가 연결되지 않았다는 간단한 메시지를 반환합니다. 연결되어 있다면, 다음을 호출합니다. getEpochInfo 현재 에포크, 블록 높이 및 슬롯 번호를 가져옵니다. 이 데이터를 JSON 형식으로 반환합니다. 다음 사항에 유의하십시오. bigint 다음과 관련된 직렬화 문제를 방지하기 위해 값을 문자열로 변환합니다. JSON.stringify.
거래 내역 도구
다음으로, 트랜잭션 세부 정보를 가져오는 도구를 추가해 봅시다. 이 도구는 트랜잭션 서명을 입력으로 받아 트랜잭션 세부 정보를 반환합니다. 다음 코드를 src/index.ts:
server.tool(
"getTransaction",
{
signature: z.string().describe("Solana transaction signature to look up"),
},
async ({ signature }) => {
try {
assertIsSignature(signature);
} catch (error) {
return {
content: [
{
type: "text",
text: `not a vaid signature: ${signature}`,
},
],
isError: true,
};
}
try {
const transaction = await solanaRpc
.getTransaction(signature, {
maxSupportedTransactionVersion: 0,
encoding: "json",
})
.send();
if (!transaction) {
return {
content: [
{ type: "text", text: `Transaction ${signature} not found` },
],
isError: true,
};
}
const programIndices = transaction.transaction.message.instructions.map(
(instruction) => instruction.programIdIndex,
);
const programsInvoked = programIndices.map((index) => {
const programId = transaction.transaction.message.accountKeys[index];
return programId.toString();
});
// Format the transaction data for readability
const formattedTx = {
signature,
computeUnits: transaction.meta?.computeUnitsConsumed?.toString(),
logs: transaction.meta?.logMessages,
accountKeys: transaction.transaction.message.accountKeys,
programsInvoked: programsInvoked,
instructions: transaction.transaction.message.instructions,
slot: transaction.slot.toString(),
blockTime: transaction.blockTime
? new Date(Number(transaction.blockTime) * 1000).toISOString()
: null,
fee: transaction.meta?.fee.toString(),
status: transaction.meta?.err ? "Failed" : "Success",
preBalances: transaction.meta?.preBalances.map((balance) =>
balance.toString(),
),
postBalances: transaction.meta?.postBalances.map((balance) =>
balance.toString(),
),
preTokenBalances: transaction.meta?.preTokenBalances,
postTokenBalances: transaction.meta?.postTokenBalances,
};
return {
content: [
{
type: "text",
text: `Transaction ${signature}:\n${JSON.stringify(formattedTx, null, 2)}`,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error while getting balance: ${isSolanaError(error) ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
},
);
잔액 확인 도구와 마찬가지로, Solana Kit 어설션을 사용하여 매개변수를 검증할 수 있습니다(이 경우, assertIsSignature). 그런 다음 우리는 getTransaction 트랜잭션 세부 정보를 가져오는 방법입니다. 데이터를 파싱하여, LLM이 트랜잭션을 분석하는 데 유용할 것으로 판단되는 데이터의 일부만 반환하고 있습니다. 이 경우, 트랜잭션에서 호출된 프로그램 ID, 트랜잭션 서명, 소비된 컴퓨트 유닛, 로그, 계정 키, 호출된 프로그램, 명령어, 슬롯 번호, 블록 시간, 수수료, 상태, 트랜잭션 전 잔액, 트랜잭션 후 잔액, 그리고 토큰의 트랜잭션 전/후 잔액을 추출합니다. 이전 도구와 마찬가지로, 우리는 다음을 변환하도록 하고 있습니다. bigint 직렬화 문제를 방지하기 위해 값을 문자열로 변환합니다.
MCP를 실험해 보시는 과정에서, IDL을 활용하여 명령 데이터를 분석하거나 유용하다고 생각되는 기타 추가적인 컨텍스트나 매핑을 추가함으로써 응답 데이터를 조금 더 확장해 보는 것도 고려해 보시기 바랍니다.
계정 정보 도구
다음으로, 계정 정보를 가져오는 도구를 추가해 봅시다. 이 도구는 계정 주소를 입력으로 받아 계정 정보를 반환합니다. 다음 코드를 src/index.ts:
server.tool(
"getAccountInfo",
{
walletAddress: z
.string()
.describe("Solana wallet address to check account information for"),
},
async ({ walletAddress }) => {
try {
assertIsAddress(walletAddress);
const accountAddress = address(walletAddress);
const { value: accountInfo } = await solanaRpc
.getAccountInfo(accountAddress)
.send();
if (!accountInfo) {
return {
content: [
{
type: "text",
text: `Account ${walletAddress} not found or has no SOL balance`,
},
],
isError: true,
};
}
const info = {
executable: accountInfo.executable,
lamports: accountInfo.lamports.toString(),
owner: accountInfo.owner.toString(),
rentEpoch: accountInfo.rentEpoch.toLocaleString(),
space: accountInfo.data.length,
};
return {
content: [
{
type: "text",
text: JSON.stringify(info, null, 2),
},
],
};
} catch (error) {
console.error("Error fetching account info:", error);
return {
content: [
{
type: "text",
text: `Error while getting account info: ${isSolanaError(error) ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
},
);
이 패턴들은 이제 다들 익숙하실 겁니다. 우리는 getAccountInfo 계정 정보를 조회하는 방법.
리소스 예시
MCP의 리소스는 서버가 LLM이 참조하고 사용할 수 있는 구조화된 데이터를 노출할 수 있는 방법을 제공합니다. 호출 시 작업을 실행하는 도구와 달리, 리소스는 데이터를 표준화된 형식으로 노출하는 “읽기 전용 엔드포인트”에 가깝습니다. 리소스는 file://, https://와 같은 스키마나, 이 예시에서와 같이 solana://와 같은 사용자 정의 스키마를 따르는 URI(Uniform Resource Identifier)로 식별됩니다.
다음은 문서 리소스를 서버로 불러오는 방법을 종합적으로 보여주는 예시입니다. 이는 솔라나(Solana) 트랜잭션 최적화 문서의 내용을 요약한 것입니다:
server.resource(
"transaction-optimization",
"solana://docs/transaction-optimization",
async (uri) => {
const optimizationGuide = {
title: "Solana Transaction Optimization Strategies",
strategies: {
priority_fees: {
description: "Increase transaction priority in validator queues",
implementation:
"Use ComputeBudgetProgram.setComputeUnitPrice({microLamports})",
best_practice:
"Use QN Priority Fee API to determine optimal fee based on network conditions",
},
compute_units: {
description:
"Optimize compute unit usage to prevent transaction drops",
current_limits: {
per_block: "48 million",
per_account_per_block: "12 million",
per_transaction: "1.4 million",
transaction_default: "200,000",
},
implementation:
"Use ComputeBudgetProgram.setComputeUnitLimit({units}) after simulation",
},
transaction_assembly: {
steps: [
"Create transaction with instructions",
"Fetch and add priority fees",
"Simulate transaction to determine compute usage",
"Set compute limit based on simulation",
"Add recent blockhash",
"Sign and send",
],
},
jito_bundles: {
description: "Bundle multiple transactions for atomic execution",
requires: "SOL transfer to Jito Tip Account",
},
confirmation: {
description: "Poll transaction status to ensure it landed",
method: "Use getSignatureStatuses and implement retry logic",
},
},
moreInfo: "https://www.quicknode.com/docs/solana/transactions",
};
return {
contents: [
{
uri: uri.href,
text: JSON.stringify(optimizationGuide, null, 2),
},
],
};
},
);
이 리소스는 솔라나(Solana)의 트랜잭션 최적화 전략에 대한 체계적인 개요를 제공합니다. LLM은 이 리소스를 활용하여 별도의 도구나 API를 호출하지 않고도 트랜잭션 최적화에 관한 질문에 답변할 수 있습니다. URI 스키마(solana://)는 이것이 사용자 정의 리소스 유형임을 나타내며, 내용은 구조화된 형식으로 반환됩니다.
유용한 프롬프트
MCP의 프롬프트는 AI가 사용자의 도구 및 리소스와 상호작용하는 방식을 안내하는 미리 정의된 메시지 템플릿입니다. 코드를 실행하는 ‘도구’나 데이터를 제공하는 ‘리소스’와 달리, 프롬프트는 대규모 언어 모델(LLM)이 특정 작업을 어떻게 수행해야 하는지를 구조화하는 지침서 역할을 합니다.
LLM이 우리 도구를 사용할 때 도움이 될 만한 프롬프트를 몇 가지 추가해 봅시다. 다음 코드를 src/index.ts:
server.prompt(
"analyze-wallet",
{ walletAddress: z.string() },
({ walletAddress }) => ({
description:
"Analyze a Solana wallet address and provide a summary of its balances and activity",
messages: [
{
role: "user",
content: {
type: "text",
text: `Please analyze this Solana wallet address: ${walletAddress}
1. What is the SOL balance of this wallet?
2. What token balances does this wallet hold?
3. Provide a summary of recent activity if possible.`,
},
},
],
}),
);
server.prompt(
"explain-transaction",
{ signature: z.string() },
({ signature }) => ({
description: "Analyze and explain a Solana transaction in simple terms",
messages: [
{
role: "user",
content: {
type: "text",
text: `Please analyze this Solana transaction signature: ${signature}
1. Was this transaction successful?
2. What type of transaction is this? (e.g., token transfer, swap, NFT mint)
3. What accounts were involved?
4. Explain what happened in simple terms.`,
},
},
],
}),
);
각 프롬프트는 다음으로 구성됩니다:
- 독창적인 이름 (예: “analyze-wallet”)
- 매개변수 스키마 (유형 유효성 검사에 Zod 사용)
- 해당 매개변수를 바탕으로 메시지 내용을 생성하는 함수
사용자가 Claude Desktop에서 프롬프트를 선택하면, 매개변수를 입력할 수 있는 양식이 표시됩니다. 양식을 제출하면 Claude는 형식이 지정된 메시지 템플릿을 수신하고 이에 따라 응답합니다. 프롬프트는 특히 다음과 같은 경우에 유용합니다:
- 일반적인 워크플로우의 표준화
- 고객이 업무를 일관성 있게 수행하도록 보장하기
- 사용자가 효과적인 검색어를 작성할 수 있도록 돕기
- 고객이 귀사의 도구를 가장 효율적인 순서로 사용할 수 있도록 안내하기
서버를 다시 구축하세요
이제 모든 도구, 리소스 및 프롬프트를 추가했으니, 서버를 다시 구축해 봅시다:
npm run build
업그레이드된 MCP 서버 테스트하기
서버의 기능을 확장했으니, 이제 Claude Desktop을 통해 새로운 기능을 테스트해 봅시다. 설정 변경 후 서버를 재시작하려면 Claude Desktop을 닫았다가 다시 열어야 합니다. Claude Desktop을 열면 도구 메뉴에 5가지 도구가 모두 표시되어 있을 것입니다:

마음껏 한번 테스트해 보세요. 다음과 같은 것들을 시도해 볼 수 있습니다:
- 솔라나 네트워크의 현황은 어떠한가요?
- 이 지갑에 있는 토큰 목록을 표로 작성하세요: XYZ...ABC
- 다음에 대한 거래 정보를 알려주세요: XYZ...ABC
- XYZ...ABC에 대한 계정 정보를 알려주세요.
또한 🔌 “MCP에서 첨부” 버튼이 표시될 것입니다. 이 버튼을 클릭하면 사용할 수 있는 리소스와 프롬프트가 표시됩니다:

자신이 작성한 프롬프트 중 하나를 클릭하면, 매개변수(예: 지갑 주소 또는 txid)를 입력할 수 있는 양식이 표시됩니다:

매개변수를 입력하고 “제출”을 클릭하면, 클로드가 해당 프롬프트를 바탕으로 (필요한 도구를 활용하여) 메시지를 생성하고 그에 따라 응답할 것입니다. 한번 시도해 보세요.
드디어 리소스를 테스트해 볼 수 있습니다. 이를 위해서는 다음을 추가하면 됩니다. 트랜잭션 최적화 프롬프트에 내용을 입력한 다음, 클로드에게 그 내용과 관련된 질문을 해보세요. 한번 해보세요:

정말 잘했어요!
마무리
이제 블록체인 기능을 통해 LLM의 역량을 강화하는 Solana MCP 서버를 성공적으로 구축하셨습니다. 이 통합을 통해 Claude는 Solana 블록체인과 직접 상호작용하여 잔액 확인, 토큰 정보 조회, 거래 내역 확인 등을 수행할 수 있습니다. AI 어시스턴트의 자연어 이해 능력과 MCP 서버의 데이터 접근 기능을 결합함으로써, 블록체인 상호작용을 위한 강력한 도구를 만들어 냈습니다. 개발자이든, 트레이더이든, 아니면 단순히 솔라나에 호기심이 있는 분이든, 이 통합을 통해 블록체인 데이터에 더 쉽게 접근하고 이해할 수 있게 되었습니다. MCP 프레임워크는 유연하고 확장성이 뛰어나므로, 필요에 따라 추가 기능을 통해 서버를 지속적으로 강화할 수 있습니다. 간단한 데이터 쿼리부터 복잡한 분석, 거래 구성(적절한 보안 조치 포함), 에이전트 조립에 이르기까지 그 가능성은 사실상 무한합니다. 이 가이드가 MCP와 솔라나 통합을 시작하는 데 도움이 되기를 바랍니다. 이미 구축한 기능을 확장하고 싶으신가요? 지속적인 개발을 위한 몇 가지 아이디어를 소개합니다:
솔라나 MCP 서버 확장하기
이제 정상적으로 작동하는 MCP 서버가 준비되었으니, 다음과 같이 기능을 더욱 향상시킬 수 있는 몇 가지 방법을 소개합니다:
- 토큰 메타데이터 가져오기: Quicknode의 DAS API를 사용하여 소스에서 NFT 및 토큰 메타데이터를 가져와, 토큰 잔액과 함께 이름, 심볼, 로고를 표시합니다.
- 가격 정보: Metis Jupiter API와 연동하여 SOL 및 SPL 토큰의 실시간 가격을 제공합니다.
- 거래 내역: 특정 지갑 주소의 최근 거래 내역을 조회할 수 있는 도구를 구현합니다.
- 프로그램의 계정 및 거래 데이터 분석: 이 MCP는 Solana Kit를 사용하여 구축되었으므로, Codama를 통해 자체 프로그램용 클라이언트를 생성하고 프로그램의 코덱을 MCP 서버에 통합할 수 있습니다.
- 스테이크 계정 정보: 스테이크 계정 및 위임 상태에 대한 정보를 조회하는 도구를 추가합니다(Solana Kit을 사용하여 스테이크 계정을 조회하는 예시).
- 확장된 기능을 위해 Quicknode 애드온을 통합하세요
창의력을 발휘해 보세요! 여러분이 어떤 작품을 만들어낼지 정말 기대됩니다. 궁금한 점이 있거나 도움이 필요하시면, Discord나 Twitter를 통해 언제든지 연락해 주세요.
추가 자료
- 이 가이드의 코드
- 모델 컨텍스트 프로토콜 문서
- 솔라나 문서
- 솔라나 키트 문서
- MCP Inspector - MCP 서버 디버깅에 유용한 도구
- MCP 보안 고려 사항 - MCP 서버 구축 시 유의해야 할 중요한 보안 사항
여러분의 피드백을 ❤️ 환영합니다!
의견이나 다루었으면 하는 새로운 주제가 있다면 알려주세요. 여러분의 의견을 기다리고 있습니다.
