Solana Debug MCP
# Solana Debug MCP
Solana Debug MCP is a Model Context Protocol server for inspecting and debugging Solana transactions, accounts, Anchor IDLs, Anchor errors, and Program Derived Addresses from MCP-compatible clients.
This project is ready for local production-style MCP use over stdio. It can simulate base64 or base58 serialized Solana transactions, inspect account metadata, inspect legacy and versioned transaction instructions, fetch on-chain Anchor IDLs, decode supported Anchor account and instruction fields, look up built-in and IDL-provided Anchor errors, and derive PDAs.
## Features
- `simulate_transaction`: Simulate a serialized Solana transaction through an RPC endpoint and summarize logs.
- `decode_account`: Fetch account metadata and decode supported Anchor account fields when an IDL is supplied or fetchable.
- `decode_instruction`: Inspect legacy/versioned instructions and decode supported Anchor instruction args when an IDL is supplied or fetchable.
- `anchor_error_lookup`: Look up common Anchor framework errors and custom IDL errors.
- `pda_verify`: Derive a PDA from seeds and check whether the account exists on chain.
## Current Limitations
- Hosted HTTP/SaaS transport is not implemented; current production target is local stdio MCP.
- IDL enum decoding and some unusual Anchor IDL shapes are not implemented yet.
- `pda_verify` supports typed seeds. Plain string seeds are still accepted as UTF-8 for backward compatibility.
- Error analysis is deterministic log pattern matching, not AI-generated analysis.
## Requirements
- Node.js 20 or newer
- pnpm 10 or newer
- A Solana RPC endpoint
- Optional Helius API key for mainnet RPC
## Installation
```bash
pnpm install
pnpm run build
```
For local development:
```bash
pnpm run dev
```
For production-style local execution:
```bash
pnpm start
```
## Configuration
Create a `.env` file from the example:
```bash
cp .env.example .env
```
Supported environment variables:
```env
# Optional. If set, the server uses Helius mainnet RPC by default.
HELIUS_API_KEY=your-helius-api-key
# Optional fallback RPC URL when HELIUS_API_KEY is not set.
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
# Documented for future cluster-aware IDL fetching. Currently unused.
SOLANA_CLUSTER=mainnet-beta
```
RPC precedence in the current implementation:
1. Tool-level `rpc_url`, where supported
2. `HELIUS_API_KEY`, if set
3. `SOLANA_RPC_URL`
4. `https://api.mainnet-beta.solana.com`
## Claude Desktop Setup
Build the project first:
```bash
pnpm run build
```
Then add the server to your Claude Desktop configuration.
macOS path:
```text
~/Library/Application Support/Claude/claude_desktop_config.json
```
Example configuration:
```json
{
"mcpServers": {
"solana-debug": {
"command": "node",
"args": ["/absolute/path/to/solanaDebug/dist/index.js"],
"env": {
"HELIUS_API_KEY": "your-helius-api-key",
"SOLANA_RPC_URL": "https://api.mainnet-beta.solana.com"
}
}
}
}
```
Restart Claude Desktop after editing the config.
## Other Client Config Examples
All examples assume you already ran:
```bash
pnpm install
pnpm run build
```
Replace `/absolute/path/to/solanaDebug` with your local checkout path. Prefer passing secrets through the client config or process environment instead of committing them to source control.
### Codex
Codex reads MCP servers from `~/.codex/config.toml`.
```toml
[mcp_servers.solana-debug]
command = "node"
args = ["/absolute/path/to/solanaDebug/dist/index.js"]
startup_timeout_sec = 10
tool_timeout_sec = 60
[mcp_servers.solana-debug.env]
HELIUS_API_KEY = "your-helius-api-key"
SOLANA_RPC_URL = "https://api.mainnet-beta.solana.com"
```
If you keep `.env` in the project root, you can omit the `env` table and set `cwd` so the server loads the local `.env` file:
```toml
[mcp_servers.solana-debug]
command = "node"
args = ["dist/index.js"]
cwd = "/absolute/path/to/solanaDebug"
startup_timeout_sec = 10
tool_timeout_sec = 60
```
### VS Code
VS Code can use a workspace `.vscode/mcp.json` or user-level MCP config.
```json
{
"servers": {
"solana-debug": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/solanaDebug/dist/index.js"],
"env": {
"HELIUS_API_KEY": "your-helius-api-key",
"SOLANA_RPC_URL": "https://api.mainnet-beta.solana.com"
}
}
}
}
```
For a workspace-local setup:
```json
{
"servers": {
"solana-debug": {
"type": "stdio",
"command": "node",
"args": ["dist/index.js"],
"cwd": "/absolute/path/to/solanaDebug"
}
}
}
```
### Hermes Agent
Hermes Agent uses `mcp_servers` in its YAML config. Hermes intentionally filters environment variables for stdio servers, so include any RPC secrets explicitly.
```yaml
mcp_servers:
solana-debug:
command: "node"
args:
- "/absolute/path/to/solanaDebug/dist/index.js"
env:
HELIUS_API_KEY: "your-helius-api-key"
SOLANA_RPC_URL: "https://api.mainnet-beta.solana.com"
enabled: true
timeout: 120
connect_timeout: 60
tools:
resources: false
prompts: false
```
### OpenClaw
OpenClaw-managed MCP servers can be configured under `mcp.servers`. If sandbox tool filtering is enabled, allow MCP plugin tools via `bundle-mcp` or `group:plugins`.
```json5
{
mcp: {
servers: {
"solana-debug": {
command: "node",
args: ["/absolute/path/to/solanaDebug/dist/index.js"],
env: {
HELIUS_API_KEY: "your-helius-api-key",
SOLANA_RPC_URL: "https://api.mainnet-beta.solana.com",
},
},
},
},
tools: {
sandbox: {
tools: {
alsoAllow: ["bundle-mcp"],
},
},
},
}
```
## MCP Tools
### simulate_transaction
Simulates a serialized Solana transaction and returns simulation status, logs, units consumed, and pattern-based analysis.
Input:
```json
{
"transaction": "base64-or-base58-serialized-transaction",
"rpc_url": "https://api.mainnet-beta.solana.com"
}
```
Fields:
- `transaction`: Required string. Accepts base64 or base58 serialized legacy or versioned transaction bytes.
- `rpc_url`: Optional string. Overrides environment RPC defaults for this call.
Output shape:
```json
{
"ok": true,
"data": {
"success": false,
"error_code": "custom program error...",
"error_message": "Transaction simulation failed",
"transaction_type": "legacy",
"encoding": "base64",
"logs": [],
"analysis": "Pattern-based explanation"
}
}
```
Implementation:
- Registered in `src/index.ts`.
- Handler is `simulateTransaction` in `src/tools/simulate.ts`.
- RPC call is made by `RPCService.simulateTransaction` in `src/services/rpc.ts`.
- Log summary is generated by `generateAnalysis` in `src/services/analyzer.ts`.
### decode_account
Fetches basic account information from RPC.
Input:
```json
{
"address": "account-public-key",
"program_id": "expected-owner-program-id"
}
```
Fields:
- `address`: Required account public key.
- `program_id`: Required expected owner program ID. The response reports whether it matches the fetched account owner.
Output shape:
```json
{
"ok": true,
"data": {
"address": "account-public-key",
"program_id": "expected-owner-program-id",
"owner_matches_program_id": true,
"account_type": "unknown",
"data": {
"lamports": 1000000,
"sol_balance": 0.001,
"owner": "actual-owner-program-id",
"executable": false,
"data_length": 128,
"note": "Full IDL decoding not yet implemented in MVP. Raw account data available."
}
}
}
```
Implementation:
- Registered in `src/index.ts`.
- Handler is `decodeAccount` in `src/tools/decode.ts`.
- Account fetching is handled by `RPCService.getAccountInfo`.
- `src/services/idl.ts` contains placeholder IDL-service code but is not wired into this tool yet.
### decode_instruction
Inspects one or all instructions in a serialized legacy transaction.
Input:
```json
{
"transaction": "base64-or-base58-serialized-transaction",
"instruction_index": 0
}
```
Fields:
- `transaction`: Required string. Accepts base64 or base58 serialized legacy or versioned transaction bytes.
- `instruction_index`: Optional number. When omitted, all instructions are returned.
Output shape for one instruction:
```json
{
"ok": true,
"data": {
"transaction_type": "legacy",
"encoding": "base64",
"instruction": {
"index": 0,
"program_id": "program-public-key",
"accounts": [
{
"pubkey": "account-public-key",
"isSigner": true,
"isWritable": true
}
],
"data": "base64-instruction-data",
"data_length": 16
}
}
}
```
Implementation:
- Registered in `src/index.ts`.
- Handler is `decodeInstruction` in `src/tools/decode.ts`.
- Uses the shared transaction parser in `src/services/transaction.ts`.
### anchor_error_lookup
Looks up a common Anchor framework error by decimal or hexadecimal code.
Input:
```json
{
"error_code": "0x1771",
"program_id": "optional-program-id"
}
```
or:
```json
{
"error_code": "6001"
}
```
Fields:
- `error_code`: Required string. Accepts decimal, `0x` hex, or `0X` hex.
- `program_id`: Optional string. Used to fetch an on-chain Anchor IDL for custom error lookup when `idl` is not supplied.
Output shape:
```json
{
"ok": true,
"data": {
"error_code": "0x1771",
"error_code_decimal": 6001,
"error_name": "Unknown",
"description": "Error code not found in Anchor error database",
"common_causes": ["Custom program error", "Unknown error type"],
"suggested_fixes": [
"Check program source code for custom error definitions",
"Review transaction logs for more context",
"Verify error code is from Anchor framework"
],
"program_id": "unknown"
}
}
```
Implementation:
- Registered in `src/index.ts`.
- Handler and built-in error table are in `src/tools/errors.ts`.
### pda_verify
Derives a Program Derived Address and checks whether the derived account exists.
Input:
```json
{
"program_id": "program-public-key",
"seeds": [
{ "type": "utf8", "value": "seed" },
{ "type": "pubkey", "value": "public-key-seed" }
]
}
```
Fields:
- `program_id`: Required program public key.
- `seeds`: Required array of typed seeds. Supported types are `utf8`, `pubkey`, `hex`, and `base64`. Plain strings are accepted as UTF-8 seeds for backward compatibility.
Output shape:
```json
{
"ok": true,
"data": {
"address": "derived-pda",
"bump": 255,
"exists": true,
"program_id": "program-public-key",
"seeds": [{ "type": "utf8", "value": "seed" }],
"account_data": {
"lamports": 1000000,
"owner": "owner-public-key",
"data_length": 128
}
}
}
```
Implementation:
- Registered in `src/index.ts`.
- Handler is `pdaVerify` in `src/tools/pda.ts`.
- PDA derivation uses `PublicKey.findProgramAddressSync`.
- Account lookup uses `RPCService.getAccountInfo`.
## Project Structure
```text
src/
├── index.ts MCP server entry point and tool registration
├── tools/
│ ├── simulate.ts simulate_transaction handler
│ ├── decode.ts decode_account and decode_instruction handlers
│ ├── errors.ts anchor_error_lookup handler and error table
│ └── pda.ts pda_verify handler
├── services/
│ ├── rpc.ts Solana RPC wrapper
│ ├── transaction.ts Shared transaction parser and instruction views
│ ├── idl.ts Placeholder IDL fetching and decoding service
│ └── analyzer.ts Transaction log pattern matching
└── utils/
└── types.ts Shared result helpers and interfaces
```
## Development Workflow
Install dependencies:
```bash
pnpm install
```
Run the server from TypeScript:
```bash
pnpm run dev
```
Typecheck and build:
```bash
pnpm run typecheck
pnpm run build
```
Run tests:
```bash
pnpm test
```
Run the opt-in live RPC smoke test:
```bash
pnpm run test:live
```
This uses your configured `.env` or process environment and reaches the configured Solana RPC provider.
Run the built server:
```bash
pnpm start
```
Clean generated output:
```bash
pnpm run clean
```
## Implementation Notes
### Adding a Tool
1. Add the handler under `src/tools/`.
2. Define its Zod schema near the handler.
3. Register it with `server.tool(...)` in `src/index.ts`.
4. Return MCP-compatible text content with `createResult` or `createErrorResult`.
5. Add tests for valid input, invalid input, and RPC failure behavior.
### Returning Results
Tools return:
```ts
{
content: [{ type: "text", text: "..." }]
}
```
JSON payloads are currently serialized into the `text` field. Success responses use `{ "ok": true, "data": ... }`; failures use `{ "ok": false, "error": "..." }`.
### RPC Access
`RPCService` wraps `@solana/web3.js` `Connection` creation and common calls. New RPC-backed features should be added there when they are reusable by multiple tools.
### IDL Decoding
`src/services/idl.ts` supports Anchor IDL fetching and decoding:
- On-chain Anchor IDL address derivation.
- Inflating and parsing on-chain Anchor IDL account data.
- Account and instruction discriminator matching.
- Primitive fields: `bool`, `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `string`, `bytes`, `publicKey`, and `pubkey`.
- Complex fields: `option`, `vec`, fixed arrays, and nested defined structs.
- Custom IDL errors through `anchor_error_lookup`.
IDL support should still add enum decoding and broader fixture coverage for unusual Anchor IDL shapes.
## Troubleshooting
### `Unable to parse transaction`
The `transaction` field must be a serialized Solana transaction encoded as base64 or base58. JSON transaction objects and signatures are not accepted.
### RPC timeouts or rate limits
Set `HELIUS_API_KEY` or `SOLANA_RPC_URL` in `.env`. The RPC wrapper has retry and timeout handling, but persistent rate limits require a better RPC provider or a dedicated key.
### `.env` is not loading
The server loads `.env` from the current working directory. Start the server from the project root, or pass environment variables through your MCP client config.
### Live RPC smoke test is skipped
This is expected. Run it explicitly:
```bash
pnpm run test:live
```
## Contributing
1. Add or update tests first.
2. Run `pnpm run typecheck`.
3. Run `pnpm test`.
4. Keep MCP tool outputs structured as `{ "ok": true, "data": ... }` or `{ "ok": false, "error": "..." }`.
5. Keep network tests opt-in unless they use mocked RPC.
## Testing Status
The project has a focused Node test suite for transaction parsing, instruction inspection, Anchor error lookup, and structured errors. More unit and integration coverage is still needed before production use. See [PRODUCTION_PLAN.md](./PRODUCTION_PLAN.md) for the recommended production-readiness checklist.
## Production Status
This project is production-ready for local stdio MCP usage. Hosted HTTP/SaaS deployment is not implemented.
## Security
See [SECURITY.md](./SECURITY.md). Do not commit `.env` files or private RPC keys. Serialized transactions and account addresses may be sent to the configured RPC provider.
## Release
See [RELEASE.md](./RELEASE.md) for the package release checklist.
## Usage Scenarios
See [USER_STORIES.md](./USER_STORIES.md) for concrete examples of how Solana developers can use this MCP server.
## Testing It Yourself
See [TESTING_GUIDE.md](./TESTING_GUIDE.md) for a hands-on path after cloning the repo.
## License
MIT
## Author
[@itsbiccs](https://x.com/itsbiccs)
TDQS
Scored across 5 tools
Each tool targets a distinct aspect of Solana debugging: transaction simulation, account data decoding, instruction decoding, error code lookup, and PDA verification. There is no overlap in their core functions.
Tool names predominantly follow a verb_noun snake_case pattern (simulate_transaction, decode_account, decode_instruction). The one exception is anchor_error_lookup, which uses a noun_verb ordering but remains clear and consistent in style.
Five tools is an ideal size for a specialized debugging server. Each tool addresses a specific need without redundancy, and the scope is well-defined.
The set covers the most common debugging tasks: simulate, decode, lookup errors, and verify PDAs. Minor gaps exist (e.g., fetching raw transaction logs or account history), but the core debugging workflow is well-supported.