#
tokens: 4867/50000 11/12 files (page 1/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 2. Use http://codebase.md/nftgo/mcp-nftgo-api?lines=true&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:
--------------------------------------------------------------------------------

```
1 | dist
2 | node_modules
3 | .git
4 | .idea
5 | package-lock.json
6 | pnpm-lock.yaml
7 | *.log 
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
 1 | node_modules
 2 | npm-debug.log
 3 | dist
 4 | Dockerfile
 5 | .dockerignore
 6 | .git
 7 | .gitignore
 8 | .idea
 9 | .vscode
10 | *.log 
```

--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------

```
 1 | {
 2 |   "semi": true,
 3 |   "singleQuote": true,
 4 |   "tabWidth": 2,
 5 |   "printWidth": 100,
 6 |   "trailingComma": "es5",
 7 |   "bracketSpacing": true,
 8 |   "arrowParens": "avoid"
 9 | }
10 | 
```

--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | jspm_packages/
 4 | 
 5 | # TypeScript cache
 6 | *.tsbuildinfo
 7 | 
 8 | # Compiled output
 9 | dist/
10 | build/
11 | out/
12 | 
13 | # Logs
14 | logs
15 | *.log
16 | npm-debug.log*
17 | yarn-debug.log*
18 | yarn-error.log*
19 | lerna-debug.log*
20 | 
21 | # Environment variables
22 | .env
23 | .env.test
24 | .env.local
25 | .env.development.local
26 | .env.test.local
27 | .env.production.local
28 | 
29 | # IDE files
30 | .idea/
31 | .vscode/
32 | *.sublime-project
33 | *.sublime-workspace
34 | .project
35 | .classpath
36 | .c9/
37 | *.launch
38 | .settings/
39 | *.swp
40 | *.swo
41 | 
42 | # OS files
43 | .DS_Store
44 | Thumbs.db 
45 | /tmp/
46 | .pnpm-store
47 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # NFTGo MCP
 2 | 
 3 | A Model Context Protocol server that provides HTTP request to NFTGo Developer API based on NFTGo [API documentation](https://docs.nftgo.io/reference/introduction).
 4 | 
 5 | Currently only support Ethereum.
 6 | 
 7 | ## Key Features
 8 | **1. NFT Collection**
 9 | - Retrieve Collection Details: Fetch metadata and statistics for specific NFT collections.
10 | - List Collections: Obtain a list of NFT collections with filtering and sorting options.
11 | 
12 | **2. NFT Asset**
13 | - Get NFT Details: Access detailed information about individual NFTs, including metadata and ownership.
14 | - List NFTs: Retrieve lists of NFTs based on various criteria such as collection, owner, or traits.
15 | 
16 | **3. Market Data and Analytics**
17 | - Market Trends: Analyze market trends and metrics over time.
18 | - Price History: Access historical pricing data for NFTs and collections.
19 | - Volume and Sales Data: Retrieve data on trading volumes and sales activities.
20 | 
21 | **4. User and Wallet Information**
22 | - Wallet Holdings: View NFTs held by specific wallet addresses.
23 | - Transaction History: Access the transaction history associated with wallets or NFTs.
24 | 
25 | **5. Search and Filtering Capabilities**
26 | - Advanced Search: Perform searches across NFTs and collections using various filters and parameters.
27 | - Trait-Based Filtering: Filter NFTs based on specific traits or attributes.
28 | 
29 | **6. Real-Time Data and Notifications**
30 | - Webhooks: Set up webhooks to receive real-time updates on specific events or changes.
31 | - Live Data Feeds: Access live data streams for market activities and NFT events.
32 | 
33 | ## Usage with Claude Desktop
34 | 
35 | To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`:
36 | 
37 | ### NPX
38 | 
39 | ```json
40 | {
41 |   "mcpServers": {
42 |     "nftgoapi": {
43 |       "command": "npx",
44 |       "args": ["-y", "@nftgo/mcp-nftgo-api", "NFTGO-API-KEY"]
45 |     }
46 |   }
47 | }
48 | ```
49 | 
50 | Replace `NFTGO-API-KEY` with your API key. You can create your free `NFTGo-API-KEY` [here](https://nftgo.io/developers).
51 | 
52 | ## Building
53 | 
54 | ```sh
55 | pnpm install
56 | pnpm build
57 | ```
58 | 
59 | ## License
60 | 
61 | 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.
62 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | FROM node:20-bookworm
 2 | 
 3 | WORKDIR /app
 4 | 
 5 | # Copy package files
 6 | COPY package*.json ./
 7 | 
 8 | # Install dependencies
 9 | RUN npm install
10 | 
11 | # Copy application code
12 | COPY . .
13 | 
14 | # Build the application
15 | RUN npm run build
16 | 
17 | # Command will be provided by smithery.yaml
18 | CMD ["node", "dist/index.js"]
19 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "outDir": "dist",
 7 |     "rootDir": "src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "resolveJsonModule": true
13 |   },
14 |   "include": ["src/**/*"],
15 |   "exclude": ["node_modules", "dist"]
16 | }
17 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | startCommand:
 2 |   type: stdio
 3 |   configSchema:
 4 |     type: object
 5 |     properties:
 6 |       apiKey:
 7 |         type: string
 8 |         description: 'NFTGo API Key'
 9 |     required: ['apiKey']
10 |   commandFunction: |
11 |     function getCommand(config) {
12 |       return {
13 |         command: "node",
14 |         args: ["dist/index.js", config.apiKey],
15 |         env: {
16 |           NFTGO_API_KEY: config.apiKey
17 |         }
18 |       }
19 |     }
20 | 
21 | build:
22 |   dockerfile: Dockerfile
23 |   dockerBuildPath: .
24 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@nftgo/mcp-nftgo-api",
 3 |   "version": "0.1.2",
 4 |   "description": "NFTGo API MCP Server",
 5 |   "license": "MIT",
 6 |   "author": "NFTGo",
 7 |   "homepage": "https://nftgo.io",
 8 |   "type": "module",
 9 |   "bin": {
10 |     "nftgo-api": "dist/index.js"
11 |   },
12 |   "files": [
13 |     "dist"
14 |   ],
15 |   "scripts": {
16 |     "build": "tsc && shx chmod +x dist/*.js",
17 |     "start": "node dist/index.js",
18 |     "watch": "tsc --watch",
19 |     "format": "prettier --write .",
20 |     "format:check": "prettier --check ."
21 |   },
22 |   "dependencies": {
23 |     "@modelcontextprotocol/sdk": "^1.9.0",
24 |     "zod": "^3.24.3"
25 |   },
26 |   "devDependencies": {
27 |     "@types/node": "^20.0.0",
28 |     "prettier": "^3.2.5",
29 |     "shx": "^0.3.4",
30 |     "typescript": "^5.6.2"
31 |   }
32 | }
33 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | #!/usr/bin/env node
 2 | 
 3 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
 4 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
 5 | import {
 6 |   CallToolRequestSchema,
 7 |   ListResourcesRequestSchema,
 8 |   ListToolsRequestSchema,
 9 |   ReadResourceRequestSchema,
10 | } from '@modelcontextprotocol/sdk/types.js';
11 | import {
12 |   callTool,
13 |   listResources,
14 |   listTools,
15 |   readResource,
16 |   setNftgoApiKey,
17 |   getNftgoApiKey,
18 | } from './nftgo.js';
19 | 
20 | const server = new Server(
21 |   {
22 |     name: 'nftgo-api',
23 |     description: 'This is an assistant for NFT data in ethereum build with NFTGo API V1.1',
24 |     version: '0.1.0',
25 |   },
26 |   {
27 |     capabilities: {
28 |       resources: {},
29 |       tools: {},
30 |     },
31 |   }
32 | );
33 | 
34 | const args = process.argv.slice(2);
35 | setNftgoApiKey(args[0]);
36 | 
37 | if (args.length === 0 || !getNftgoApiKey()) {
38 |   console.error('Please provide a valid NFTGo API key as a command-line argument');
39 |   process.exit(1);
40 | }
41 | 
42 | server.setRequestHandler(ListResourcesRequestSchema, listResources);
43 | 
44 | server.setRequestHandler(ReadResourceRequestSchema, async request => {
45 |   const uri = request.params.uri;
46 |   return readResource(uri);
47 | });
48 | 
49 | server.setRequestHandler(ListToolsRequestSchema, listTools);
50 | 
51 | server.setRequestHandler(CallToolRequestSchema, callTool);
52 | 
53 | async function main() {
54 |   const transport = new StdioServerTransport();
55 |   await server.connect(transport);
56 | }
57 | 
58 | main();
59 | 
```

--------------------------------------------------------------------------------
/src/nftgo.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { z } from 'zod';
  2 | import { CallToolRequest } from '@modelcontextprotocol/sdk/types.js';
  3 | import { openapiSpec as openapiSpecJson } from './openapi-spec.js';
  4 | 
  5 | let nftgoApiKey: string;
  6 | const host = 'https://data-api.nftgo.io';
  7 | 
  8 | const RequestSchema = z.object({
  9 |   type: z.enum(['POST', 'GET', 'PUT', 'DELETE']),
 10 |   url: z.string(),
 11 |   headers: z.record(z.string(), z.string()).optional(),
 12 |   body: z.any().optional(),
 13 | });
 14 | 
 15 | const openapiSpec = openapiSpecJson as ApiSpec;
 16 | type ApiSpec = {
 17 |   paths: {
 18 |     [key: string]: PathSchema;
 19 |   };
 20 |   components: {
 21 |     schemas: {
 22 |       [key: string]: object;
 23 |     };
 24 |   };
 25 | };
 26 | type PathSchema = {
 27 |   get?: {
 28 |     summary?: string;
 29 |     description?: string;
 30 |     parameters?: Array<{
 31 |       name: string;
 32 |       in: string;
 33 |       description: string;
 34 |       required: boolean;
 35 |       schema: {
 36 |         type: string;
 37 |       };
 38 |     }>;
 39 |     requestBody?: {
 40 |       content?: {
 41 |         'application/json'?: {
 42 |           schema?: {
 43 |             $ref?: string;
 44 |           };
 45 |         };
 46 |       };
 47 |     };
 48 |     [key: string]: string | object | undefined;
 49 |   };
 50 |   post?: {
 51 |     summary?: string;
 52 |     description?: string;
 53 |     parameters?: Array<{
 54 |       name: string;
 55 |       in: string;
 56 |       description: string;
 57 |       required: boolean;
 58 |       schema: {
 59 |         type: string;
 60 |       };
 61 |     }>;
 62 |     requestBody?: {
 63 |       content?: {
 64 |         'application/json'?: {
 65 |           schema?: {
 66 |             $ref?: string;
 67 |           };
 68 |         };
 69 |       };
 70 |     };
 71 |     [key: string]: string | object | undefined;
 72 |   };
 73 | };
 74 | 
 75 | export function getNftgoApiKey() {
 76 |   return nftgoApiKey;
 77 | }
 78 | 
 79 | export function setNftgoApiKey(key: string) {
 80 |   nftgoApiKey = key;
 81 | }
 82 | 
 83 | export async function makeRequest(
 84 |   url: string,
 85 |   type: string,
 86 |   headers: Record<string, string>,
 87 |   body: any
 88 | ) {
 89 |   try {
 90 |     headers['X-API-KEY'] = getNftgoApiKey();
 91 |     const response = await fetch(url, {
 92 |       method: type,
 93 |       headers,
 94 |       body: body && (type === 'POST' || type === 'PUT') ? JSON.stringify(body) : undefined,
 95 |     });
 96 | 
 97 |     if (!response.ok) {
 98 |       throw new Error(`HTTP error! status: ${response.status}`);
 99 |     }
100 | 
101 |     return {
102 |       status: response.status,
103 |       data: await response.text(),
104 |       headers: Object.fromEntries(response.headers),
105 |     };
106 |   } catch (error) {
107 |     console.error('Error making request:', error);
108 |     throw error;
109 |   }
110 | }
111 | 
112 | export function listResources() {
113 |   const resources = [];
114 |   for (let [path, schema] of Object.entries(openapiSpec.paths)) {
115 |     schema = schema as PathSchema;
116 |     const detail = schema.get || schema.post;
117 |     resources.push({
118 |       uri: new URL(`${host}${path}`).href,
119 |       mimeType: 'application/json',
120 |       name: `${detail?.summary || detail?.description} API Doc`,
121 |     });
122 |   }
123 |   return {
124 |     resources: resources,
125 |   };
126 | }
127 | 
128 | function getAPIRequestSpec(path: string) {
129 |   const schema = openapiSpec.paths[path];
130 |   const detail = schema.get || schema.post;
131 |   const spec: any = {
132 |     method: schema.get ? 'GET' : 'POST',
133 |   };
134 |   if (detail?.parameters) {
135 |     spec.parameters = detail.parameters;
136 |   }
137 |   if (detail?.requestBody) {
138 |     const bodyRef = detail.requestBody?.content?.['application/json']?.schema?.['$ref'];
139 |     if (bodyRef) {
140 |       const bodySchema =
141 |         openapiSpec.components?.schemas?.[bodyRef.replace('#/components/schemas/', '')];
142 |       spec.body = bodySchema;
143 |     }
144 |   }
145 |   return JSON.stringify(spec, null, 2);
146 | }
147 | 
148 | export function readResource(uri: string) {
149 |   const path = decodeURIComponent(uri.replace(host, ''));
150 |   return {
151 |     contents: [
152 |       {
153 |         uri,
154 |         mimeType: 'application/json',
155 |         text: getAPIRequestSpec(path),
156 |       },
157 |     ],
158 |   };
159 | }
160 | 
161 | export function listTools() {
162 |   return {
163 |     tools: [
164 |       {
165 |         name: 'request',
166 |         description: `Make an HTTP request to NFTGo API(${host}) based on the OpenAPI specifications returned by the api-path-schema tool.`,
167 |         inputSchema: {
168 |           type: 'object',
169 |           properties: {
170 |             type: {
171 |               type: 'string',
172 |               description: 'Type of the request. GET, POST, PUT, DELETE',
173 |             },
174 |             url: {
175 |               type: 'string',
176 |               description: 'Url to make the request to',
177 |             },
178 |             headers: {
179 |               type: 'object',
180 |               description: 'Headers to include in the request',
181 |             },
182 |             body: {
183 |               type: 'object',
184 |               description: 'Body to include in the request',
185 |             },
186 |           },
187 |           required: ['type', 'url'],
188 |         },
189 |       },
190 |       {
191 |         name: 'api-path-schema',
192 |         description: `Get detail description and parameters of a NFT API path based on OpenAPI specifications.`,
193 |         inputSchema: {
194 |           type: 'object',
195 |           properties: {
196 |             path: {
197 |               type: 'string',
198 |               description:
199 |                 'Path to get the api detail of, format should be like: /eth/v1/nft/name/{keywords} or /eth/v1/nft/{contract}/{tokenId}/metrics',
200 |             },
201 |           },
202 |           required: ['path'],
203 |         },
204 |       },
205 |       {
206 |         name: 'api-documentation',
207 |         description: `Retrieve a comprehensive list of all NFT API endpoints with documentation based on OpenAPI specifications.`,
208 |         inputSchema: {
209 |           type: 'object',
210 |           properties: {},
211 |           required: [],
212 |         },
213 |       },
214 |     ],
215 |   };
216 | }
217 | 
218 | export async function callTool(request: CallToolRequest) {
219 |   const { name, arguments: args } = request.params;
220 | 
221 |   try {
222 |     if (name === 'request') {
223 |       const { type, url, headers, body } = RequestSchema.parse(args);
224 |       const response = await makeRequest(url, type, headers || {}, body || {});
225 |       return {
226 |         content: [
227 |           {
228 |             type: 'text',
229 |             text: JSON.stringify({
230 |               response,
231 |             }),
232 |           },
233 |         ],
234 |       };
235 |     } else if (name === 'api-documentation') {
236 |       return {
237 |         content: [
238 |           {
239 |             type: 'text',
240 |             text: JSON.stringify(listResources()),
241 |           },
242 |         ],
243 |       };
244 |     } else if (name === 'api-path-schema') {
245 |       return {
246 |         content: [
247 |           {
248 |             type: 'text',
249 |             text: getAPIRequestSpec(request.params.arguments?.path as string),
250 |           },
251 |         ],
252 |       };
253 |     } else {
254 |       throw new Error(`Unknown tool: ${name}`);
255 |     }
256 |   } catch (error) {
257 |     if (error instanceof z.ZodError) {
258 |       throw new Error(
259 |         `Invalid arguments: ${error.errors
260 |           .map(e => `${e.path.join('.')}: ${e.message}`)
261 |           .join(', ')}`
262 |       );
263 |     }
264 |     throw error;
265 |   }
266 | }
267 | 
```
Page 1/2FirstPrevNextLast