@hellocrossman/mcp-sdk 0.1.2 → 0.2.0
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/README.md +99 -28
- package/dist/cjs/cli.d.ts +3 -0
- package/dist/cjs/cli.d.ts.map +1 -0
- package/dist/cjs/cli.js +182 -0
- package/dist/cjs/cli.js.map +1 -0
- package/dist/cjs/db-executor.d.ts +4 -0
- package/dist/cjs/db-executor.d.ts.map +1 -0
- package/dist/cjs/db-executor.js +152 -0
- package/dist/cjs/db-executor.js.map +1 -0
- package/dist/cjs/db-introspect.d.ts +18 -0
- package/dist/cjs/db-introspect.d.ts.map +1 -0
- package/dist/cjs/db-introspect.js +145 -0
- package/dist/cjs/db-introspect.js.map +1 -0
- package/dist/cjs/db-tool-generator.d.ts +9 -0
- package/dist/cjs/db-tool-generator.d.ts.map +1 -0
- package/dist/cjs/db-tool-generator.js +167 -0
- package/dist/cjs/db-tool-generator.js.map +1 -0
- package/dist/cjs/enrichment.d.ts +13 -0
- package/dist/cjs/enrichment.d.ts.map +1 -0
- package/dist/cjs/enrichment.js +36 -0
- package/dist/cjs/enrichment.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/introspect.d.ts.map +1 -1
- package/dist/cjs/introspect.js +10 -4
- package/dist/cjs/introspect.js.map +1 -1
- package/dist/cjs/server.d.ts +1 -0
- package/dist/cjs/server.d.ts.map +1 -1
- package/dist/cjs/server.js +113 -15
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types.d.ts +6 -0
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +177 -0
- package/dist/cli.js.map +1 -0
- package/dist/db-executor.d.ts +4 -0
- package/dist/db-executor.d.ts.map +1 -0
- package/dist/db-executor.js +125 -0
- package/dist/db-executor.js.map +1 -0
- package/dist/db-introspect.d.ts +18 -0
- package/dist/db-introspect.d.ts.map +1 -0
- package/dist/db-introspect.js +118 -0
- package/dist/db-introspect.js.map +1 -0
- package/dist/db-tool-generator.d.ts +9 -0
- package/dist/db-tool-generator.d.ts.map +1 -0
- package/dist/db-tool-generator.js +163 -0
- package/dist/db-tool-generator.js.map +1 -0
- package/dist/enrichment.d.ts +13 -0
- package/dist/enrichment.d.ts.map +1 -0
- package/dist/enrichment.js +33 -0
- package/dist/enrichment.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +10 -4
- package/dist/introspect.js.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +113 -15
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -3
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const DB_ENV_KEYS = [
|
|
2
|
+
"DATABASE_URL",
|
|
3
|
+
"DB_URL",
|
|
4
|
+
"POSTGRES_URL",
|
|
5
|
+
"PG_CONNECTION_STRING",
|
|
6
|
+
"PGDATABASE",
|
|
7
|
+
];
|
|
8
|
+
export function detectDatabaseUrl() {
|
|
9
|
+
for (const key of DB_ENV_KEYS) {
|
|
10
|
+
const val = process.env[key];
|
|
11
|
+
if (val && val.length > 0) {
|
|
12
|
+
return val;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (process.env.PGHOST && process.env.PGDATABASE) {
|
|
16
|
+
const host = process.env.PGHOST;
|
|
17
|
+
const port = process.env.PGPORT || "5432";
|
|
18
|
+
const db = process.env.PGDATABASE;
|
|
19
|
+
const user = process.env.PGUSER || "postgres";
|
|
20
|
+
const pass = process.env.PGPASSWORD || "";
|
|
21
|
+
return `postgresql://${user}:${pass}@${host}:${port}/${db}`;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function mapPgType(pgType) {
|
|
26
|
+
const t = pgType.toLowerCase();
|
|
27
|
+
if (t.includes("int") ||
|
|
28
|
+
t === "serial" ||
|
|
29
|
+
t === "bigserial" ||
|
|
30
|
+
t === "smallserial" ||
|
|
31
|
+
t === "numeric" ||
|
|
32
|
+
t === "decimal" ||
|
|
33
|
+
t === "real" ||
|
|
34
|
+
t === "double precision" ||
|
|
35
|
+
t === "float") {
|
|
36
|
+
return "number";
|
|
37
|
+
}
|
|
38
|
+
if (t === "boolean" || t === "bool") {
|
|
39
|
+
return "boolean";
|
|
40
|
+
}
|
|
41
|
+
if (t === "jsonb" || t === "json") {
|
|
42
|
+
return "object";
|
|
43
|
+
}
|
|
44
|
+
if (t.includes("timestamp") || t === "date") {
|
|
45
|
+
return "string";
|
|
46
|
+
}
|
|
47
|
+
if (t === "uuid") {
|
|
48
|
+
return "string";
|
|
49
|
+
}
|
|
50
|
+
if (t.startsWith("_") || t.includes("[]")) {
|
|
51
|
+
return "array";
|
|
52
|
+
}
|
|
53
|
+
return "string";
|
|
54
|
+
}
|
|
55
|
+
export async function introspectDatabase(connectionUrl) {
|
|
56
|
+
let pg;
|
|
57
|
+
try {
|
|
58
|
+
pg = await import("pg");
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new Error("[mcp-sdk] 'pg' package is required for database introspection. Install it with: npm install pg");
|
|
62
|
+
}
|
|
63
|
+
const Pool = pg.default?.Pool || pg.Pool;
|
|
64
|
+
const pool = new Pool({
|
|
65
|
+
connectionString: connectionUrl,
|
|
66
|
+
max: 2,
|
|
67
|
+
connectionTimeoutMillis: 5000,
|
|
68
|
+
idleTimeoutMillis: 10000,
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
const tablesResult = await pool.query(`
|
|
72
|
+
SELECT table_name
|
|
73
|
+
FROM information_schema.tables
|
|
74
|
+
WHERE table_schema = 'public'
|
|
75
|
+
AND table_type = 'BASE TABLE'
|
|
76
|
+
ORDER BY table_name
|
|
77
|
+
`);
|
|
78
|
+
const tables = [];
|
|
79
|
+
for (const row of tablesResult.rows) {
|
|
80
|
+
const tableName = row.table_name;
|
|
81
|
+
const colsResult = await pool.query(`
|
|
82
|
+
SELECT
|
|
83
|
+
c.column_name,
|
|
84
|
+
c.data_type,
|
|
85
|
+
c.udt_name,
|
|
86
|
+
c.is_nullable,
|
|
87
|
+
c.column_default,
|
|
88
|
+
CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary
|
|
89
|
+
FROM information_schema.columns c
|
|
90
|
+
LEFT JOIN (
|
|
91
|
+
SELECT ku.column_name
|
|
92
|
+
FROM information_schema.table_constraints tc
|
|
93
|
+
JOIN information_schema.key_column_usage ku
|
|
94
|
+
ON tc.constraint_name = ku.constraint_name
|
|
95
|
+
WHERE tc.table_name = $1
|
|
96
|
+
AND tc.constraint_type = 'PRIMARY KEY'
|
|
97
|
+
AND tc.table_schema = 'public'
|
|
98
|
+
) pk ON pk.column_name = c.column_name
|
|
99
|
+
WHERE c.table_name = $1
|
|
100
|
+
AND c.table_schema = 'public'
|
|
101
|
+
ORDER BY c.ordinal_position
|
|
102
|
+
`, [tableName]);
|
|
103
|
+
const columns = colsResult.rows.map((col) => ({
|
|
104
|
+
name: col.column_name,
|
|
105
|
+
type: mapPgType(col.udt_name || col.data_type),
|
|
106
|
+
nullable: col.is_nullable === "YES",
|
|
107
|
+
isPrimary: col.is_primary,
|
|
108
|
+
hasDefault: col.column_default !== null,
|
|
109
|
+
}));
|
|
110
|
+
tables.push({ name: tableName, columns });
|
|
111
|
+
}
|
|
112
|
+
return { tables, connectionSource: "auto-detected" };
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
await pool.end();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=db-introspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-introspect.js","sourceRoot":"","sources":["../src/db-introspect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DbTable } from "./db-introspect.js";
|
|
2
|
+
import type { DiscoveredTool } from "./types.js";
|
|
3
|
+
export declare function isSensitiveTable(tableName: string): boolean;
|
|
4
|
+
export declare function generateToolsFromTables(tables: DbTable[], options?: {
|
|
5
|
+
excludeTables?: string[];
|
|
6
|
+
includeTables?: string[];
|
|
7
|
+
includeWrites?: boolean;
|
|
8
|
+
}): DiscoveredTool[];
|
|
9
|
+
//# sourceMappingURL=db-tool-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-tool-generator.d.ts","sourceRoot":"","sources":["../src/db-tool-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkDjD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAG3D;AA2DD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EAAE,EACjB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACpB,GACL,cAAc,EAAE,CA0ElB"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const SENSITIVE_TABLES = [
|
|
2
|
+
"users",
|
|
3
|
+
"user",
|
|
4
|
+
"accounts",
|
|
5
|
+
"account",
|
|
6
|
+
"sessions",
|
|
7
|
+
"session",
|
|
8
|
+
"passwords",
|
|
9
|
+
"password_resets",
|
|
10
|
+
"tokens",
|
|
11
|
+
"access_tokens",
|
|
12
|
+
"refresh_tokens",
|
|
13
|
+
"api_keys",
|
|
14
|
+
"secrets",
|
|
15
|
+
"credentials",
|
|
16
|
+
"auth",
|
|
17
|
+
"authentication",
|
|
18
|
+
"oauth",
|
|
19
|
+
"oauth_tokens",
|
|
20
|
+
"migrations",
|
|
21
|
+
"schema_migrations",
|
|
22
|
+
"drizzle",
|
|
23
|
+
"__drizzle_migrations",
|
|
24
|
+
"knex_migrations",
|
|
25
|
+
"knex_migrations_lock",
|
|
26
|
+
"typeorm_metadata",
|
|
27
|
+
"prisma_migrations",
|
|
28
|
+
"_prisma_migrations",
|
|
29
|
+
"pgmigrations",
|
|
30
|
+
];
|
|
31
|
+
const SENSITIVE_COLUMNS = [
|
|
32
|
+
"password",
|
|
33
|
+
"password_hash",
|
|
34
|
+
"hashed_password",
|
|
35
|
+
"secret",
|
|
36
|
+
"api_key",
|
|
37
|
+
"api_secret",
|
|
38
|
+
"token",
|
|
39
|
+
"access_token",
|
|
40
|
+
"refresh_token",
|
|
41
|
+
"private_key",
|
|
42
|
+
"ssn",
|
|
43
|
+
"social_security",
|
|
44
|
+
"credit_card",
|
|
45
|
+
"card_number",
|
|
46
|
+
];
|
|
47
|
+
export function isSensitiveTable(tableName) {
|
|
48
|
+
const lower = tableName.toLowerCase();
|
|
49
|
+
return SENSITIVE_TABLES.includes(lower);
|
|
50
|
+
}
|
|
51
|
+
function filterSensitiveColumns(columns) {
|
|
52
|
+
return columns.filter((col) => !SENSITIVE_COLUMNS.includes(col.name.toLowerCase()));
|
|
53
|
+
}
|
|
54
|
+
function formatTableName(name) {
|
|
55
|
+
return name
|
|
56
|
+
.replace(/_/g, " ")
|
|
57
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
58
|
+
.toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
function buildInputSchema(columns, mode) {
|
|
61
|
+
const properties = {};
|
|
62
|
+
const required = [];
|
|
63
|
+
if (mode === "get_by_id") {
|
|
64
|
+
const pk = columns.find((c) => c.isPrimary);
|
|
65
|
+
if (pk) {
|
|
66
|
+
properties[pk.name] = {
|
|
67
|
+
type: pk.type === "number" ? "number" : "string",
|
|
68
|
+
description: `The ${pk.name} of the record`,
|
|
69
|
+
};
|
|
70
|
+
required.push(pk.name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
properties["limit"] = {
|
|
75
|
+
type: "number",
|
|
76
|
+
description: "Maximum number of results to return (default: 50)",
|
|
77
|
+
};
|
|
78
|
+
properties["offset"] = {
|
|
79
|
+
type: "number",
|
|
80
|
+
description: "Number of results to skip for pagination",
|
|
81
|
+
};
|
|
82
|
+
const filterableCols = columns.filter((c) => !c.isPrimary && (c.type === "string" || c.type === "number" || c.type === "boolean"));
|
|
83
|
+
for (const col of filterableCols.slice(0, 5)) {
|
|
84
|
+
properties[`filter_${col.name}`] = {
|
|
85
|
+
type: col.type,
|
|
86
|
+
description: `Filter by ${col.name.replace(/_/g, " ")}`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
type: "object",
|
|
92
|
+
properties,
|
|
93
|
+
required: required.length > 0 ? required : undefined,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function generateToolsFromTables(tables, options = {}) {
|
|
97
|
+
const tools = [];
|
|
98
|
+
for (const table of tables) {
|
|
99
|
+
if (options.includeTables && options.includeTables.length > 0) {
|
|
100
|
+
if (!options.includeTables.includes(table.name))
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
if (isSensitiveTable(table.name))
|
|
105
|
+
continue;
|
|
106
|
+
if (options.excludeTables &&
|
|
107
|
+
options.excludeTables.includes(table.name))
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const safeColumns = filterSensitiveColumns(table.columns);
|
|
111
|
+
const pk = table.columns.find((c) => c.isPrimary);
|
|
112
|
+
const readableName = formatTableName(table.name);
|
|
113
|
+
tools.push({
|
|
114
|
+
name: `list_${table.name}`,
|
|
115
|
+
description: `List all ${readableName} records with optional filtering and pagination`,
|
|
116
|
+
method: "DB_QUERY",
|
|
117
|
+
path: `db://${table.name}`,
|
|
118
|
+
inputSchema: buildInputSchema(safeColumns, "list"),
|
|
119
|
+
params: [],
|
|
120
|
+
dbOperation: "list",
|
|
121
|
+
});
|
|
122
|
+
if (pk) {
|
|
123
|
+
tools.push({
|
|
124
|
+
name: `get_${table.name}_by_${pk.name}`,
|
|
125
|
+
description: `Get a specific ${readableName} record by its ${pk.name}`,
|
|
126
|
+
method: "DB_QUERY",
|
|
127
|
+
path: `db://${table.name}/${pk.name}`,
|
|
128
|
+
inputSchema: buildInputSchema(safeColumns, "get_by_id"),
|
|
129
|
+
params: [pk.name],
|
|
130
|
+
dbOperation: "get_by_id",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (options.includeWrites) {
|
|
134
|
+
const insertCols = safeColumns.filter((c) => !c.isPrimary && !c.hasDefault);
|
|
135
|
+
const insertProps = {};
|
|
136
|
+
const insertRequired = [];
|
|
137
|
+
for (const col of insertCols) {
|
|
138
|
+
insertProps[col.name] = {
|
|
139
|
+
type: col.type,
|
|
140
|
+
description: `The ${col.name.replace(/_/g, " ")} value`,
|
|
141
|
+
};
|
|
142
|
+
if (!col.nullable) {
|
|
143
|
+
insertRequired.push(col.name);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
tools.push({
|
|
147
|
+
name: `create_${table.name}`,
|
|
148
|
+
description: `Create a new ${readableName} record`,
|
|
149
|
+
method: "DB_INSERT",
|
|
150
|
+
path: `db://${table.name}`,
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: insertProps,
|
|
154
|
+
required: insertRequired.length > 0 ? insertRequired : undefined,
|
|
155
|
+
},
|
|
156
|
+
params: [],
|
|
157
|
+
dbOperation: "insert",
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return tools;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=db-tool-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-tool-generator.js","sourceRoot":"","sources":["../src/db-tool-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DiscoveredTool } from "./types.js";
|
|
2
|
+
interface EnrichmentOptions {
|
|
3
|
+
name?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
}
|
|
7
|
+
interface EnrichedTool {
|
|
8
|
+
name?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function enrichTools(tools: DiscoveredTool[], options?: EnrichmentOptions): Promise<EnrichedTool[]>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=enrichment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrichment.d.ts","sourceRoot":"","sources":["../src/enrichment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,UAAU,iBAAiB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,YAAY,EAAE,CAAC,CAkCzB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const DEFAULT_ENRICHMENT_URL = "https://mcp-skill-scanner.replit.app/api/enrich";
|
|
2
|
+
export async function enrichTools(tools, options = {}) {
|
|
3
|
+
const endpoint = options.endpoint || DEFAULT_ENRICHMENT_URL;
|
|
4
|
+
const toolSummaries = tools.map((t) => ({
|
|
5
|
+
name: t.name,
|
|
6
|
+
description: t.description,
|
|
7
|
+
method: t.method,
|
|
8
|
+
path: t.path,
|
|
9
|
+
}));
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const timeout = setTimeout(() => controller.abort(), 15000);
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch(endpoint, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
serverName: options.name,
|
|
18
|
+
serverDescription: options.description,
|
|
19
|
+
tools: toolSummaries,
|
|
20
|
+
}),
|
|
21
|
+
signal: controller.signal,
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(`Enrichment API returned ${res.status}`);
|
|
25
|
+
}
|
|
26
|
+
const data = (await res.json());
|
|
27
|
+
return data.tools || [];
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
clearTimeout(timeout);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=enrichment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrichment.js","sourceRoot":"","sources":["../src/enrichment.ts"],"names":[],"mappings":"AAEA,MAAM,sBAAsB,GAAG,iDAAiD,CAAC;AAajF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAuB,EACvB,UAA6B,EAAE;IAE/B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,sBAAsB,CAAC;IAE5D,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI;KACb,CAAC,CAAC,CAAC;IAEJ,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,UAAU,EAAE,OAAO,CAAC,IAAI;gBACxB,iBAAiB,EAAE,OAAO,CAAC,WAAW;gBACtC,KAAK,EAAE,aAAa;aACrB,CAAC;YACF,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA8B,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { createMcpServer } from "./server.js";
|
|
2
2
|
export type { McpServerOptions, DiscoveredRoute, DiscoveredTool } from "./types.js";
|
|
3
|
+
export { detectDatabaseUrl, introspectDatabase } from "./db-introspect.js";
|
|
4
|
+
export type { DbTable, DbColumn, DbIntrospectionResult } from "./db-introspect.js";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/introspect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,SAAS,GACnB,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,SAAS,GACnB,eAAe,EAAE,CAyEnB"}
|
package/dist/introspect.js
CHANGED
|
@@ -42,16 +42,22 @@ export function introspectExpressRoutes(app, routePrefix = "/api") {
|
|
|
42
42
|
}
|
|
43
43
|
const a = app;
|
|
44
44
|
let router = null;
|
|
45
|
-
if (
|
|
46
|
-
router = a.router;
|
|
47
|
-
}
|
|
48
|
-
else if (a._router && a._router.stack) {
|
|
45
|
+
if (a._router && a._router.stack) {
|
|
49
46
|
router = a._router;
|
|
50
47
|
}
|
|
51
48
|
else if (typeof a.lazyrouter === "function") {
|
|
52
49
|
a.lazyrouter();
|
|
53
50
|
router = a._router;
|
|
54
51
|
}
|
|
52
|
+
if (!router) {
|
|
53
|
+
try {
|
|
54
|
+
const r = a.router;
|
|
55
|
+
if (r && r.stack) {
|
|
56
|
+
router = r;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (_) { }
|
|
60
|
+
}
|
|
55
61
|
if (router && router.stack) {
|
|
56
62
|
extractRoutes(router.stack);
|
|
57
63
|
}
|
package/dist/introspect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,uBAAuB,CACrC,GAAY,EACZ,WAAW,GAAG,MAAM;IAEpB,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,SAAS,aAAa,CAAC,KAAY,EAAE,QAAQ,GAAG,EAAE;QAChD,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;gBAE7C,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;oBAAE,SAAS;gBAEhD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CACrD,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAC9B,CAAC;gBAEF,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAEvC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,QAAQ,EAAE,CAAC;oBAClD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;wBAAE,SAAS;oBAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAEd,MAAM,CAAC,IAAI,CAAC;wBACV,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;wBAC5B,IAAI,EAAE,QAAQ;wBACd,MAAM;qBACP,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;iBAAM,IACL,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;gBAChD,KAAK,CAAC,MAAM,EAAE,KAAK,EACnB,CAAC;gBACD,IAAI,MAAM,GAAG,QAAQ,CAAC;gBACtB,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxC,kCAAkC;gBACpC,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;oBACxB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;oBACpE,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,GAAG,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;oBAC3D,CAAC;gBACH,CAAC;gBACD,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAG,GAAU,CAAC;IACrB,IAAI,MAAM,GAAQ,IAAI,CAAC;IAEvB,IAAI,
|
|
1
|
+
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import type { McpServerOptions, DiscoveredTool } from "./types.js";
|
|
|
2
2
|
export declare function createMcpServer(options: McpServerOptions): {
|
|
3
3
|
readonly tools: DiscoveredTool[];
|
|
4
4
|
readonly routes: import("./types.js").DiscoveredRoute[];
|
|
5
|
+
ready: Promise<void>;
|
|
5
6
|
};
|
|
6
7
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB;;;;EAoRxD"}
|
package/dist/server.js
CHANGED
|
@@ -4,27 +4,110 @@ import { randomUUID } from "crypto";
|
|
|
4
4
|
import { introspectExpressRoutes } from "./introspect.js";
|
|
5
5
|
import { generateToolsFromRoutes } from "./tool-generator.js";
|
|
6
6
|
import { executeTool } from "./executor.js";
|
|
7
|
+
import { detectDatabaseUrl, introspectDatabase } from "./db-introspect.js";
|
|
8
|
+
import { generateToolsFromTables, isSensitiveTable } from "./db-tool-generator.js";
|
|
9
|
+
import { initDbPool, executeDbTool } from "./db-executor.js";
|
|
10
|
+
import { enrichTools } from "./enrichment.js";
|
|
7
11
|
import { z } from "zod";
|
|
8
12
|
export function createMcpServer(options) {
|
|
9
|
-
const { app, path: mcpPath = "/mcp", name = "mcp-server", version = "1.0.0", description = "Auto-discovered MCP server", routePrefix = "/api", excludeRoutes = [], } = options;
|
|
13
|
+
const { app, path: mcpPath = "/mcp", name = "mcp-server", version = "1.0.0", description = "Auto-discovered MCP server", routePrefix = "/api", excludeRoutes = [], database = true, excludeTables = [], includeTables = [], includeWrites = false, enrichment = true, } = options;
|
|
10
14
|
let tools = null;
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
let discoveryComplete = false;
|
|
16
|
+
let discoveryPromise = null;
|
|
17
|
+
async function discoverTools() {
|
|
18
|
+
if (tools && discoveryComplete)
|
|
13
19
|
return tools;
|
|
20
|
+
const allTools = [];
|
|
14
21
|
const routes = introspectExpressRoutes(app, routePrefix);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
console.log(
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
const routeTools = generateToolsFromRoutes(routes, excludeRoutes);
|
|
23
|
+
allTools.push(...routeTools);
|
|
24
|
+
console.log(`\n[mcp-sdk] ---- Discovery Report ----`);
|
|
25
|
+
console.log(`[mcp-sdk] Express routes: ${routes.length} found, ${routeTools.length} tools generated`);
|
|
26
|
+
routeTools.forEach((t) => {
|
|
27
|
+
console.log(`[mcp-sdk] + ${t.name} (${t.method} ${t.path})`);
|
|
20
28
|
});
|
|
29
|
+
if (database !== false) {
|
|
30
|
+
const dbUrl = typeof database === "string" ? database : detectDatabaseUrl();
|
|
31
|
+
if (dbUrl) {
|
|
32
|
+
try {
|
|
33
|
+
await initDbPool(dbUrl);
|
|
34
|
+
const dbResult = await introspectDatabase(dbUrl);
|
|
35
|
+
const sensitiveTables = dbResult.tables.filter((t) => isSensitiveTable(t.name));
|
|
36
|
+
const dbTools = generateToolsFromTables(dbResult.tables, {
|
|
37
|
+
excludeTables,
|
|
38
|
+
includeTables,
|
|
39
|
+
includeWrites,
|
|
40
|
+
});
|
|
41
|
+
allTools.push(...dbTools);
|
|
42
|
+
console.log(`[mcp-sdk] Database: ${dbResult.tables.length} tables found, ${dbTools.length} tools generated`);
|
|
43
|
+
dbTools.forEach((t) => {
|
|
44
|
+
console.log(`[mcp-sdk] + ${t.name} (${t.method})`);
|
|
45
|
+
});
|
|
46
|
+
if (sensitiveTables.length > 0) {
|
|
47
|
+
console.log(`[mcp-sdk] Auto-hidden (sensitive): ${sensitiveTables.map((t) => t.name).join(", ")}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
console.log(`[mcp-sdk] Database: skipped (${msg})`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(`[mcp-sdk] Database: no connection found in environment`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (enrichment !== false) {
|
|
60
|
+
const endpoint = typeof enrichment === "string" ? enrichment : undefined;
|
|
61
|
+
try {
|
|
62
|
+
const enriched = await enrichTools(allTools, { name, description, endpoint });
|
|
63
|
+
for (let i = 0; i < allTools.length; i++) {
|
|
64
|
+
if (enriched[i]) {
|
|
65
|
+
if (enriched[i].description)
|
|
66
|
+
allTools[i].description = enriched[i].description;
|
|
67
|
+
if (enriched[i].name)
|
|
68
|
+
allTools[i].name = enriched[i].name;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
console.log(`[mcp-sdk] AI enrichment: applied`);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
console.log(`[mcp-sdk] AI enrichment: skipped (service unavailable)`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
console.log(`[mcp-sdk] Total tools: ${allTools.length}`);
|
|
78
|
+
console.log(`[mcp-sdk] ----------------------------\n`);
|
|
79
|
+
const nameCount = new Map();
|
|
80
|
+
for (const tool of allTools) {
|
|
81
|
+
const count = nameCount.get(tool.name) || 0;
|
|
82
|
+
nameCount.set(tool.name, count + 1);
|
|
83
|
+
}
|
|
84
|
+
const seen = new Map();
|
|
85
|
+
for (const tool of allTools) {
|
|
86
|
+
const total = nameCount.get(tool.name) || 1;
|
|
87
|
+
if (total > 1) {
|
|
88
|
+
const idx = (seen.get(tool.name) || 0) + 1;
|
|
89
|
+
seen.set(tool.name, idx);
|
|
90
|
+
if (idx > 1) {
|
|
91
|
+
tool.name = `${tool.name}_db`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
tools = allTools;
|
|
96
|
+
discoveryComplete = true;
|
|
21
97
|
return tools;
|
|
22
98
|
}
|
|
99
|
+
discoveryPromise = discoverTools().then(() => { }).catch((err) => {
|
|
100
|
+
console.error("[mcp-sdk] Discovery error:", err);
|
|
101
|
+
});
|
|
102
|
+
function getToolsSync() {
|
|
103
|
+
return tools || [];
|
|
104
|
+
}
|
|
23
105
|
const port = parseInt(process.env.PORT || "5000", 10);
|
|
24
106
|
const sessions = new Map();
|
|
25
|
-
function buildMcpServer() {
|
|
107
|
+
async function buildMcpServer() {
|
|
108
|
+
await discoveryPromise;
|
|
26
109
|
const mcpServer = new McpServer({ name, version });
|
|
27
|
-
const currentTools =
|
|
110
|
+
const currentTools = getToolsSync();
|
|
28
111
|
for (const tool of currentTools) {
|
|
29
112
|
const paramShape = {};
|
|
30
113
|
if (tool.inputSchema.properties && typeof tool.inputSchema.properties === "object") {
|
|
@@ -34,9 +117,15 @@ export function createMcpServer(options) {
|
|
|
34
117
|
if (schema.type === "number") {
|
|
35
118
|
zodType = z.number().describe(schema.description || key);
|
|
36
119
|
}
|
|
120
|
+
else if (schema.type === "boolean") {
|
|
121
|
+
zodType = z.boolean().describe(schema.description || key);
|
|
122
|
+
}
|
|
37
123
|
else if (schema.type === "object") {
|
|
38
124
|
zodType = z.record(z.unknown()).describe(schema.description || key);
|
|
39
125
|
}
|
|
126
|
+
else if (schema.type === "array") {
|
|
127
|
+
zodType = z.array(z.unknown()).describe(schema.description || key);
|
|
128
|
+
}
|
|
40
129
|
else {
|
|
41
130
|
zodType = z.string().describe(schema.description || key);
|
|
42
131
|
}
|
|
@@ -46,9 +135,16 @@ export function createMcpServer(options) {
|
|
|
46
135
|
paramShape[key] = zodType;
|
|
47
136
|
}
|
|
48
137
|
}
|
|
138
|
+
const toolRef = tool;
|
|
49
139
|
mcpServer.tool(tool.name, tool.description, paramShape, async (args) => {
|
|
50
140
|
try {
|
|
51
|
-
|
|
141
|
+
let result;
|
|
142
|
+
if (toolRef.method.startsWith("DB_")) {
|
|
143
|
+
result = await executeDbTool(toolRef, args);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
result = await executeTool(app, toolRef, args, port);
|
|
147
|
+
}
|
|
52
148
|
return {
|
|
53
149
|
content: [{ type: "text", text: result }],
|
|
54
150
|
};
|
|
@@ -81,7 +177,7 @@ export function createMcpServer(options) {
|
|
|
81
177
|
return;
|
|
82
178
|
}
|
|
83
179
|
try {
|
|
84
|
-
const mcpServer = buildMcpServer();
|
|
180
|
+
const mcpServer = await buildMcpServer();
|
|
85
181
|
const transport = new StreamableHTTPServerTransport({
|
|
86
182
|
sessionIdGenerator: () => randomUUID(),
|
|
87
183
|
});
|
|
@@ -105,7 +201,7 @@ export function createMcpServer(options) {
|
|
|
105
201
|
}
|
|
106
202
|
}
|
|
107
203
|
});
|
|
108
|
-
app.get(mcpPath, (req, res) => {
|
|
204
|
+
app.get(mcpPath, async (req, res) => {
|
|
109
205
|
const sessionId = req.headers["mcp-session-id"];
|
|
110
206
|
if (sessionId && sessions.has(sessionId)) {
|
|
111
207
|
const session = sessions.get(sessionId);
|
|
@@ -114,7 +210,8 @@ export function createMcpServer(options) {
|
|
|
114
210
|
});
|
|
115
211
|
return;
|
|
116
212
|
}
|
|
117
|
-
|
|
213
|
+
await discoveryPromise;
|
|
214
|
+
const currentTools = getToolsSync();
|
|
118
215
|
res.json({
|
|
119
216
|
name,
|
|
120
217
|
version,
|
|
@@ -142,8 +239,9 @@ export function createMcpServer(options) {
|
|
|
142
239
|
});
|
|
143
240
|
console.log(`[mcp-sdk] MCP endpoint available at ${mcpPath}`);
|
|
144
241
|
return {
|
|
145
|
-
get tools() { return
|
|
242
|
+
get tools() { return getToolsSync(); },
|
|
146
243
|
get routes() { return introspectExpressRoutes(app, routePrefix); },
|
|
244
|
+
ready: discoveryPromise,
|
|
147
245
|
};
|
|
148
246
|
}
|
|
149
247
|
//# sourceMappingURL=server.js.map
|