@sampuli/mcp 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/server.js +32 -2
- package/src/tools.js +24 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sampuli/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Model Context Protocol server for Sampuli — generate format-true synthetic test data for 90 countries directly inside Claude, Cursor, Copilot and any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
47
|
-
"@sampuli/data": "^0.3.
|
|
47
|
+
"@sampuli/data": "^0.3.3",
|
|
48
48
|
"zod": "^3.25.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
package/src/server.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// generate format-true test data inline. Transport is stdio (see bin.js).
|
|
4
4
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
5
5
|
import { z } from 'zod'
|
|
6
|
-
import { listCountries, describeCountry, generateData } from './tools.js'
|
|
6
|
+
import { listCountries, describeCountry, generateData, listGenericTypes, generateFromSchema } from './tools.js'
|
|
7
7
|
|
|
8
8
|
export function createServer() {
|
|
9
9
|
const server = new McpServer({
|
|
@@ -40,7 +40,7 @@ export function createServer() {
|
|
|
40
40
|
description:
|
|
41
41
|
'Generate format-true, entirely synthetic test data for a country. spec is "<country>.<selector>" where selector is a field key ("phone"), "person" (a full coherent record), or "preset:<key>" (a scenario). Values match each country\'s real formats and pass validators (IBAN mod-97, card Luhn, …) but are never real or registered.',
|
|
42
42
|
inputSchema: {
|
|
43
|
-
spec: z.string().describe('e.g. "ke.person", "de.iban", "ng.phone", "ke.preset:kyc".'),
|
|
43
|
+
spec: z.string().describe('e.g. "ke.person" (core fields), "ke.full" (every field incl. card/passport/income), "de.iban", "ng.phone", "ke.company", "ke.product", "ke.preset:kyc".'),
|
|
44
44
|
count: z.number().int().min(1).max(10000).optional().describe('How many rows (omit for one).'),
|
|
45
45
|
fields: z.union([z.array(z.string()), z.literal('all')]).optional().describe('Which fields for a person record, or "all".'),
|
|
46
46
|
seed: z.string().optional().describe('Reproducible output — same seed, same data.'),
|
|
@@ -50,5 +50,35 @@ export function createServer() {
|
|
|
50
50
|
async args => generateData(args),
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
+
server.registerTool(
|
|
54
|
+
'sampuli_list_types',
|
|
55
|
+
{
|
|
56
|
+
title: 'List generic field types',
|
|
57
|
+
description: 'List the country-agnostic generic types (uuid, enum, int, float, date, vin, isbn, imei, mac, email, …) usable in a custom schema or as "any.<type>".',
|
|
58
|
+
inputSchema: {},
|
|
59
|
+
},
|
|
60
|
+
async () => listGenericTypes(),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
server.registerTool(
|
|
64
|
+
'sampuli_schema',
|
|
65
|
+
{
|
|
66
|
+
title: 'Generate a custom dataset',
|
|
67
|
+
description:
|
|
68
|
+
'Generate rows from a custom schema, mixing generic types and country-accurate fields. Each field has a name and a type — a generic type ("uuid", "int:0,500", "enum:free,pro,team", "date:2021,2025") or a country field spec ("ke.phone", "de.iban"). Optional per-field "blank" (0–1) makes it null that often.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
fields: z.array(z.object({
|
|
71
|
+
name: z.string().describe('Column name.'),
|
|
72
|
+
type: z.string().describe('Generic type or country field spec, e.g. "uuid", "int:0,500", "ke.phone".'),
|
|
73
|
+
blank: z.number().min(0).max(1).optional().describe('Probability (0–1) the value is null.'),
|
|
74
|
+
})).describe('The columns to generate.'),
|
|
75
|
+
count: z.number().int().min(1).max(10000).optional().describe('How many rows (default 1).'),
|
|
76
|
+
seed: z.string().optional().describe('Reproducible output.'),
|
|
77
|
+
format: z.enum(['json', 'csv']).optional(),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
async args => generateFromSchema(args),
|
|
81
|
+
)
|
|
82
|
+
|
|
53
83
|
return server
|
|
54
84
|
}
|
package/src/tools.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Pure tool implementations for the Sampuli MCP server.
|
|
2
2
|
// Kept separate from the transport so they can be unit-tested directly.
|
|
3
3
|
// Each returns a Model Context Protocol tool result: { content: [...], isError? }.
|
|
4
|
-
import { generate, generateMany, listPacks, listFields, listPresets } from '@sampuli/data'
|
|
4
|
+
import { generate, generateMany, generateSchema, listPacks, listFields, listPresets, listTypes } from '@sampuli/data'
|
|
5
5
|
|
|
6
6
|
const text = t => ({ content: [{ type: 'text', text: t }] })
|
|
7
7
|
const fail = t => ({ content: [{ type: 'text', text: t }], isError: true })
|
|
@@ -64,3 +64,26 @@ export function generateData({ spec, count, fields, seed, format }) {
|
|
|
64
64
|
if (format === 'csv') return text(toCsv(data))
|
|
65
65
|
return text(typeof data === 'string' ? data : JSON.stringify(data, null, 2))
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/** List the generic, country-agnostic field types (uuid, enum, int, vin…). */
|
|
69
|
+
export function listGenericTypes() {
|
|
70
|
+
const lines = listTypes().map(t => ` ${t.key.padEnd(12)} ${t.label}${t.params ? ` (${t.params})` : ''}`)
|
|
71
|
+
return text(`Generic types — use as "any.<type>" or as a field type in a custom schema:\n${lines.join('\n')}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate rows from a custom schema — mix generic types and country fields.
|
|
76
|
+
* fields: [{ name, type, blank? }] type = "uuid" | "int:0,500" | "ke.phone" | …
|
|
77
|
+
* count: rows (default 1)
|
|
78
|
+
* seed: reproducible
|
|
79
|
+
* format: "json" | "csv"
|
|
80
|
+
*/
|
|
81
|
+
export function generateFromSchema({ fields, count, seed, format }) {
|
|
82
|
+
if (!Array.isArray(fields) || fields.length === 0) return fail('`fields` must be a non-empty array of { name, type }.')
|
|
83
|
+
const schema = { fields, count: Number(count) || 1 }
|
|
84
|
+
if (seed != null && seed !== '') schema.seed = String(seed)
|
|
85
|
+
let rows
|
|
86
|
+
try { rows = generateSchema(schema) } catch (e) { return fail(e.message) }
|
|
87
|
+
if (format === 'csv') return text(toCsv(rows))
|
|
88
|
+
return text(JSON.stringify(rows, null, 2))
|
|
89
|
+
}
|