mcp-aiven 0.1.5
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/LICENSE +201 -0
- package/README.md +173 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +84 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +42 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/aiven-api.d.ts +49982 -0
- package/dist/generated/aiven-api.d.ts.map +1 -0
- package/dist/generated/aiven-api.js +6 -0
- package/dist/generated/aiven-api.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/manifests/core.yaml +206 -0
- package/dist/manifests/integrations.yaml +72 -0
- package/dist/manifests/kafka.yaml +143 -0
- package/dist/manifests/pg.yaml +43 -0
- package/dist/prompts.d.ts +5 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +10 -0
- package/dist/prompts.js.map +1 -0
- package/dist/security.d.ts +5 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +52 -0
- package/dist/security.js.map +1 -0
- package/dist/shared/service-info.d.ts +5 -0
- package/dist/shared/service-info.d.ts.map +1 -0
- package/dist/shared/service-info.js +24 -0
- package/dist/shared/service-info.js.map +1 -0
- package/dist/tool-result-limit.d.ts +7 -0
- package/dist/tool-result-limit.d.ts.map +1 -0
- package/dist/tool-result-limit.js +44 -0
- package/dist/tool-result-limit.js.map +1 -0
- package/dist/tools/api-tool.d.ts +4 -0
- package/dist/tools/api-tool.d.ts.map +1 -0
- package/dist/tools/api-tool.js +80 -0
- package/dist/tools/api-tool.js.map +1 -0
- package/dist/tools/applications/handlers.d.ts +4 -0
- package/dist/tools/applications/handlers.d.ts.map +1 -0
- package/dist/tools/applications/handlers.js +345 -0
- package/dist/tools/applications/handlers.js.map +1 -0
- package/dist/tools/applications/index.d.ts +2 -0
- package/dist/tools/applications/index.d.ts.map +1 -0
- package/dist/tools/applications/index.js +2 -0
- package/dist/tools/applications/index.js.map +1 -0
- package/dist/tools/applications/schemas.d.ts +276 -0
- package/dist/tools/applications/schemas.d.ts.map +1 -0
- package/dist/tools/applications/schemas.js +204 -0
- package/dist/tools/applications/schemas.js.map +1 -0
- package/dist/tools/json-schema-to-zod.d.ts +4 -0
- package/dist/tools/json-schema-to-zod.d.ts.map +1 -0
- package/dist/tools/json-schema-to-zod.js +118 -0
- package/dist/tools/json-schema-to-zod.js.map +1 -0
- package/dist/tools/kafka/descriptions.d.ts +3 -0
- package/dist/tools/kafka/descriptions.d.ts.map +1 -0
- package/dist/tools/kafka/descriptions.js +43 -0
- package/dist/tools/kafka/descriptions.js.map +1 -0
- package/dist/tools/kafka/handlers.d.ts +4 -0
- package/dist/tools/kafka/handlers.d.ts.map +1 -0
- package/dist/tools/kafka/handlers.js +65 -0
- package/dist/tools/kafka/handlers.js.map +1 -0
- package/dist/tools/kafka/helpers.d.ts +4 -0
- package/dist/tools/kafka/helpers.d.ts.map +1 -0
- package/dist/tools/kafka/helpers.js +79 -0
- package/dist/tools/kafka/helpers.js.map +1 -0
- package/dist/tools/kafka/index.d.ts +2 -0
- package/dist/tools/kafka/index.d.ts.map +1 -0
- package/dist/tools/kafka/index.js +2 -0
- package/dist/tools/kafka/index.js.map +1 -0
- package/dist/tools/kafka/schemas.d.ts +43 -0
- package/dist/tools/kafka/schemas.d.ts.map +1 -0
- package/dist/tools/kafka/schemas.js +23 -0
- package/dist/tools/kafka/schemas.js.map +1 -0
- package/dist/tools/pg/connection.d.ts +5 -0
- package/dist/tools/pg/connection.d.ts.map +1 -0
- package/dist/tools/pg/connection.js +28 -0
- package/dist/tools/pg/connection.js.map +1 -0
- package/dist/tools/pg/descriptions.d.ts +4 -0
- package/dist/tools/pg/descriptions.d.ts.map +1 -0
- package/dist/tools/pg/descriptions.js +66 -0
- package/dist/tools/pg/descriptions.js.map +1 -0
- package/dist/tools/pg/handlers.d.ts +4 -0
- package/dist/tools/pg/handlers.d.ts.map +1 -0
- package/dist/tools/pg/handlers.js +91 -0
- package/dist/tools/pg/handlers.js.map +1 -0
- package/dist/tools/pg/index.d.ts +2 -0
- package/dist/tools/pg/index.d.ts.map +1 -0
- package/dist/tools/pg/index.js +2 -0
- package/dist/tools/pg/index.js.map +1 -0
- package/dist/tools/pg/query.d.ts +6 -0
- package/dist/tools/pg/query.d.ts.map +1 -0
- package/dist/tools/pg/query.js +120 -0
- package/dist/tools/pg/query.js.map +1 -0
- package/dist/tools/pg/schemas.d.ts +59 -0
- package/dist/tools/pg/schemas.d.ts.map +1 -0
- package/dist/tools/pg/schemas.js +69 -0
- package/dist/tools/pg/schemas.js.map +1 -0
- package/dist/tools/pg/validation.d.ts +10 -0
- package/dist/tools/pg/validation.d.ts.map +1 -0
- package/dist/tools/pg/validation.js +77 -0
- package/dist/tools/pg/validation.js.map +1 -0
- package/dist/tools/registry.d.ts +4 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +120 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/response-filter.d.ts +3 -0
- package/dist/tools/response-filter.d.ts.map +1 -0
- package/dist/tools/response-filter.js +19 -0
- package/dist/tools/response-filter.js.map +1 -0
- package/dist/transport.d.ts +14 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +111 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +81 -0
- package/dist/types.js.map +1 -0
- package/generator/schemas/api-schemas.json +2106 -0
- package/package.json +78 -0
- package/src/manifests/core.yaml +206 -0
- package/src/manifests/integrations.yaml +72 -0
- package/src/manifests/kafka.yaml +143 -0
- package/src/manifests/pg.yaml +43 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { randomUUID, createHash } from 'node:crypto';
|
|
2
|
+
import { PgQueryMode, toolSuccess, toolError } from '../../types.js';
|
|
3
|
+
import { errorMessage } from '../../errors.js';
|
|
4
|
+
import { redactSensitiveData } from '../../security.js';
|
|
5
|
+
import { UNTRUSTED_DATA_WARNING } from '../../prompts.js';
|
|
6
|
+
import { connectToService } from './connection.js';
|
|
7
|
+
import { validateReadQuery, validateWriteQuery } from './validation.js';
|
|
8
|
+
export const MAX_ROWS = 1000;
|
|
9
|
+
export const DEFAULT_LIMIT = 100;
|
|
10
|
+
const MAX_CELL_LENGTH = 4096;
|
|
11
|
+
const STATEMENT_TIMEOUT_MS = 30000;
|
|
12
|
+
const RATE_LIMIT_MAX = 100;
|
|
13
|
+
const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
14
|
+
const rateLimitBuckets = new Map();
|
|
15
|
+
function hashToken(token) {
|
|
16
|
+
return createHash('sha256').update(token).digest('hex');
|
|
17
|
+
}
|
|
18
|
+
function checkRateLimit(token) {
|
|
19
|
+
const key = token ? hashToken(token) : '__stdio__';
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
const cutoff = now - RATE_LIMIT_WINDOW_MS;
|
|
22
|
+
let timestamps = rateLimitBuckets.get(key);
|
|
23
|
+
if (timestamps) {
|
|
24
|
+
while (timestamps.length > 0 && (timestamps[0] ?? 0) <= cutoff) {
|
|
25
|
+
timestamps.shift();
|
|
26
|
+
}
|
|
27
|
+
if (timestamps.length === 0) {
|
|
28
|
+
rateLimitBuckets.delete(key);
|
|
29
|
+
timestamps = undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (timestamps && timestamps.length >= RATE_LIMIT_MAX) {
|
|
33
|
+
return `Rate limit exceeded: maximum ${RATE_LIMIT_MAX} queries per ${RATE_LIMIT_WINDOW_MS / 1000} seconds. Please wait before issuing more queries.`;
|
|
34
|
+
}
|
|
35
|
+
if (!timestamps) {
|
|
36
|
+
timestamps = [];
|
|
37
|
+
rateLimitBuckets.set(key, timestamps);
|
|
38
|
+
}
|
|
39
|
+
timestamps.push(now);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
function truncateCells(row) {
|
|
43
|
+
const result = {};
|
|
44
|
+
for (const [key, value] of Object.entries(row)) {
|
|
45
|
+
if (typeof value === 'string' && value.length > MAX_CELL_LENGTH) {
|
|
46
|
+
result[key] = value.slice(0, MAX_CELL_LENGTH) + '... (truncated)';
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result[key] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function sanitizePgError(err) {
|
|
55
|
+
if (!(err instanceof Error))
|
|
56
|
+
return 'PostgreSQL query error: query execution failed';
|
|
57
|
+
const code = 'code' in err && typeof err.code === 'string' ? ` [${err.code}]` : '';
|
|
58
|
+
return `PostgreSQL error${code}: ${err.message}`;
|
|
59
|
+
}
|
|
60
|
+
function wrapInBoundary(data) {
|
|
61
|
+
const uuid = randomUUID();
|
|
62
|
+
const redacted = redactSensitiveData(data);
|
|
63
|
+
return [
|
|
64
|
+
UNTRUSTED_DATA_WARNING,
|
|
65
|
+
`<untrusted-query-result-${uuid}>`,
|
|
66
|
+
JSON.stringify(redacted, null, 2),
|
|
67
|
+
`</untrusted-query-result-${uuid}>`,
|
|
68
|
+
].join('\n');
|
|
69
|
+
}
|
|
70
|
+
export async function executePgQuery(client, options) {
|
|
71
|
+
const { project, service_name, query, database, mode, limit = DEFAULT_LIMIT, offset = 0, token, } = options;
|
|
72
|
+
const validation = mode === PgQueryMode.ReadOnly
|
|
73
|
+
? await validateReadQuery(query)
|
|
74
|
+
: await validateWriteQuery(query);
|
|
75
|
+
if (!validation.valid) {
|
|
76
|
+
return toolError(validation.error);
|
|
77
|
+
}
|
|
78
|
+
const rateLimitError = checkRateLimit(token);
|
|
79
|
+
if (rateLimitError)
|
|
80
|
+
return toolError(rateLimitError);
|
|
81
|
+
const apiOpts = { token, mcpClient: options.mcpClient, toolName: options.toolName };
|
|
82
|
+
let pgClient;
|
|
83
|
+
try {
|
|
84
|
+
pgClient = await connectToService(client, project, service_name, database, apiOpts);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return toolError(errorMessage(err));
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
await pgClient.query(mode === PgQueryMode.ReadOnly ? 'BEGIN READ ONLY' : 'BEGIN');
|
|
91
|
+
await pgClient.query(`SET LOCAL statement_timeout = '${String(STATEMENT_TIMEOUT_MS)}'`);
|
|
92
|
+
const result = await pgClient.query(query);
|
|
93
|
+
await pgClient.query('COMMIT');
|
|
94
|
+
const allRows = result.rows.slice(0, MAX_ROWS);
|
|
95
|
+
const paged = allRows.slice(offset, offset + limit);
|
|
96
|
+
const truncatedRows = paged.map((row) => truncateCells(row));
|
|
97
|
+
const meta = {
|
|
98
|
+
rowCount: result.rowCount ?? 0,
|
|
99
|
+
returnedRows: paged.length,
|
|
100
|
+
totalRowsCapped: allRows.length,
|
|
101
|
+
truncated: (result.rowCount ?? 0) > MAX_ROWS,
|
|
102
|
+
offset,
|
|
103
|
+
limit,
|
|
104
|
+
hasMore: offset + limit < allRows.length,
|
|
105
|
+
fields: result.fields.map((f) => f.name),
|
|
106
|
+
};
|
|
107
|
+
if (mode === PgQueryMode.ReadWrite) {
|
|
108
|
+
meta['command'] = result['command'];
|
|
109
|
+
}
|
|
110
|
+
return toolSuccess(wrapInBoundary({ meta, rows: truncatedRows }));
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
await pgClient.query('ROLLBACK').catch(() => { });
|
|
114
|
+
return toolError(sanitizePgError(err));
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
await pgClient.end();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/tools/pg/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const optimizeQueryInput: z.ZodObject<{
|
|
3
|
+
account_id: z.ZodString;
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
pg_version: z.ZodDefault<z.ZodEnum<["18", "17", "16", "15", "14", "13", "12", "11", "10", "9"]>>;
|
|
6
|
+
}, "strict", z.ZodTypeAny, {
|
|
7
|
+
account_id: string;
|
|
8
|
+
query: string;
|
|
9
|
+
pg_version: "18" | "17" | "16" | "15" | "14" | "13" | "12" | "11" | "10" | "9";
|
|
10
|
+
}, {
|
|
11
|
+
account_id: string;
|
|
12
|
+
query: string;
|
|
13
|
+
pg_version?: "18" | "17" | "16" | "15" | "14" | "13" | "12" | "11" | "10" | "9" | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const pgQueryInput: z.ZodObject<{
|
|
16
|
+
project: z.ZodString;
|
|
17
|
+
service_name: z.ZodString;
|
|
18
|
+
query: z.ZodString;
|
|
19
|
+
database: z.ZodOptional<z.ZodString>;
|
|
20
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
}, "strict", z.ZodTypeAny, {
|
|
23
|
+
project: string;
|
|
24
|
+
service_name: string;
|
|
25
|
+
query: string;
|
|
26
|
+
database?: string | undefined;
|
|
27
|
+
limit?: number | undefined;
|
|
28
|
+
offset?: number | undefined;
|
|
29
|
+
}, {
|
|
30
|
+
project: string;
|
|
31
|
+
service_name: string;
|
|
32
|
+
query: string;
|
|
33
|
+
database?: string | undefined;
|
|
34
|
+
limit?: number | undefined;
|
|
35
|
+
offset?: number | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
export declare const pgExecuteQueryInput: z.ZodObject<{
|
|
38
|
+
project: z.ZodString;
|
|
39
|
+
service_name: z.ZodString;
|
|
40
|
+
query: z.ZodString;
|
|
41
|
+
database: z.ZodOptional<z.ZodString>;
|
|
42
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
}, "strict", z.ZodTypeAny, {
|
|
45
|
+
project: string;
|
|
46
|
+
service_name: string;
|
|
47
|
+
query: string;
|
|
48
|
+
database?: string | undefined;
|
|
49
|
+
limit?: number | undefined;
|
|
50
|
+
offset?: number | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
project: string;
|
|
53
|
+
service_name: string;
|
|
54
|
+
query: string;
|
|
55
|
+
database?: string | undefined;
|
|
56
|
+
limit?: number | undefined;
|
|
57
|
+
offset?: number | undefined;
|
|
58
|
+
}>;
|
|
59
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/tools/pg/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAapB,CAAC;AAEZ,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;EA+Bd,CAAC;AAEZ,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;EA+BrB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { MAX_ROWS, DEFAULT_LIMIT } from './query.js';
|
|
3
|
+
export const optimizeQueryInput = z
|
|
4
|
+
.object({
|
|
5
|
+
account_id: z
|
|
6
|
+
.string()
|
|
7
|
+
.describe('Aiven account ID. Get this from get_project response at project.account_id'),
|
|
8
|
+
query: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe('SQL query to optimize (plain text, will be base64 encoded automatically)'),
|
|
11
|
+
pg_version: z
|
|
12
|
+
.enum(['18', '17', '16', '15', '14', '13', '12', '11', '10', '9'])
|
|
13
|
+
.default('16')
|
|
14
|
+
.describe('PostgreSQL version'),
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
17
|
+
export const pgQueryInput = z
|
|
18
|
+
.object({
|
|
19
|
+
project: z.string().describe('Aiven project name — use aiven_project_list to get valid names'),
|
|
20
|
+
service_name: z.string().describe('Aiven PostgreSQL service name'),
|
|
21
|
+
query: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe('Read-only SQL query to execute. Only SELECT and similar read operations are allowed.'),
|
|
24
|
+
database: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Database name to connect to (default: service default, usually "defaultdb")'),
|
|
28
|
+
limit: z
|
|
29
|
+
.number()
|
|
30
|
+
.int()
|
|
31
|
+
.min(1)
|
|
32
|
+
.max(MAX_ROWS)
|
|
33
|
+
.optional()
|
|
34
|
+
.describe(`Maximum number of rows to return per page (default: ${DEFAULT_LIMIT}, max: ${MAX_ROWS}). Use with offset for pagination.`),
|
|
35
|
+
offset: z
|
|
36
|
+
.number()
|
|
37
|
+
.int()
|
|
38
|
+
.min(0)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe('Number of rows to skip before returning results (default: 0). Use with limit for pagination.'),
|
|
41
|
+
})
|
|
42
|
+
.strict();
|
|
43
|
+
export const pgExecuteQueryInput = z
|
|
44
|
+
.object({
|
|
45
|
+
project: z.string().describe('Aiven project name — use aiven_project_list to get valid names'),
|
|
46
|
+
service_name: z.string().describe('Aiven PostgreSQL service name'),
|
|
47
|
+
query: z
|
|
48
|
+
.string()
|
|
49
|
+
.describe('SQL statement to execute. Allows DML (INSERT, UPDATE, DELETE) and DDL (CREATE TABLE, ALTER TABLE, CREATE INDEX). Blocks DROP, TRUNCATE, GRANT, and REVOKE.'),
|
|
50
|
+
database: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Database name to connect to (default: service default, usually "defaultdb")'),
|
|
54
|
+
limit: z
|
|
55
|
+
.number()
|
|
56
|
+
.int()
|
|
57
|
+
.min(1)
|
|
58
|
+
.max(MAX_ROWS)
|
|
59
|
+
.optional()
|
|
60
|
+
.describe(`Maximum number of rows to return per page (default: ${DEFAULT_LIMIT}, max: ${MAX_ROWS}). Use with offset for pagination.`),
|
|
61
|
+
offset: z
|
|
62
|
+
.number()
|
|
63
|
+
.int()
|
|
64
|
+
.min(0)
|
|
65
|
+
.optional()
|
|
66
|
+
.describe('Number of rows to skip before returning results (default: 0). Use with limit for pagination.'),
|
|
67
|
+
})
|
|
68
|
+
.strict();
|
|
69
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/tools/pg/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,QAAQ,CAAC,4EAA4E,CAAC;IACzF,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CAAC,0EAA0E,CAAC;IACvF,UAAU,EAAE,CAAC;SACV,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;SACjE,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,oBAAoB,CAAC;CAClC,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;IAC9F,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAClE,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CACP,sFAAsF,CACvF;IACH,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,6EAA6E,CAAC;IAC1F,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,QAAQ,CAAC;SACb,QAAQ,EAAE;SACV,QAAQ,CACP,uDAAuD,aAAa,UAAU,QAAQ,oCAAoC,CAC3H;IACH,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CACP,8FAA8F,CAC/F;CACJ,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;IAC9F,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAClE,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CACP,4JAA4J,CAC7J;IACH,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,6EAA6E,CAAC;IAC1F,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,QAAQ,CAAC;SACb,QAAQ,EAAE;SACV,QAAQ,CACP,uDAAuD,aAAa,UAAU,QAAQ,oCAAoC,CAC3H;IACH,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CACP,8FAA8F,CAC/F;CACJ,CAAC;KACD,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type SqlValidationResult = {
|
|
2
|
+
valid: true;
|
|
3
|
+
stmtType: string;
|
|
4
|
+
} | {
|
|
5
|
+
valid: false;
|
|
6
|
+
error: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function validateReadQuery(query: string): Promise<SqlValidationResult>;
|
|
9
|
+
export declare function validateWriteQuery(query: string): Promise<SqlValidationResult>;
|
|
10
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/tools/pg/validation.ts"],"names":[],"mappings":"AAoCA,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAsBpC,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAYnF;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAepF"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { loadModule, parseSync } from 'libpg-query';
|
|
2
|
+
// WASM module must be loaded once before parseSync can be used
|
|
3
|
+
let moduleLoaded = false;
|
|
4
|
+
async function ensurePgQueryLoaded() {
|
|
5
|
+
if (!moduleLoaded) {
|
|
6
|
+
await loadModule();
|
|
7
|
+
moduleLoaded = true;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
// Read-only tool: only allow SELECT and EXPLAIN
|
|
11
|
+
const READONLY_ALLOWED = new Set(['SelectStmt', 'ExplainStmt']);
|
|
12
|
+
// Write tool: block dangerous DDL + SET/transaction injection
|
|
13
|
+
const WRITE_BLOCKED = new Set([
|
|
14
|
+
'DropStmt',
|
|
15
|
+
'DropRoleStmt',
|
|
16
|
+
'DropdbStmt',
|
|
17
|
+
'DropTableSpaceStmt',
|
|
18
|
+
'DropSubscriptionStmt',
|
|
19
|
+
'DropOwnedStmt',
|
|
20
|
+
'TruncateStmt',
|
|
21
|
+
'GrantStmt', // also covers REVOKE
|
|
22
|
+
'ReassignOwnedStmt',
|
|
23
|
+
'SecLabelStmt',
|
|
24
|
+
'DoStmt',
|
|
25
|
+
'CreateFunctionStmt',
|
|
26
|
+
'VariableSetStmt',
|
|
27
|
+
'TransactionStmt',
|
|
28
|
+
]);
|
|
29
|
+
function extractStmtType(query) {
|
|
30
|
+
let ast;
|
|
31
|
+
try {
|
|
32
|
+
ast = parseSync(query);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error('SQL parse error: the query could not be parsed as valid PostgreSQL.');
|
|
36
|
+
}
|
|
37
|
+
if (ast.stmts.length !== 1) {
|
|
38
|
+
throw new Error('Multiple SQL statements are not allowed. Please send one query at a time.');
|
|
39
|
+
}
|
|
40
|
+
const stmtType = Object.keys(ast.stmts[0]?.stmt ?? {})[0];
|
|
41
|
+
if (!stmtType) {
|
|
42
|
+
throw new Error('Empty statement.');
|
|
43
|
+
}
|
|
44
|
+
return stmtType;
|
|
45
|
+
}
|
|
46
|
+
export async function validateReadQuery(query) {
|
|
47
|
+
await ensurePgQueryLoaded();
|
|
48
|
+
let stmtType;
|
|
49
|
+
try {
|
|
50
|
+
stmtType = extractStmtType(query);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return { valid: false, error: err.message };
|
|
54
|
+
}
|
|
55
|
+
if (!READONLY_ALLOWED.has(stmtType)) {
|
|
56
|
+
return { valid: false, error: `Only SELECT and EXPLAIN statements are allowed in read-only mode.` };
|
|
57
|
+
}
|
|
58
|
+
return { valid: true, stmtType };
|
|
59
|
+
}
|
|
60
|
+
export async function validateWriteQuery(query) {
|
|
61
|
+
await ensurePgQueryLoaded();
|
|
62
|
+
let stmtType;
|
|
63
|
+
try {
|
|
64
|
+
stmtType = extractStmtType(query);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return { valid: false, error: err.message };
|
|
68
|
+
}
|
|
69
|
+
if (WRITE_BLOCKED.has(stmtType)) {
|
|
70
|
+
return {
|
|
71
|
+
valid: false,
|
|
72
|
+
error: `Blocked statement type: ${stmtType}. DROP, TRUNCATE, GRANT, REVOKE, DO, CREATE FUNCTION, SET, and transaction control statements are not allowed through this tool.`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { valid: true, stmtType };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/tools/pg/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMpD,+DAA+D;AAC/D,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,KAAK,UAAU,mBAAmB;IAChC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,UAAU,EAAE,CAAC;QACnB,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;AAEhE,8DAA8D;AAC9D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,UAAU;IACV,cAAc;IACd,YAAY;IACZ,oBAAoB;IACpB,sBAAsB;IACtB,eAAe;IACf,cAAc;IACd,WAAW,EAAE,qBAAqB;IAClC,mBAAmB;IACnB,cAAc;IACd,QAAQ;IACR,oBAAoB;IACpB,iBAAiB;IACjB,iBAAiB;CAClB,CAAC,CAAC;AAMH,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,GAAU,CAAC;IACf,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,KAAK,CAAU,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAa;IACnD,MAAM,mBAAmB,EAAE,CAAC;IAC5B,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,mEAAmE,EAAE,CAAC;IACtG,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAa;IACpD,MAAM,mBAAmB,EAAE,CAAC;IAC5B,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,2BAA2B,QAAQ,kIAAkI;SAC7K,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EACV,cAAc,EAOf,MAAM,aAAa,CAAC;AAgIrB,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,EAAE,CAmDlE"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
import { ServiceCategory, READ_ONLY_ANNOTATIONS, CREATE_ANNOTATIONS, UPDATE_ANNOTATIONS, DELETE_ANNOTATIONS, } from '../types.js';
|
|
5
|
+
import { jsonSchemaToZod } from './json-schema-to-zod.js';
|
|
6
|
+
import { createApiTool } from './api-tool.js';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { TOOL_LIST_PICKER_SUFFIX } from '../prompts.js';
|
|
9
|
+
const CATEGORY_MAP = {
|
|
10
|
+
core: ServiceCategory.Core,
|
|
11
|
+
pg: ServiceCategory.Pg,
|
|
12
|
+
kafka: ServiceCategory.Kafka,
|
|
13
|
+
integrations: ServiceCategory.Integrations,
|
|
14
|
+
};
|
|
15
|
+
function toCategory(cat) {
|
|
16
|
+
const mapped = CATEGORY_MAP[cat];
|
|
17
|
+
if (!mapped)
|
|
18
|
+
throw new Error(`Unknown category: ${cat}`);
|
|
19
|
+
return mapped;
|
|
20
|
+
}
|
|
21
|
+
function deriveAnnotations(method, readOnly, destructive) {
|
|
22
|
+
if (readOnly)
|
|
23
|
+
return READ_ONLY_ANNOTATIONS;
|
|
24
|
+
const base = (() => {
|
|
25
|
+
switch (method.toUpperCase()) {
|
|
26
|
+
case 'GET':
|
|
27
|
+
return READ_ONLY_ANNOTATIONS;
|
|
28
|
+
case 'DELETE':
|
|
29
|
+
return DELETE_ANNOTATIONS;
|
|
30
|
+
case 'PUT':
|
|
31
|
+
case 'PATCH':
|
|
32
|
+
return UPDATE_ANNOTATIONS;
|
|
33
|
+
default:
|
|
34
|
+
return CREATE_ANNOTATIONS;
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
if (destructive && !base.destructiveHint) {
|
|
38
|
+
return { ...base, destructiveHint: true };
|
|
39
|
+
}
|
|
40
|
+
return base;
|
|
41
|
+
}
|
|
42
|
+
function loadManifests() {
|
|
43
|
+
const manifestDir = path.join(path.dirname(new URL(import.meta.url).pathname), '..', 'manifests');
|
|
44
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- trusted internal path
|
|
45
|
+
const files = fs
|
|
46
|
+
.readdirSync(manifestDir)
|
|
47
|
+
.filter((f) => f.endsWith('.yaml'))
|
|
48
|
+
.sort();
|
|
49
|
+
const entries = [];
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- trusted internal path
|
|
52
|
+
const content = fs.readFileSync(path.join(manifestDir, file), 'utf-8');
|
|
53
|
+
const manifest = parseYaml(content);
|
|
54
|
+
entries.push(...manifest.tools);
|
|
55
|
+
}
|
|
56
|
+
return entries;
|
|
57
|
+
}
|
|
58
|
+
function loadSchemas() {
|
|
59
|
+
const require = createRequire(import.meta.url);
|
|
60
|
+
return require('../../generator/schemas/api-schemas.json');
|
|
61
|
+
}
|
|
62
|
+
async function resolveFreePlanCloud(params, client, token) {
|
|
63
|
+
if (typeof params['plan'] !== 'string' || !params['plan'].startsWith('free'))
|
|
64
|
+
return;
|
|
65
|
+
try {
|
|
66
|
+
const opts = token ? { token } : undefined;
|
|
67
|
+
const res = await client.get('/console/free-plan-availability', opts);
|
|
68
|
+
const providers = res.free_plan_cloud_providers;
|
|
69
|
+
const cloud = params['cloud'];
|
|
70
|
+
const isValid = cloud && providers.some((p) => cloud.startsWith(`${p}-`));
|
|
71
|
+
if (!isValid && res.free_plan_cloud_preferences.length > 0) {
|
|
72
|
+
params['cloud'] = res.free_plan_cloud_preferences.reduce((a, b) => b.weight > a.weight ? b : a).cloud_name;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// ignore free-plan availability lookup failures
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function loadApiTools(client) {
|
|
80
|
+
const manifests = loadManifests();
|
|
81
|
+
const schemas = loadSchemas();
|
|
82
|
+
const tools = [];
|
|
83
|
+
for (const entry of manifests) {
|
|
84
|
+
const category = toCategory(entry.category);
|
|
85
|
+
const schemaEntry = schemas[entry.name];
|
|
86
|
+
if (!schemaEntry) {
|
|
87
|
+
console.error(`mcp-aiven: No schema found for tool ${entry.name}, skipping`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
let description = entry.description ?? schemaEntry.description;
|
|
91
|
+
if (entry.append_list_picker_hint) {
|
|
92
|
+
description = `${description}\n\n${TOOL_LIST_PICKER_SUFFIX}`;
|
|
93
|
+
}
|
|
94
|
+
const inputSchema = jsonSchemaToZod(schemaEntry.schema, schemaEntry.strict);
|
|
95
|
+
const tool = createApiTool({
|
|
96
|
+
name: entry.name,
|
|
97
|
+
title: schemaEntry.title,
|
|
98
|
+
description,
|
|
99
|
+
category,
|
|
100
|
+
method: entry.method,
|
|
101
|
+
path: entry.path,
|
|
102
|
+
inputSchema,
|
|
103
|
+
annotations: deriveAnnotations(entry.method, entry.readOnly, entry.destructive),
|
|
104
|
+
defaults: entry.defaults,
|
|
105
|
+
responseFilter: entry.response_filter,
|
|
106
|
+
}, client);
|
|
107
|
+
// Resolve free plan cloud for aiven_service_create
|
|
108
|
+
if (entry.name === 'aiven_service_create') {
|
|
109
|
+
const originalHandler = tool.handler;
|
|
110
|
+
tool.handler = async (params, context) => {
|
|
111
|
+
const args = params;
|
|
112
|
+
await resolveFreePlanCloud(args, client, context?.token);
|
|
113
|
+
return originalHandler(params, context);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
tools.push(tool);
|
|
117
|
+
}
|
|
118
|
+
return tools;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAW1C,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AA4BxD,MAAM,YAAY,GAAoC;IACpD,IAAI,EAAE,eAAe,CAAC,IAAI;IAC1B,EAAE,EAAE,eAAe,CAAC,EAAE;IACtB,KAAK,EAAE,eAAe,CAAC,KAAK;IAC5B,YAAY,EAAE,eAAe,CAAC,YAAY;CAC3C,CAAC;AAEF,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAc,EACd,QAAkB,EAClB,WAAqB;IAErB,IAAI,QAAQ;QAAE,OAAO,qBAAqB,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,GAAoB,EAAE;QAClC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7B,KAAK,KAAK;gBACR,OAAO,qBAAqB,CAAC;YAC/B,KAAK,QAAQ;gBACX,OAAO,kBAAkB,CAAC;YAC5B,KAAK,KAAK,CAAC;YACX,KAAK,OAAO;gBACV,OAAO,kBAAkB,CAAC;YAC5B;gBACE,OAAO,kBAAkB,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IACL,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzC,OAAO,EAAE,GAAG,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAClG,4FAA4F;IAC5F,MAAM,KAAK,GAAG,EAAE;SACb,WAAW,CAAC,WAAW,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SAClC,IAAI,EAAE,CAAC;IAEV,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,4FAA4F;QAC5F,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAiB,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,WAAW;IAClB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,0CAA0C,CAAc,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,MAA+B,EAC/B,MAAmB,EACnB,KAAc;IAEd,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO;IAErF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAGzB,iCAAiC,EAAE,IAAI,CAAC,CAAC;QAE5C,MAAM,SAAS,GAAG,GAAG,CAAC,yBAAyB,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAuB,CAAC;QACpD,MAAM,OAAO,GAAG,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAElF,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC5B,CAAC,UAAU,CAAC;QACf,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,uCAAuC,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC;YAC7E,SAAS;QACX,CAAC;QAED,IAAI,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,CAAC;QAC/D,IAAI,KAAK,CAAC,uBAAuB,EAAE,CAAC;YAClC,WAAW,GAAG,GAAG,WAAW,OAAO,uBAAuB,EAAE,CAAC;QAC/D,CAAC;QACD,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAE5E,MAAM,IAAI,GAAG,aAAa,CACxB;YACE,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,WAAW;YACX,QAAQ;YACR,MAAM,EAAE,KAAK,CAAC,MAAoB;YAClC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW;YACX,WAAW,EAAE,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC;YAC/E,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,cAAc,EAAE,KAAK,CAAC,eAAe;SACtC,EACD,MAAM,CACP,CAAC;QAEF,mDAAmD;QACnD,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC1C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC;YACrC,IAAI,CAAC,OAAO,GAAG,KAAK,EAAE,MAAM,EAAE,OAAwB,EAAuB,EAAE;gBAC7E,MAAM,IAAI,GAAG,MAAiC,CAAC;gBAC/C,MAAM,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;gBACzD,OAAO,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-filter.d.ts","sourceRoot":"","sources":["../../src/tools/response-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AASxD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,oBAAoB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function pickFields(item, allowlist) {
|
|
2
|
+
return Object.fromEntries(Object.entries(item).filter(([key]) => allowlist.has(key)));
|
|
3
|
+
}
|
|
4
|
+
export function applyResponseFilter(data, config) {
|
|
5
|
+
const value = data[config.key];
|
|
6
|
+
const allowlist = new Set(config.fields);
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
return {
|
|
9
|
+
[config.key]: value.map((item) => pickFields(item, allowlist)),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === 'object' && value !== null) {
|
|
13
|
+
return {
|
|
14
|
+
[config.key]: pickFields(value, allowlist),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=response-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-filter.js","sourceRoot":"","sources":["../../src/tools/response-filter.ts"],"names":[],"mappings":"AAEA,SAAS,UAAU,CACjB,IAA6B,EAC7B,SAAsB;IAEtB,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAA6B,EAC7B,MAA4B;IAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAA6B,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;SACxF,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO;YACL,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,KAAgC,EAAE,SAAS,CAAC;SACtE,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { HttpMcpRateLimitConfig } from './config.js';
|
|
4
|
+
export declare function createStdioTransport(): StdioServerTransport;
|
|
5
|
+
interface HttpServerConfig {
|
|
6
|
+
port: number;
|
|
7
|
+
apiOrigin: string;
|
|
8
|
+
scopes: string[];
|
|
9
|
+
rateLimit: HttpMcpRateLimitConfig;
|
|
10
|
+
trustProxy: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function startHttpServer(createServer: () => McpServer, config: HttpServerConfig): void;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,wBAAgB,oBAAoB,IAAI,oBAAoB,CAE3D;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,sBAAsB,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;CACrB;AAgED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,SAAS,EAC7B,MAAM,EAAE,gBAAgB,GACvB,IAAI,CAwDN"}
|