在 Solana 区块链上为自主 AI 代理和模型上下文协议(MCP)服务器提供全面的链上注册系统。
代理注册表: BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr | 浏览器
MCP 服务器注册表: BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR | 浏览器
Solana AI 注册表协议提供了发现、验证和与自主 AI 代理及模型上下文协议(MCP)服务器交互的基本基础设施。此实现包括两个相互连接的链上注册表:
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装 Solana CLI
curl --proto '=https' --tlsv1.2 -sSfL https://solana-install.solana.workers.dev | bash
# 设置本地开发环境
solana config set --url localhost
solana-test-validator
# 克隆仓库
git clone https://github.com/openSVM/aeamcp.git
cd aeamcp
# 构建所有程序
./scripts/build.sh
# 或手动构建
cargo build --all
cargo test --all
# 运行全面测试套件
cargo test --all
# 运行特定注册表测试
cargo test agent_registry_tests
cargo test mcp_server_registry_tests
# 使用详细输出运行
cargo test -- --nocapture
aeamcp/
├── programs/
│ ├── common/ # 共享工具和类型
│ ├── agent-registry/ # 代理注册表程序
│ └── mcp-server-registry/ # MCP 服务器注册表程序
├── tests/ # 集成测试
├── scripts/ # 构建和部署脚本
├── docs/ # 协议文档
└── README.md # 此文件
use solana_ai_registries_common::*;
use agent_registry::instruction::AgentRegistryInstruction;
// 创建注册指令
let instruction = AgentRegistryInstruction::RegisterAgent {
agent_id: "my-trading-agent".to_string(),
name: "高级交易代理".to_string(),
description: "自动化交易策略的 AI 代理".to_string(),
agent_version: "1.0.0".to_string(),
provider_name: Some("TradingCorp".to_string()),
provider_url: Some("https://tradingcorp.com".to_string()),
documentation_url: Some("https://docs.tradingcorp.com/agent".to_string()),
service_endpoints: vec![
ServiceEndpointInput {
protocol: "a2a_http_jsonrpc".to_string(),
url: "https://api.tradingcorp.com/agent".to_string(),
is_default: true,
}
],
capabilities_flags: 0x01, // 支持流式传输
supported_input_modes: vec!["application/json".to_string()],
supported_output_modes: vec!["application/json".to_string()],
skills: vec![
AgentSkillInput {
id: "market-analysis".to_string(),
name: "市场分析".to_string(),
description_hash: Some([0u8; 32]), // 详细描述的哈希
tags: vec!["交易".to_string(), "分析".to_string()],
}
],
security_info_uri: Some("https://tradingcorp.com/security".to_string()),
aea_address: None,
economic_intent_summary: Some("最大化交易利润".to_string()),
supported_aea_protocols_hash: None,
extended_metadata_uri: Some("https://ipfs.io/ipfs/QmAgent...".to_string()),
tags: vec!["交易".to_string(), "DeFi".to_string()],
};
let update_instruction = AgentRegistryInstruction::UpdateAgentStatus {
new_status: AgentStatus::Active as u8,
};
use mcp_server_registry::instruction::McpServerRegistryInstruction;
let instruction = McpServerRegistryInstruction::RegisterMcpServer {
server_id: "金融数据服务器".to_string(),
name: "金融数据 MCP 服务器".to_string(),
server_version: "2.1.0".to_string(),
service_endpoint: "https://api.findata.com/mcp".to_string(),
documentation_url: Some("https://docs.findata.com".to_string()),
server_capabilities_summary: Some("实时金融数据和分析工具".to_string()),
supports_resources: true,
supports_tools: true,
supports_prompts: false,
onchain_tool_definitions: vec![
McpToolDefinitionOnChainInput {
name: "获取股票价格".to_string(),
description_hash: [1u8; 32],
input_schema_hash: [2u8; 32],
output_schema_hash: [3u8; 32],
tags: vec!["股票".to_string(), "价格".to_string()],
}
],
onchain_resource_definitions: vec![
McpResourceDefinitionOnChainInput {
uri_pattern: "股票://符号/*".to_string(),
description_hash: [4u8; 32],
tags: vec!["股票".to_string()],
}
],
onchain_prompt_definitions: vec![],
full_capabilities_uri: Some("https://ipfs.io/ipfs/QmServer...".to_string()),
tags: vec!["金融".to_string(), "数据".to_string()],
};
// 导出 PDA 以直接查找代理
let (agent_pda, _) = Pubkey::find_program_address(
&[AGENT_REGISTRY_PDA_SEED, "my-agent-id".as_bytes()],
&agent_registry::id(),
);
// 获取代理数据
let agent_data = client.get_account_data(&agent_pda)?;
let agent_entry = AgentRegistryEntryV1::try_from_slice(&agent_data)?;
// 监听代理注册事件
client.on_logs_subscribe(
RpcTransactionLogsFilter::Mentions(vec![agent_registry::id().to_string()]),
RpcTransactionLogsConfig {
commitment: Some(CommitmentConfig::confirmed()),
},
)?;
// 处理事件以进行链下索引
for log in logs {
if log.contains("AgentRegistered") {
// 解析并索引代理数据
let event: AgentRegistered = parse_event(&log)?;
index_agent(event).await?;
}
}
# 运行所有测试
cargo test --all
# 运行带覆盖率的测试
cargo test --all -- --test-threads=1
# 运行特定测试类别
cargo test validation_tests
cargo test authorization_tests
cargo test integration_tests
# 启动本地验证器
solana-test-validator
# 部署程序
./scripts/deploy-devnet.sh
# 配置为开发网
solana config set --url devnet
# 验证部署
./scripts/deploy-devnet.sh
./scripts/verify.sh
Solana AI 注册表目前在 Solana 开发网上部署并运行:
BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkprBCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR# 配置为开发网
solana config set --url devnet
# 查询代理注册表程序信息
solana program show BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr
# 查询 MCP 服务器注册表程序信息
solana program show BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR
# 列出所有代理账户(需要自定义 RPC 调用)
solana account BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr --output json
# 列出所有 MCP 服务器账户(需要自定义 RPC 调用)
solana account BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX2sR2SR --output json
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com');
// 程序地址
const AGENT_REGISTRY_PROGRAM_ID = new PublicKey('BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr');
const MCP_REGISTRY_PROGRAM_ID = new PublicKey('BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR');
// 查询所有代理账户
async function getAllAgents() {
const accounts = await connection.getProgramAccounts(AGENT_REGISTRY_PROGRAM_ID);
return accounts.map(account => ({
pubkey: account.pubkey.toString(),
data: account.account.data,
owner: account.account.owner.toString()
}));
}
// 查询所有 MCP 服务器账户
async function getAllMcpServers() {
const accounts = await connection.getProgramAccounts(MCP_REGISTRY_PROGRAM_ID);
return accounts.map(account => ({
pubkey: account.pubkey.toString(),
data: account.account.data,
owner: account.account.owner.toString()
}));
}
// 通过 PDA 查询特定代理
async function getAgentByOwner(ownerPubkey: PublicKey) {
const [agentPda] = PublicKey.findProgramAddressSync(
[Buffer.from("agent"), ownerPubkey.toBuffer()],
AGENT_REGISTRY_PROGRAM_ID
);
const accountInfo = await connection.getAccountInfo(agentPda);
return accountInfo;
}
// 通过 PDA 查询特定 MCP 服务器
async function getMcpServerByOwner(ownerPubkey: PublicKey) {
const [serverPda] = PublicKey.findProgramAddressSync(
[Buffer.from("mcp_server"), ownerPubkey.toBuffer()],
MCP_REGISTRY_PROGRAM_ID
);
const accountInfo = await connection.getAccountInfo(serverPda);
return accountInfo;
}
from solana.rpc.api import Client
from solana.publickey import PublicKey
# 连接到开发网
client = Client("https://api.devnet.solana.com")
# 程序地址
AGENT_REGISTRY_PROGRAM_ID = PublicKey("BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr")
MCP_REGISTRY_PROGRAM_ID = PublicKey("BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR")
# 查询所有代理账户
def get_all_agents():
response = client.get_program_accounts(AGENT_REGISTRY_PROGRAM_ID)
return response
# 查询所有 MCP 服务器账户
def get_all_mcp_servers():
response = client.get_program_accounts(MCP_REGISTRY_PROGRAM_ID)
return response
# 查询特定账户
def get_account_info(pubkey_str):
pubkey = PublicKey(pubkey_str)
response = client.get_account_info(pubkey)
return response
use solana_client::rpc_client::RpcClient;
use solana_sdk::pubkey::Pubkey;
use std::str::FromStr;
// 连接到开发网
let rpc_client = RpcClient::new("https://api.devnet.solana.com");
// 程序地址
let agent_registry_program_id = Pubkey::from_str("BruRLHGfNaf6C5HKUqFu6md5ePJNELafm1vZdhctPkpr").unwrap();
let mcp_registry_program_id = Pubkey::from_str("BCBVehUHR3yhbDbvhV3QHS3s27k3LTbpX5CrXQ2sR2SR").unwrap();
// 查询所有代理账户
let agent_accounts = rpc_client.get_program_accounts(&agent_registry_program_id)?;
// 查询所有 MCP 服务器账户
let mcp_accounts = rpc_client.get_program_accounts(&mcp_registry_program_id)?;
// 查询特定账户
let account_info = rpc_client.get_account(&some_pubkey)?;
# 配置为主网
solana config set --url mainnet-beta
# 部署(需要安全审计)
./scripts/deploy-mainnet.sh
RegisterAgent: 创建新的代理条目UpdateAgentDetails: 修改代理信息UpdateAgentStatus: 更改代理操作状态DeregisterAgent: 标记代理为已注销