This is page 1 of 2. Use http://codebase.md/nftgo/mcp-nftgo-api?page={x} to view the full context. # Directory Structure ``` ├── .dockerignore ├── .prettierignore ├── .prettierrc ├── Dockerfile ├── package.json ├── pnpm-lock.yaml ├── README.md ├── smithery.yaml ├── src │ ├── .gitignore │ ├── index.ts │ ├── nftgo.ts │ └── openapi-spec.ts └── tsconfig.json ``` # Files -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- ``` dist node_modules .git .idea package-lock.json pnpm-lock.yaml *.log ``` -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- ``` node_modules npm-debug.log dist Dockerfile .dockerignore .git .gitignore .idea .vscode *.log ``` -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- ``` { "semi": true, "singleQuote": true, "tabWidth": 2, "printWidth": 100, "trailingComma": "es5", "bracketSpacing": true, "arrowParens": "avoid" } ``` -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- ``` # Dependency directories node_modules/ jspm_packages/ # TypeScript cache *.tsbuildinfo # Compiled output dist/ build/ out/ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* # Environment variables .env .env.test .env.local .env.development.local .env.test.local .env.production.local # IDE files .idea/ .vscode/ *.sublime-project *.sublime-workspace .project .classpath .c9/ *.launch .settings/ *.swp *.swo # OS files .DS_Store Thumbs.db /tmp/ .pnpm-store ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # NFTGo MCP A Model Context Protocol server that provides HTTP request to NFTGo Developer API based on NFTGo [API documentation](https://docs.nftgo.io/reference/introduction). Currently only support Ethereum. ## Key Features **1. NFT Collection** - Retrieve Collection Details: Fetch metadata and statistics for specific NFT collections. - List Collections: Obtain a list of NFT collections with filtering and sorting options. **2. NFT Asset** - Get NFT Details: Access detailed information about individual NFTs, including metadata and ownership. - List NFTs: Retrieve lists of NFTs based on various criteria such as collection, owner, or traits. **3. Market Data and Analytics** - Market Trends: Analyze market trends and metrics over time. - Price History: Access historical pricing data for NFTs and collections. - Volume and Sales Data: Retrieve data on trading volumes and sales activities. **4. User and Wallet Information** - Wallet Holdings: View NFTs held by specific wallet addresses. - Transaction History: Access the transaction history associated with wallets or NFTs. **5. Search and Filtering Capabilities** - Advanced Search: Perform searches across NFTs and collections using various filters and parameters. - Trait-Based Filtering: Filter NFTs based on specific traits or attributes. **6. Real-Time Data and Notifications** - Webhooks: Set up webhooks to receive real-time updates on specific events or changes. - Live Data Feeds: Access live data streams for market activities and NFT events. ## Usage with Claude Desktop To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`: ### NPX ```json { "mcpServers": { "nftgoapi": { "command": "npx", "args": ["-y", "@nftgo/mcp-nftgo-api", "NFTGO-API-KEY"] } } } ``` Replace `NFTGO-API-KEY` with your API key. You can create your free `NFTGo-API-KEY` [here](https://nftgo.io/developers). ## Building ```sh pnpm install pnpm build ``` ## License This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- ```dockerfile FROM node:20-bookworm WORKDIR /app # Copy package files COPY package*.json ./ # Install dependencies RUN npm install # Copy application code COPY . . # Build the application RUN npm run build # Command will be provided by smithery.yaml CMD ["node", "dist/index.js"] ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- ```yaml startCommand: type: stdio configSchema: type: object properties: apiKey: type: string description: 'NFTGo API Key' required: ['apiKey'] commandFunction: | function getCommand(config) { return { command: "node", args: ["dist/index.js", config.apiKey], env: { NFTGO_API_KEY: config.apiKey } } } build: dockerfile: Dockerfile dockerBuildPath: . ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json { "name": "@nftgo/mcp-nftgo-api", "version": "0.1.2", "description": "NFTGo API MCP Server", "license": "MIT", "author": "NFTGo", "homepage": "https://nftgo.io", "type": "module", "bin": { "nftgo-api": "dist/index.js" }, "files": [ "dist" ], "scripts": { "build": "tsc && shx chmod +x dist/*.js", "start": "node dist/index.js", "watch": "tsc --watch", "format": "prettier --write .", "format:check": "prettier --check ." }, "dependencies": { "@modelcontextprotocol/sdk": "^1.9.0", "zod": "^3.24.3" }, "devDependencies": { "@types/node": "^20.0.0", "prettier": "^3.2.5", "shx": "^0.3.4", "typescript": "^5.6.2" } } ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { callTool, listResources, listTools, readResource, setNftgoApiKey, getNftgoApiKey, } from './nftgo.js'; const server = new Server( { name: 'nftgo-api', description: 'This is an assistant for NFT data in ethereum build with NFTGo API V1.1', version: '0.1.0', }, { capabilities: { resources: {}, tools: {}, }, } ); const args = process.argv.slice(2); setNftgoApiKey(args[0]); if (args.length === 0 || !getNftgoApiKey()) { console.error('Please provide a valid NFTGo API key as a command-line argument'); process.exit(1); } server.setRequestHandler(ListResourcesRequestSchema, listResources); server.setRequestHandler(ReadResourceRequestSchema, async request => { const uri = request.params.uri; return readResource(uri); }); server.setRequestHandler(ListToolsRequestSchema, listTools); server.setRequestHandler(CallToolRequestSchema, callTool); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); } main(); ``` -------------------------------------------------------------------------------- /src/nftgo.ts: -------------------------------------------------------------------------------- ```typescript import { z } from 'zod'; import { CallToolRequest } from '@modelcontextprotocol/sdk/types.js'; import { openapiSpec as openapiSpecJson } from './openapi-spec.js'; let nftgoApiKey: string; const host = 'https://data-api.nftgo.io'; const RequestSchema = z.object({ type: z.enum(['POST', 'GET', 'PUT', 'DELETE']), url: z.string(), headers: z.record(z.string(), z.string()).optional(), body: z.any().optional(), }); const openapiSpec = openapiSpecJson as ApiSpec; type ApiSpec = { paths: { [key: string]: PathSchema; }; components: { schemas: { [key: string]: object; }; }; }; type PathSchema = { get?: { summary?: string; description?: string; parameters?: Array<{ name: string; in: string; description: string; required: boolean; schema: { type: string; }; }>; requestBody?: { content?: { 'application/json'?: { schema?: { $ref?: string; }; }; }; }; [key: string]: string | object | undefined; }; post?: { summary?: string; description?: string; parameters?: Array<{ name: string; in: string; description: string; required: boolean; schema: { type: string; }; }>; requestBody?: { content?: { 'application/json'?: { schema?: { $ref?: string; }; }; }; }; [key: string]: string | object | undefined; }; }; export function getNftgoApiKey() { return nftgoApiKey; } export function setNftgoApiKey(key: string) { nftgoApiKey = key; } export async function makeRequest( url: string, type: string, headers: Record<string, string>, body: any ) { try { headers['X-API-KEY'] = getNftgoApiKey(); const response = await fetch(url, { method: type, headers, body: body && (type === 'POST' || type === 'PUT') ? JSON.stringify(body) : undefined, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return { status: response.status, data: await response.text(), headers: Object.fromEntries(response.headers), }; } catch (error) { console.error('Error making request:', error); throw error; } } export function listResources() { const resources = []; for (let [path, schema] of Object.entries(openapiSpec.paths)) { schema = schema as PathSchema; const detail = schema.get || schema.post; resources.push({ uri: new URL(`${host}${path}`).href, mimeType: 'application/json', name: `${detail?.summary || detail?.description} API Doc`, }); } return { resources: resources, }; } function getAPIRequestSpec(path: string) { const schema = openapiSpec.paths[path]; const detail = schema.get || schema.post; const spec: any = { method: schema.get ? 'GET' : 'POST', }; if (detail?.parameters) { spec.parameters = detail.parameters; } if (detail?.requestBody) { const bodyRef = detail.requestBody?.content?.['application/json']?.schema?.['$ref']; if (bodyRef) { const bodySchema = openapiSpec.components?.schemas?.[bodyRef.replace('#/components/schemas/', '')]; spec.body = bodySchema; } } return JSON.stringify(spec, null, 2); } export function readResource(uri: string) { const path = decodeURIComponent(uri.replace(host, '')); return { contents: [ { uri, mimeType: 'application/json', text: getAPIRequestSpec(path), }, ], }; } export function listTools() { return { tools: [ { name: 'request', description: `Make an HTTP request to NFTGo API(${host}) based on the OpenAPI specifications returned by the api-path-schema tool.`, inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'Type of the request. GET, POST, PUT, DELETE', }, url: { type: 'string', description: 'Url to make the request to', }, headers: { type: 'object', description: 'Headers to include in the request', }, body: { type: 'object', description: 'Body to include in the request', }, }, required: ['type', 'url'], }, }, { name: 'api-path-schema', description: `Get detail description and parameters of a NFT API path based on OpenAPI specifications.`, inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Path to get the api detail of, format should be like: /eth/v1/nft/name/{keywords} or /eth/v1/nft/{contract}/{tokenId}/metrics', }, }, required: ['path'], }, }, { name: 'api-documentation', description: `Retrieve a comprehensive list of all NFT API endpoints with documentation based on OpenAPI specifications.`, inputSchema: { type: 'object', properties: {}, required: [], }, }, ], }; } export async function callTool(request: CallToolRequest) { const { name, arguments: args } = request.params; try { if (name === 'request') { const { type, url, headers, body } = RequestSchema.parse(args); const response = await makeRequest(url, type, headers || {}, body || {}); return { content: [ { type: 'text', text: JSON.stringify({ response, }), }, ], }; } else if (name === 'api-documentation') { return { content: [ { type: 'text', text: JSON.stringify(listResources()), }, ], }; } else if (name === 'api-path-schema') { return { content: [ { type: 'text', text: getAPIRequestSpec(request.params.arguments?.path as string), }, ], }; } else { throw new Error(`Unknown tool: ${name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error( `Invalid arguments: ${error.errors .map(e => `${e.path.join('.')}: ${e.message}`) .join(', ')}` ); } throw error; } } ```