#
tokens: 5676/50000 3/3 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── index.ts
├── package-lock.json
├── package.json
└── README.md
```

# Files

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

```
1 | node_modules
```

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

```json
 1 | {
 2 |   "name": "mock-data-mcp",
 3 |   "version": "1.0.0",
 4 |   "description": "",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "keywords": [],
10 |   "author": "",
11 |   "license": "ISC",
12 |   "type": "commonjs",
13 |   "dependencies": {
14 |     "@modelcontextprotocol/sdk": "^1.6.1",
15 |     "chalk": "^5.4.1"
16 |   },
17 |   "devDependencies": {
18 |     "@faker-js/faker": "^9.6.0",
19 |     "@types/node": "^22.13.10"
20 |   }
21 | }
22 | 
```

--------------------------------------------------------------------------------
/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 |   ListToolsRequestSchema,
  8 |   Tool,
  9 | } from "@modelcontextprotocol/sdk/types.js";
 10 | import { faker, Faker, fakerEN } from '@faker-js/faker';
 11 | import chalk from 'chalk';
 12 | 
 13 | // Add type definitions
 14 | type FieldDefinition = {
 15 |   name: string;
 16 |   type: string;
 17 |   options?: Record<string, any>;
 18 | };
 19 | 
 20 | // Create locale-specific faker instances
 21 | const createLocaleFaker = (locale: string): Faker => {
 22 |   // For now, we'll use English as the default locale since locale support needs more setup
 23 |   return fakerEN;
 24 | };
 25 | 
 26 | // Define the mock data generation tools
 27 | const MOCK_DATA_TOOLS: Tool[] = [
 28 |   {
 29 |     name: "generateCustomData",
 30 |     description: `Generates mock data based on custom field definitions.
 31 |     
 32 |     Parameters:
 33 |     - locale: The locale to use for generating data (e.g., "en", "es", "fr")
 34 |     - fields: Array of field definitions, each containing:
 35 |       - name: Name of the field
 36 |       - type: Type of data to generate
 37 |       - options: Optional parameters for data generation
 38 |     
 39 |     Available types:
 40 |     Person:
 41 |     - "firstName" | "lastName" | "fullName" | "gender" | "prefix" | "suffix" | "jobTitle" | "jobType" | "jobArea"
 42 |     
 43 |     Internet:
 44 |     - "email" | "userName" | "password" | "url" | "ipAddress" | "domainName" | "protocol" | "httpMethod"
 45 |     
 46 |     Location:
 47 |     - "address" | "city" | "country" | "countryCode" | "zipCode" | "state" | "stateAbbr" | "latitude" | "longitude" | "timeZone"
 48 |     
 49 |     Date/Time:
 50 |     - "date" (options: past, future, between) | "weekday" | "month" | "timestamp"
 51 |     
 52 |     Commerce:
 53 |     - "product" | "productName" | "price" (options: min, max) | "department" | "productMaterial" | "productDescription"
 54 |     
 55 |     Company:
 56 |     - "companyName" | "catchPhrase" | "bs" | "bsAdjective" | "bsBuzz" | "bsNoun"
 57 |     
 58 |     Finance:
 59 |     - "accountNumber" | "accountName" | "amount" | "currencyCode" | "currencyName" | "currencySymbol" | "bitcoinAddress"
 60 |     
 61 |     Vehicle:
 62 |     - "vehicle" | "manufacturer" | "model" | "type" | "fuel" | "vin" | "color"
 63 |     
 64 |     System:
 65 |     - "fileName" | "mimeType" | "fileExt" | "directoryPath" | "semver"
 66 |     
 67 |     Science:
 68 |     - "chemicalElement" | "unit" | "scientificUnit"
 69 |     
 70 |     Music:
 71 |     - "genre" | "songName" | "artist"
 72 |     
 73 |     Primitive Types:
 74 |     - "number" (options: min, max) | "float" (options: min, max, precision)
 75 |     - "word" | "words" | "sentence" | "paragraph" | "text"
 76 |     - "uuid" | "boolean"
 77 |     - "color" (options: format: 'hex'|'rgb')
 78 |     `,
 79 |     inputSchema: {
 80 |       type: "object",
 81 |       properties: {
 82 |         locale: {
 83 |           type: "string",
 84 |           description: "Locale for generating data",
 85 |           default: "en"
 86 |         },
 87 |         fields: {
 88 |           type: "array",
 89 |           items: {
 90 |             type: "object",
 91 |             properties: {
 92 |               name: {
 93 |                 type: "string",
 94 |                 description: "Name of the field"
 95 |               },
 96 |               type: {
 97 |                 type: "string",
 98 |                 description: "Type of data to generate"
 99 |               },
100 |               options: {
101 |                 type: "object",
102 |                 description: "Optional parameters for data generation",
103 |                 additionalProperties: true
104 |               }
105 |             },
106 |             required: ["name", "type"]
107 |           },
108 |           description: "Field definitions for data generation"
109 |         }
110 |       },
111 |       required: ["fields"]
112 |     }
113 |   },
114 |   {
115 |     name: "generatePerson",
116 |     description: `Generates mock person data including name, email, address, etc.
117 |     
118 |     Parameters:
119 |     - locale: The locale to use for generating data (e.g., "en", "es", "fr")
120 |     - fields: Array of fields to include in the generated data
121 |       Available fields: firstName, lastName, email, phone, address, dateOfBirth
122 |     `,
123 |     inputSchema: {
124 |       type: "object",
125 |       properties: {
126 |         locale: {
127 |           type: "string",
128 |           description: "Locale for generating data",
129 |           default: "en"
130 |         },
131 |         fields: {
132 |           type: "array",
133 |           items: {
134 |             type: "string",
135 |             enum: ["firstName", "lastName", "email", "phone", "address", "dateOfBirth"]
136 |           },
137 |           description: "Fields to include in the generated data"
138 |         }
139 |       },
140 |       required: ["fields"]
141 |     }
142 |   },
143 |   {
144 |     name: "generateCompany",
145 |     description: `Generates mock company data including name, industry, address, etc.
146 |     
147 |     Parameters:
148 |     - locale: The locale to use for generating data
149 |     - fields: Array of fields to include in the generated data
150 |       Available fields: name, industry, catchPhrase, address, phone
151 |     `,
152 |     inputSchema: {
153 |       type: "object",
154 |       properties: {
155 |         locale: {
156 |           type: "string",
157 |           description: "Locale for generating data",
158 |           default: "en"
159 |         },
160 |         fields: {
161 |           type: "array",
162 |           items: {
163 |             type: "string",
164 |             enum: ["name", "industry", "catchPhrase", "address", "phone"]
165 |           },
166 |           description: "Fields to include in the generated data"
167 |         }
168 |       },
169 |       required: ["fields"]
170 |     }
171 |   }
172 | ];
173 | 
174 | class MockDataServer {
175 |   private generateCustomData(locale: string, fields: FieldDefinition[]) {
176 |     const data: Record<string, any> = {};
177 |     const localeFaker = createLocaleFaker(locale);
178 | 
179 |     fields.forEach(field => {
180 |       const { name, type, options = {} } = field;
181 |       
182 |       try {
183 |         switch (type) {
184 |           case "firstName":
185 |             data[name] = localeFaker.person.firstName();
186 |             break;
187 |           case "lastName":
188 |             data[name] = localeFaker.person.lastName();
189 |             break;
190 |           case "fullName":
191 |             data[name] = localeFaker.person.fullName();
192 |             break;
193 |           case "email":
194 |             data[name] = localeFaker.internet.email();
195 |             break;
196 |           case "phone":
197 |             data[name] = localeFaker.phone.number();
198 |             break;
199 |           case "number":
200 |             data[name] = localeFaker.number.int({
201 |               min: options.min || 0,
202 |               max: options.max || 1000
203 |             });
204 |             break;
205 |           case "date":
206 |             if (options.past) {
207 |               data[name] = localeFaker.date.past().toISOString();
208 |             } else if (options.future) {
209 |               data[name] = localeFaker.date.future().toISOString();
210 |             } else {
211 |               data[name] = localeFaker.date.recent().toISOString();
212 |             }
213 |             break;
214 |           case "address":
215 |             data[name] = localeFaker.location.streetAddress();
216 |             break;
217 |           case "city":
218 |             data[name] = localeFaker.location.city();
219 |             break;
220 |           case "country":
221 |             data[name] = localeFaker.location.country();
222 |             break;
223 |           case "zipCode":
224 |             data[name] = localeFaker.location.zipCode();
225 |             break;
226 |           case "word":
227 |             data[name] = localeFaker.word.sample();
228 |             break;
229 |           case "sentence":
230 |             data[name] = localeFaker.lorem.sentence();
231 |             break;
232 |           case "paragraph":
233 |             data[name] = localeFaker.lorem.paragraph();
234 |             break;
235 |           case "uuid":
236 |             data[name] = localeFaker.string.uuid();
237 |             break;
238 |           case "boolean":
239 |             data[name] = localeFaker.datatype.boolean();
240 |             break;
241 |           case "url":
242 |             data[name] = localeFaker.internet.url();
243 |             break;
244 |           case "ipAddress":
245 |             data[name] = localeFaker.internet.ip();
246 |             break;
247 |           case "color":
248 |             data[name] = options.format === 'rgb' 
249 |               ? `rgb(${localeFaker.number.int({ min: 0, max: 255 })}, ${localeFaker.number.int({ min: 0, max: 255 })}, ${localeFaker.number.int({ min: 0, max: 255 })})`
250 |               : `#${localeFaker.string.hexadecimal({ length: 6 }).substring(2)}`;
251 |             break;
252 |           case "gender":
253 |             data[name] = localeFaker.person.gender();
254 |             break;
255 |           case "prefix":
256 |             data[name] = localeFaker.person.prefix();
257 |             break;
258 |           case "suffix":
259 |             data[name] = localeFaker.person.suffix();
260 |             break;
261 |           case "jobTitle":
262 |             data[name] = localeFaker.person.jobTitle();
263 |             break;
264 |           case "jobType":
265 |             data[name] = localeFaker.person.jobType();
266 |             break;
267 |           case "jobArea":
268 |             data[name] = localeFaker.person.jobArea();
269 |             break;
270 |           case "userName":
271 |             data[name] = localeFaker.internet.userName();
272 |             break;
273 |           case "password":
274 |             data[name] = localeFaker.internet.password();
275 |             break;
276 |           case "domainName":
277 |             data[name] = localeFaker.internet.domainName();
278 |             break;
279 |           case "protocol":
280 |             data[name] = localeFaker.internet.protocol();
281 |             break;
282 |           case "httpMethod":
283 |             data[name] = localeFaker.internet.httpMethod();
284 |             break;
285 |           case "countryCode":
286 |             data[name] = localeFaker.location.countryCode();
287 |             break;
288 |           case "state":
289 |             data[name] = localeFaker.location.state();
290 |             break;
291 |           case "stateAbbr":
292 |             data[name] = localeFaker.location.state({ abbreviated: true });
293 |             break;
294 |           case "latitude":
295 |             data[name] = localeFaker.location.latitude();
296 |             break;
297 |           case "longitude":
298 |             data[name] = localeFaker.location.longitude();
299 |             break;
300 |           case "timeZone":
301 |             data[name] = localeFaker.location.timeZone();
302 |             break;
303 |           case "weekday":
304 |             data[name] = localeFaker.date.weekday();
305 |             break;
306 |           case "month":
307 |             data[name] = localeFaker.date.month();
308 |             break;
309 |           case "timestamp":
310 |             data[name] = localeFaker.date.anytime().getTime();
311 |             break;
312 |           case "product":
313 |             data[name] = localeFaker.commerce.product();
314 |             break;
315 |           case "productName":
316 |             data[name] = localeFaker.commerce.productName();
317 |             break;
318 |           case "price":
319 |             data[name] = localeFaker.commerce.price({
320 |               min: options.min || 1,
321 |               max: options.max || 1000,
322 |             });
323 |             break;
324 |           case "department":
325 |             data[name] = localeFaker.commerce.department();
326 |             break;
327 |           case "productMaterial":
328 |             data[name] = localeFaker.commerce.productMaterial();
329 |             break;
330 |           case "productDescription":
331 |             data[name] = localeFaker.commerce.productDescription();
332 |             break;
333 |           case "companyName":
334 |             data[name] = localeFaker.company.name();
335 |             break;
336 |           case "catchPhrase":
337 |             data[name] = localeFaker.company.catchPhrase();
338 |             break;
339 |           case "bs":
340 |             data[name] = localeFaker.company.buzzPhrase();
341 |             break;
342 |           case "bsAdjective":
343 |             data[name] = localeFaker.company.buzzAdjective();
344 |             break;
345 |           case "bsBuzz":
346 |             data[name] = localeFaker.company.buzzVerb();
347 |             break;
348 |           case "bsNoun":
349 |             data[name] = localeFaker.company.buzzNoun();
350 |             break;
351 |           case "accountNumber":
352 |             data[name] = localeFaker.finance.accountNumber();
353 |             break;
354 |           case "accountName":
355 |             data[name] = localeFaker.finance.accountName();
356 |             break;
357 |           case "amount":
358 |             data[name] = localeFaker.finance.amount();
359 |             break;
360 |           case "currencyCode":
361 |             data[name] = localeFaker.finance.currencyCode();
362 |             break;
363 |           case "currencyName":
364 |             data[name] = localeFaker.finance.currencyName();
365 |             break;
366 |           case "currencySymbol":
367 |             data[name] = localeFaker.finance.currencySymbol();
368 |             break;
369 |           case "bitcoinAddress":
370 |             data[name] = localeFaker.finance.bitcoinAddress();
371 |             break;
372 |           case "vehicle":
373 |             data[name] = localeFaker.vehicle.vehicle();
374 |             break;
375 |           case "manufacturer":
376 |             data[name] = localeFaker.vehicle.manufacturer();
377 |             break;
378 |           case "model":
379 |             data[name] = localeFaker.vehicle.model();
380 |             break;
381 |           case "type":
382 |             data[name] = localeFaker.vehicle.type();
383 |             break;
384 |           case "fuel":
385 |             data[name] = localeFaker.vehicle.fuel();
386 |             break;
387 |           case "vin":
388 |             data[name] = localeFaker.vehicle.vin();
389 |             break;
390 |           case "fileName":
391 |             data[name] = localeFaker.system.fileName();
392 |             break;
393 |           case "mimeType":
394 |             data[name] = localeFaker.system.mimeType();
395 |             break;
396 |           case "fileExt":
397 |             data[name] = localeFaker.system.fileExt();
398 |             break;
399 |           case "directoryPath":
400 |             data[name] = localeFaker.system.directoryPath();
401 |             break;
402 |           case "semver":
403 |             data[name] = localeFaker.system.semver();
404 |             break;
405 |           case "chemicalElement":
406 |             data[name] = localeFaker.science.chemicalElement();
407 |             break;
408 |           case "unit":
409 |             data[name] = localeFaker.science.unit();
410 |             break;
411 |           case "scientificUnit":
412 |             data[name] = localeFaker.science.unit();
413 |             break;
414 |           case "genre":
415 |             data[name] = localeFaker.music.genre();
416 |             break;
417 |           case "songName":
418 |             data[name] = localeFaker.music.songName();
419 |             break;
420 |           case "artist":
421 |             data[name] = localeFaker.music.artist();
422 |             break;
423 |           case "float":
424 |             data[name] = localeFaker.number.float({
425 |               min: options.min || 0,
426 |               max: options.max || 1000,
427 |               fractionDigits: options.precision || 2
428 |             });
429 |             break;
430 |           case "words":
431 |             data[name] = localeFaker.word.words();
432 |             break;
433 |           case "text":
434 |             data[name] = localeFaker.lorem.text();
435 |             break;
436 |           default:
437 |             throw new Error(`Unsupported field type: ${type}`);
438 |         }
439 |       } catch (error) {
440 |         console.error(chalk.yellow(`Error generating field ${name}: ${error}`));
441 |         data[name] = null;
442 |       }
443 |     });
444 | 
445 |     return data;
446 |   }
447 | 
448 |   private generatePersonData(locale: string, fields: string[]) {
449 |     const data: Record<string, any> = {};
450 |     const localeFaker = createLocaleFaker(locale);
451 | 
452 |     fields.forEach(field => {
453 |       switch (field) {
454 |         case "firstName":
455 |           data.firstName = localeFaker.person.firstName();
456 |           break;
457 |         case "lastName":
458 |           data.lastName = localeFaker.person.lastName();
459 |           break;
460 |         case "email":
461 |           data.email = localeFaker.internet.email();
462 |           break;
463 |         case "phone":
464 |           data.phone = localeFaker.phone.number();
465 |           break;
466 |         case "address":
467 |           data.address = {
468 |             street: localeFaker.location.streetAddress(),
469 |             city: localeFaker.location.city(),
470 |             state: localeFaker.location.state(),
471 |             country: localeFaker.location.country(),
472 |             zipCode: localeFaker.location.zipCode()
473 |           };
474 |           break;
475 |         case "dateOfBirth":
476 |           data.dateOfBirth = localeFaker.date.past({ years: 70 }).toISOString();
477 |           break;
478 |       }
479 |     });
480 | 
481 |     return data;
482 |   }
483 | 
484 |   private generateCompanyData(locale: string, fields: string[]) {
485 |     const data: Record<string, any> = {};
486 |     const localeFaker = createLocaleFaker(locale);
487 | 
488 |     fields.forEach(field => {
489 |       switch (field) {
490 |         case "name":
491 |           data.name = localeFaker.company.name();
492 |           break;
493 |         case "industry":
494 |           data.industry = localeFaker.company.buzzPhrase();
495 |           break;
496 |         case "catchPhrase":
497 |           data.catchPhrase = localeFaker.company.catchPhrase();
498 |           break;
499 |         case "address":
500 |           data.address = {
501 |             street: localeFaker.location.streetAddress(),
502 |             city: localeFaker.location.city(),
503 |             state: localeFaker.location.state(),
504 |             country: localeFaker.location.country(),
505 |             zipCode: localeFaker.location.zipCode()
506 |           };
507 |           break;
508 |         case "phone":
509 |           data.phone = localeFaker.phone.number();
510 |           break;
511 |       }
512 |     });
513 | 
514 |     return data;
515 |   }
516 | 
517 |   public processRequest(toolName: string, args: any): { content: Array<{ type: string; text: string }>; isError?: boolean } {
518 |     try {
519 |       let result;
520 |       const locale = args.locale || "en";
521 | 
522 |       switch (toolName) {
523 |         case "generateCustomData":
524 |           result = this.generateCustomData(locale, args.fields);
525 |           break;
526 |         case "generatePerson":
527 |           result = this.generatePersonData(locale, args.fields);
528 |           break;
529 |         case "generateCompany":
530 |           result = this.generateCompanyData(locale, args.fields);
531 |           break;
532 |         default:
533 |           throw new Error(`Unknown tool: ${toolName}`);
534 |       }
535 | 
536 |       console.error(chalk.green(`Generated ${toolName} data successfully`));
537 | 
538 |       return {
539 |         content: [{
540 |           type: "text",
541 |           text: JSON.stringify(result, null, 2)
542 |         }]
543 |       };
544 |     } catch (error) {
545 |       console.error(chalk.red(`Error generating mock data: ${error}`));
546 |       return {
547 |         content: [{
548 |           type: "text",
549 |           text: JSON.stringify({
550 |             error: error instanceof Error ? error.message : String(error),
551 |             status: 'failed'
552 |           }, null, 2)
553 |         }],
554 |         isError: true
555 |       };
556 |     }
557 |   }
558 | }
559 | 
560 | const server = new Server(
561 |   {
562 |     name: "mock-data-server",
563 |     version: "1.0.0",
564 |   },
565 |   {
566 |     capabilities: {
567 |       tools: {},
568 |     },
569 |   }
570 | );
571 | 
572 | const mockDataServer = new MockDataServer();
573 | 
574 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
575 |   tools: MOCK_DATA_TOOLS,
576 | }));
577 | 
578 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
579 |   return mockDataServer.processRequest(request.params.name, request.params.arguments);
580 | });
581 | 
582 | async function runServer() {
583 |   const transport = new StdioServerTransport();
584 |   await server.connect(transport);
585 |   console.error(chalk.blue("Mock Data MCP Server running on stdio"));
586 | }
587 | 
588 | runServer().catch((error) => {
589 |   console.error(chalk.red("Fatal error running server:", error));
590 |   process.exit(1);
591 | }); 
```