diff --git a/.github/actions/generate-mcp-tools/generate-tools.mjs b/.github/actions/generate-mcp-tools/generate-tools.mjs new file mode 100644 index 0000000..20ace7e --- /dev/null +++ b/.github/actions/generate-mcp-tools/generate-tools.mjs @@ -0,0 +1,156 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { zodToJsonSchema } from "zod-to-json-schema"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, "../../.."); +const README_PATH = path.join(ROOT, "README.md"); +const TOOLS_DIR = path.join(ROOT, "src", "tools"); + +const START = ""; +const END = ""; + +/** + * Load MCP tools + * Scans for any export that looks like an MCP tool: + * { + * name: string, + * description: string, + * parameters?: ZodSchema + * schema?: JSONSchema + * } + */ +async function loadTools() { + const files = fs + .readdirSync(TOOLS_DIR) + .filter((f) => f.endsWith(".ts") && f !== "index.ts"); + + const toolPromises = files.map(async (file) => { + const mod = await import(path.join(TOOLS_DIR, file)); + + const matches = Object.values(mod).filter( + (exp) => + exp && + typeof exp === "object" && + typeof exp.name === "string" && + typeof exp.description === "string" && + (exp.parameters || exp.schema), + ); + + if (matches.length === 0) { + return null; + } + + if (matches.length > 1) { + console.warn( + `Warning: ${file} exports multiple MCP-like tools. Using the first one.`, + ); + } + + return matches[0]; + }); + + const loadedTools = await Promise.all(toolPromises); + const tools = loadedTools.filter(Boolean); + + return tools.sort((a, b) => a.name.localeCompare(b.name)); +} + +function renderSchema(schema) { + if (!schema) { + return "_No parameters_"; + } + + // If this is a Zod schema, convert it to JSON Schema + const jsonSchema = + typeof schema.safeParse === "function" ? zodToJsonSchema(schema) : schema; + + const properties = jsonSchema.properties ?? {}; + const required = new Set(jsonSchema.required ?? []); + + if (Object.keys(properties).length === 0) { + return "_No parameters_"; + } + + // Check if any param has a default value to determine table columns + const hasDefaults = Object.values(properties).some( + (prop) => prop.default !== undefined, + ); + + // Build table header + let table = hasDefaults + ? "| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n" + : "| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n"; + + // Build table rows + for (const [key, prop] of Object.entries(properties)) { + const type = Array.isArray(prop.type) + ? prop.type.join(" | ") + : (prop.type ?? "unknown"); + + const requiredStr = required.has(key) ? "โœ…" : ""; + const description = prop.description ?? ""; + const defaultVal = + prop.default !== undefined ? JSON.stringify(prop.default) : ""; + + if (hasDefaults) { + table += `| \`${key}\` | ${type} | ${requiredStr} | ${defaultVal} | ${description} |\n`; + } else { + table += `| \`${key}\` | ${type} | ${requiredStr} | ${description} |\n`; + } + } + + return table.trim(); +} + +function renderMarkdown(tools) { + let md = ""; + + for (const tool of tools) { + const schema = tool.parameters || tool.schema; + + md += `### \`${tool.name}\`\n`; + md += `${tool.description}\n\n`; + md += `${renderSchema(schema)}\n\n`; + } + + return md.trim(); +} + +function updateReadme({ readme, tools }) { + if (!readme.includes(START) || !readme.includes(END)) { + throw new Error("README missing AUTO-GENERATED TOOLS markers"); + } + + const toolsMd = renderMarkdown(tools); + + return readme.replace( + new RegExp(`${START}[\\s\\S]*?${END}`, "m"), + `${START}\n\n${toolsMd}\n\n${END}`, + ); +} + +async function main() { + try { + const readme = fs.readFileSync(README_PATH, "utf8"); + const tools = await loadTools(); + + if (tools.length === 0) { + console.warn("Warning: No tools found!"); + } + + const updated = updateReadme({ readme, tools }); + + fs.writeFileSync(README_PATH, updated); + console.log(`Synced ${tools.length} MCP tools to README.md`); + } catch (error) { + console.error("Error updating README:", error); + process.exit(1); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/.github/workflows/sync-tools.yml b/.github/workflows/sync-tools.yml new file mode 100644 index 0000000..81f62f4 --- /dev/null +++ b/.github/workflows/sync-tools.yml @@ -0,0 +1,47 @@ +name: Sync MCP Tool Docs + +on: + push: + branches: + - main + +permissions: + contents: write + +jobs: + sync-tools: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: | + if [ -f pnpm-lock.yaml ]; then + corepack enable + pnpm install --frozen-lockfile + else + npm install + fi + + - name: Generate MCP tool documentation + run: npx tsx .github/actions/generate-mcp-tools/generate-tools.mjs + + - name: Commit README changes + run: | + if git diff --quiet; then + echo "No README changes" + exit 0 + fi + + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add README.md + git commit -m "chore: auto-sync MCP tool documentation" + git push diff --git a/README.md b/README.md index f053feb..c4aec6f 100644 --- a/README.md +++ b/README.md @@ -1,165 +1,161 @@ -# ๐ŸŒŠ Near Agent MCP Server +# ๐ŸŒŠ NEAR Agent MCP Server -A Model Context Protocol (MCP) server enabling smart contract interaction, transaction handling, and event listening on the NEAR blockchain for AI agents and applications. +[![npm version](https://img.shields.io/npm/v/@iqai/mcp-near-agent.svg)](https://www.npmjs.com/package/@iqai/mcp-near-agent) +[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC) -## ๐Ÿ“Œ Overview +## ๐Ÿ“– Overview -This MCP server provides seamless integration with the NEAR Protocol blockchain for any MCP-compatible client or agent framework. +The NEAR Agent MCP Server enables AI agents to interact with the [NEAR Protocol](https://near.org) blockchain. This server provides smart contract interaction, transaction handling, and event listening capabilities with AI-driven processing. -- โœ… Execute contract methods and transactions on NEAR blockchain -- โœ… Listen to and respond to contract events with AI processing -- โœ… View contract data and account information -- โœ… Handle custom logic through intelligent event listeners -- โœ… Compatible with any MCP client (Claude Desktop, Cursor, custom agents) +By implementing the Model Context Protocol (MCP), this server allows Large Language Models (LLMs) to monitor blockchain events, process them with AI intelligence, and respond back to smart contracts, bridging the gap between AI and decentralized applications. -## ๐Ÿ”„ AI-Driven Event Processing Workflow +## โœจ Features -The server enables an "AI in the loop" workflow: +* **Event Watching**: Monitor NEAR smart contracts for specific events in real-time. +* **AI-Driven Processing**: Automatically process blockchain events with AI and send responses back to contracts. +* **Subscription Management**: Manage multiple event subscriptions with detailed statistics. +* **Flexible Configuration**: Customizable polling intervals, response methods, and network settings. -1. ๐Ÿ”— Smart contract transaction triggers an event and pauses execution -2. ๐Ÿค– MCP server detects the event and requests AI processing from the client -3. ๐Ÿง  AI client processes the event data and provides intelligent response -4. โ†ฉ๏ธ Server sends AI response back to blockchain via transaction -5. โœ… Original smart contract resumes with the AI-provided data +## ๐Ÿ“ฆ Installation -## ๐Ÿ›  Installation +### ๐Ÿš€ Using npx (Recommended) -### Option 1: Using `pnpm dlx` (Recommended) -Run directly without installation: -```bash -pnpm dlx mcp-near-agent -``` +To use this server without installing it globally: -### Option 2: Global Installation ```bash -pnpm add -g mcp-near-agent +npx @iqai/mcp-near-agent ``` -### Option 3: From Source +### ๐Ÿ”ง Build from Source + ```bash -git clone +git clone https://github.com/IQAIcom/mcp-near-agent.git cd mcp-near-agent pnpm install pnpm run build ``` -## โš™ Configuration - -Set these environment variables in your MCP client configuration: +## โšก Running with an MCP Client -| ๐Ÿ”ง Variable Name | ๐ŸŒœ Description | -|------------------|----------------| -| `ACCOUNT_ID` | Your NEAR account ID for authentication ๐Ÿ†” | -| `ACCOUNT_KEY` | Private key for your NEAR account (ed25519: or secp256k1: format) ๐Ÿ”‘ | -| `NEAR_NETWORK_ID` | NEAR network ("mainnet", "testnet", "betanet") - defaults to "mainnet" ๐ŸŒ | -| `NEAR_NODE_URL` | Custom NEAR RPC endpoint (optional) ๐Ÿ”— | -| `NEAR_GAS_LIMIT` | Gas limit for transactions (optional) โ›ฝ | +Add the following configuration to your MCP client settings (e.g., `claude_desktop_config.json`). -## ๐Ÿš€ MCP Client Configuration +### ๐Ÿ“‹ Minimal Configuration -### Custom Agent Framework -```typescript -import { MCPClient } from "your-mcp-client"; - -const client = new MCPClient({ - serverCommand: "pnpm", - serverArgs: ["dlx", "mcp-near-agent"], - serverEnv: { - ACCOUNT_ID: "your-account.testnet", - ACCOUNT_KEY: "ed25519:your_private_key_here", - NEAR_NETWORK_ID: "testnet" +```json +{ + "mcpServers": { + "near-agent": { + "command": "npx", + "args": ["-y", "@iqai/mcp-near-agent"], + "env": { + "ACCOUNT_ID": "your-account.near", + "ACCOUNT_KEY": "ed25519:your_private_key_here" + } + } } -}); +} ``` -## ๐Ÿ”ง Available Tools +### โš™๏ธ Advanced Configuration (Local Build) -### `watch_near_event` -Start watching for specific events on a NEAR contract: -```typescript +```json { - eventName: "run_agent", // Event to watch for - contractId: "contract.testnet", // Contract to monitor - responseMethodName: "agent_response", // Method to call with AI response - cronExpression: "*/10 * * * * *" // Optional: polling frequency + "mcpServers": { + "near-agent": { + "command": "node", + "args": ["/absolute/path/to/mcp-near-agent/dist/index.js"], + "env": { + "ACCOUNT_ID": "your-account.near", + "ACCOUNT_KEY": "ed25519:your_private_key_here", + "NEAR_NETWORK_ID": "mainnet", + "NEAR_NODE_URL": "https://rpc.mainnet.near.org" + } + } + } } ``` -### `stop_watching_near_event` -Stop watching for specific events: -```typescript -{ - contractId: "contract.testnet", - eventName: "run_agent" -} -``` +## ๐Ÿ” Configuration (Environment Variables) -### `list_watched_near_events` -List all currently watched events and statistics: -```typescript -{ - includeStats: true // Optional: include performance statistics -} -``` +| Variable | Required | Description | Default | +| :--- | :--- | :--- | :--- | +| `ACCOUNT_ID` | Yes | Your NEAR account ID for authentication | - | +| `ACCOUNT_KEY` | Yes | Private key for your NEAR account (ed25519: or secp256k1: format) | - | +| `NEAR_NETWORK_ID` | No | NEAR network ("mainnet", "testnet", "betanet") | `mainnet` | +| `NEAR_NODE_URL` | No | Custom NEAR RPC endpoint | - | +| `NEAR_GAS_LIMIT` | No | Gas limit for transactions | - | -## ๐ŸŽฏ Usage Example +## ๐Ÿ’ก Usage Examples -1. **Start the MCP server** with your client -2. **Watch for events** using the MCP tool: - ``` - Use watch_near_event with: - - eventName: "price_request" - - contractId: "oracle.testnet" - - responseMethodName: "price_response" - ``` -3. **AI processes events automatically** when they occur on the blockchain -4. **Monitor with** `list_watched_near_events` to see status and statistics +### ๐Ÿ”” Event Watching +* "Watch for 'run_agent' events on contract oracle.near" +* "Start monitoring price_request events on my-contract.testnet" +* "Set up a listener for transfer events with 5-second polling" -## ๐ŸŒœ Event Processing Flow +### ๐Ÿ“Š Subscription Management +* "List all my active event subscriptions" +* "Show statistics for my event watchers" +* "Stop watching events on contract oracle.near" -When a blockchain event is detected: +### ๐Ÿค– AI-Driven Workflows +* "Process incoming oracle requests and respond with AI analysis" +* "Monitor for user queries and provide intelligent responses" -1. ๐Ÿ“ก **Event Detection**: Server monitors blockchain for specified events -2. ๐Ÿค– **AI Request**: Server requests sampling from MCP client with event data -3. ๐Ÿง  **AI Processing**: Client processes event and returns intelligent response -4. ๐Ÿ“ค **Blockchain Response**: Server sends AI response back to contract -5. ๐Ÿ“Š **Statistics**: Performance metrics are tracked and available +## ๐Ÿ› ๏ธ MCP Tools -## ๐Ÿ“Š Response Format + -The server provides structured responses: + -- โœ” **Success/failure status** with detailed messages -- ๐Ÿ”— **Subscription IDs** for tracking active watchers -- ๐Ÿ“ˆ **Performance statistics** (success rates, processing times) -- ๐ŸŽฏ **Event details** (contract, event type, timestamps) -- ๐Ÿ’ก **Helpful guidance** and troubleshooting tips +## ๐Ÿ‘จโ€๐Ÿ’ป Development -## โŒ Error Handling +### ๐Ÿ—๏ธ Build Project +```bash +pnpm run build +``` + +### ๐Ÿ‘๏ธ Development Mode (Watch) +```bash +pnpm run watch +``` -The server handles common NEAR-related errors: +### โœ… Linting & Formatting +```bash +pnpm run lint +pnpm run format +``` + +### ๐Ÿงช Running Tests +```bash +pnpm test +``` -- ๐Ÿšจ **Invalid contract calls** or method names -- ๐Ÿ’ธ **Insufficient account balance** for transactions -- ๐Ÿ”‘ **Authentication issues** with account credentials -- ๐ŸŒ **Network connectivity problems** with NEAR RPC -- ๐Ÿšซ **Contract execution errors** returned by smart contracts -- โฑ๏ธ **Timeout handling** for long-running operations +### ๐Ÿ“ Project Structure +* `src/tools/`: Individual tool definitions +* `src/services/`: Event watcher, auth manager, and business logic +* `src/types.ts`: TypeScript type definitions +* `src/index.ts`: Server entry point + +## ๐Ÿ”„ AI-Driven Event Processing Workflow + +The server enables an "AI in the loop" workflow: + +1. ๐Ÿ”— Smart contract transaction triggers an event and pauses execution +2. ๐Ÿค– MCP server detects the event and requests AI processing from the client +3. ๐Ÿง  AI client processes the event data and provides intelligent response +4. โ†ฉ๏ธ Server sends AI response back to blockchain via transaction +5. โœ… Original smart contract resumes with the AI-provided data -## ๐Ÿ” Monitoring & Debugging +## ๐Ÿ“š Resources -- **Real-time logging** of all blockchain interactions -- **Performance metrics** for event processing -- **Error tracking** with detailed error messages -- **Statistics dashboard** via `list_watched_near_events` +* [NEAR Protocol Documentation](https://docs.near.org) +* [Model Context Protocol (MCP)](https://modelcontextprotocol.io) +* [NEAR JavaScript API](https://github.com/near/near-api-js) -## ๐Ÿ›ก Security Notes +## โš ๏ธ Disclaimer -- **Private keys** are handled securely in memory only -- **Environment variables** should be properly secured -- **Gas limits** prevent runaway transaction costs -- **Error handling** prevents sensitive data leakage +This project interacts with the NEAR blockchain and requires private keys for transaction signing. Users should exercise caution, secure their credentials, and verify all transactions independently. Blockchain operations involve risk and may incur gas fees. -## ๐Ÿค Contributing +## ๐Ÿ“„ License -This MCP server is designed to work with any MCP-compatible client or agent framework. Contributions welcome! +[ISC](LICENSE)