@getjack/jack 0.1.24 → 0.1.26
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 +1 -1
- package/src/commands/services.ts +156 -36
- package/src/commands/update.ts +0 -1
- package/src/lib/control-plane.ts +86 -0
- package/src/lib/services/db-execute.ts +100 -1
- package/src/lib/services/db-list.ts +34 -7
- package/src/lib/services/sql-classifier.test.ts +18 -18
- package/src/lib/services/sql-classifier.ts +7 -7
- package/src/lib/services/vectorize-config.ts +569 -0
- package/src/lib/services/vectorize-create.ts +166 -0
- package/src/lib/services/vectorize-delete.ts +54 -0
- package/src/lib/services/vectorize-info.ts +52 -0
- package/src/lib/services/vectorize-list.ts +56 -0
- package/src/mcp/tools/index.ts +282 -0
- package/templates/AI-BINDINGS.md +181 -0
- package/templates/CLAUDE.md +30 -0
- package/templates/ai-chat/.jack.json +3 -4
- package/templates/ai-chat/src/index.ts +45 -5
- package/templates/ai-chat/src/jack-ai.ts +96 -0
- package/templates/semantic-search/.jack.json +3 -4
- package/templates/semantic-search/src/index.ts +70 -12
- package/templates/semantic-search/src/jack-ai.ts +96 -0
- package/templates/semantic-search/src/jack-vectorize.ts +165 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vectorize index creation logic for jack MCP tools
|
|
3
|
+
*
|
|
4
|
+
* Uses wrangler CLI to create Vectorize indexes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { $ } from "bun";
|
|
9
|
+
import { getProjectNameFromDir } from "../storage/index.ts";
|
|
10
|
+
import { addVectorizeBinding, getExistingVectorizeBindings } from "./vectorize-config.ts";
|
|
11
|
+
|
|
12
|
+
export type VectorizeMetric = "cosine" | "euclidean" | "dot-product";
|
|
13
|
+
|
|
14
|
+
export interface CreateVectorizeOptions {
|
|
15
|
+
name?: string;
|
|
16
|
+
dimensions?: number;
|
|
17
|
+
metric?: VectorizeMetric;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CreateVectorizeResult {
|
|
21
|
+
indexName: string;
|
|
22
|
+
bindingName: string;
|
|
23
|
+
dimensions: number;
|
|
24
|
+
metric: VectorizeMetric;
|
|
25
|
+
created: boolean; // false if reused existing
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Convert an index name to SCREAMING_SNAKE_CASE for the binding name.
|
|
30
|
+
* Special case: first index in a project gets "VECTORS" as the binding.
|
|
31
|
+
*/
|
|
32
|
+
function toBindingName(indexName: string, isFirst: boolean): string {
|
|
33
|
+
if (isFirst) {
|
|
34
|
+
return "VECTORS";
|
|
35
|
+
}
|
|
36
|
+
// Convert kebab-case/snake_case to SCREAMING_SNAKE_CASE
|
|
37
|
+
return indexName
|
|
38
|
+
.replace(/-/g, "_")
|
|
39
|
+
.replace(/[^a-zA-Z0-9_]/g, "")
|
|
40
|
+
.toUpperCase();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generate a unique index name for a project.
|
|
45
|
+
* First index: {project}-vectors
|
|
46
|
+
* Subsequent: {project}-vectors-{n}
|
|
47
|
+
*/
|
|
48
|
+
function generateIndexName(projectName: string, existingCount: number): string {
|
|
49
|
+
if (existingCount === 0) {
|
|
50
|
+
return `${projectName}-vectors`;
|
|
51
|
+
}
|
|
52
|
+
return `${projectName}-vectors-${existingCount + 1}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface ExistingIndex {
|
|
56
|
+
name: string;
|
|
57
|
+
dimensions?: number;
|
|
58
|
+
metric?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* List all Vectorize indexes in the Cloudflare account via wrangler
|
|
63
|
+
*/
|
|
64
|
+
async function listIndexesViaWrangler(): Promise<ExistingIndex[]> {
|
|
65
|
+
const result = await $`wrangler vectorize list --json`.nothrow().quiet();
|
|
66
|
+
|
|
67
|
+
if (result.exitCode !== 0) {
|
|
68
|
+
// If wrangler fails, return empty list (might not be logged in)
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const output = result.stdout.toString().trim();
|
|
74
|
+
const data = JSON.parse(output);
|
|
75
|
+
// wrangler vectorize list --json returns array: [{ "name": "...", ... }]
|
|
76
|
+
return Array.isArray(data) ? data : [];
|
|
77
|
+
} catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Find an existing Vectorize index by name
|
|
84
|
+
*/
|
|
85
|
+
async function findExistingIndex(indexName: string): Promise<ExistingIndex | null> {
|
|
86
|
+
const indexes = await listIndexesViaWrangler();
|
|
87
|
+
return indexes.find((idx) => idx.name === indexName) ?? null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create a Vectorize index via wrangler
|
|
92
|
+
*/
|
|
93
|
+
async function createIndexViaWrangler(
|
|
94
|
+
indexName: string,
|
|
95
|
+
dimensions: number,
|
|
96
|
+
metric: VectorizeMetric,
|
|
97
|
+
): Promise<{ created: boolean }> {
|
|
98
|
+
// Check if index already exists
|
|
99
|
+
const existing = await findExistingIndex(indexName);
|
|
100
|
+
if (existing) {
|
|
101
|
+
return { created: false };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const result =
|
|
105
|
+
await $`wrangler vectorize create ${indexName} --dimensions=${dimensions} --metric=${metric}`.nothrow().quiet();
|
|
106
|
+
|
|
107
|
+
if (result.exitCode !== 0) {
|
|
108
|
+
const stderr = result.stderr.toString().trim();
|
|
109
|
+
throw new Error(stderr || `Failed to create Vectorize index ${indexName}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { created: true };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create a Vectorize index for the current project.
|
|
117
|
+
*
|
|
118
|
+
* Uses wrangler vectorize create to create the index, then updates
|
|
119
|
+
* wrangler.jsonc with the new binding.
|
|
120
|
+
*/
|
|
121
|
+
export async function createVectorizeIndex(
|
|
122
|
+
projectDir: string,
|
|
123
|
+
options: CreateVectorizeOptions = {},
|
|
124
|
+
): Promise<CreateVectorizeResult> {
|
|
125
|
+
// Get project name from wrangler config
|
|
126
|
+
const projectName = await getProjectNameFromDir(projectDir);
|
|
127
|
+
|
|
128
|
+
// Get existing Vectorize bindings to determine naming
|
|
129
|
+
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
130
|
+
const existingBindings = await getExistingVectorizeBindings(wranglerPath);
|
|
131
|
+
const existingCount = existingBindings.length;
|
|
132
|
+
|
|
133
|
+
// Determine index name
|
|
134
|
+
const indexName = options.name ?? generateIndexName(projectName, existingCount);
|
|
135
|
+
|
|
136
|
+
// Determine binding name
|
|
137
|
+
const isFirst = existingCount === 0;
|
|
138
|
+
const bindingName = toBindingName(indexName, isFirst);
|
|
139
|
+
|
|
140
|
+
// Check if binding name already exists
|
|
141
|
+
const bindingExists = existingBindings.some((b) => b.binding === bindingName);
|
|
142
|
+
if (bindingExists) {
|
|
143
|
+
throw new Error(`Binding "${bindingName}" already exists. Choose a different index name.`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Use omakase defaults: 768 dimensions (for bge-base-en-v1.5), cosine metric
|
|
147
|
+
const dimensions = options.dimensions ?? 768;
|
|
148
|
+
const metric = options.metric ?? "cosine";
|
|
149
|
+
|
|
150
|
+
// Create via wrangler
|
|
151
|
+
const result = await createIndexViaWrangler(indexName, dimensions, metric);
|
|
152
|
+
|
|
153
|
+
// Update wrangler.jsonc with the new binding
|
|
154
|
+
await addVectorizeBinding(wranglerPath, {
|
|
155
|
+
binding: bindingName,
|
|
156
|
+
index_name: indexName,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
indexName,
|
|
161
|
+
bindingName,
|
|
162
|
+
dimensions,
|
|
163
|
+
metric,
|
|
164
|
+
created: result.created,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vectorize index deletion logic for jack MCP tools
|
|
3
|
+
*
|
|
4
|
+
* Uses wrangler CLI to delete Vectorize indexes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { $ } from "bun";
|
|
9
|
+
import { removeVectorizeBinding } from "./vectorize-config.ts";
|
|
10
|
+
|
|
11
|
+
export interface DeleteVectorizeResult {
|
|
12
|
+
indexName: string;
|
|
13
|
+
deleted: boolean;
|
|
14
|
+
bindingRemoved: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Delete a Vectorize index via wrangler
|
|
19
|
+
*/
|
|
20
|
+
async function deleteIndexViaWrangler(indexName: string): Promise<void> {
|
|
21
|
+
const result = await $`wrangler vectorize delete ${indexName} --force`.nothrow().quiet();
|
|
22
|
+
|
|
23
|
+
if (result.exitCode !== 0) {
|
|
24
|
+
const stderr = result.stderr.toString().trim();
|
|
25
|
+
// Ignore "not found" errors - the index might already be deleted
|
|
26
|
+
if (!stderr.includes("not found") && !stderr.includes("does not exist")) {
|
|
27
|
+
throw new Error(stderr || `Failed to delete Vectorize index ${indexName}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Delete a Vectorize index for the current project.
|
|
34
|
+
*
|
|
35
|
+
* Uses wrangler vectorize delete to delete the index, then removes
|
|
36
|
+
* the binding from wrangler.jsonc.
|
|
37
|
+
*/
|
|
38
|
+
export async function deleteVectorizeIndex(
|
|
39
|
+
projectDir: string,
|
|
40
|
+
indexName: string,
|
|
41
|
+
): Promise<DeleteVectorizeResult> {
|
|
42
|
+
// Delete via wrangler
|
|
43
|
+
await deleteIndexViaWrangler(indexName);
|
|
44
|
+
|
|
45
|
+
// Remove binding from wrangler.jsonc
|
|
46
|
+
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
47
|
+
const bindingRemoved = await removeVectorizeBinding(wranglerPath, indexName);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
indexName,
|
|
51
|
+
deleted: true,
|
|
52
|
+
bindingRemoved,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vectorize index info logic for jack MCP tools
|
|
3
|
+
*
|
|
4
|
+
* Uses wrangler CLI to get information about Vectorize indexes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { $ } from "bun";
|
|
8
|
+
|
|
9
|
+
export interface VectorizeInfo {
|
|
10
|
+
name: string;
|
|
11
|
+
dimensions: number;
|
|
12
|
+
metric: string;
|
|
13
|
+
vectorCount: number;
|
|
14
|
+
createdOn?: string;
|
|
15
|
+
modifiedOn?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get Vectorize index info via wrangler vectorize info
|
|
20
|
+
*/
|
|
21
|
+
export async function getVectorizeInfo(indexName: string): Promise<VectorizeInfo | null> {
|
|
22
|
+
const result = await $`wrangler vectorize info ${indexName} --json`.nothrow().quiet();
|
|
23
|
+
|
|
24
|
+
if (result.exitCode !== 0) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const output = result.stdout.toString().trim();
|
|
30
|
+
const data = JSON.parse(output);
|
|
31
|
+
|
|
32
|
+
// wrangler vectorize info --json returns:
|
|
33
|
+
// {
|
|
34
|
+
// "name": "...",
|
|
35
|
+
// "config": { "dimensions": N, "metric": "..." },
|
|
36
|
+
// "vectorsCount": N,
|
|
37
|
+
// "created_on": "...",
|
|
38
|
+
// "modified_on": "..."
|
|
39
|
+
// }
|
|
40
|
+
return {
|
|
41
|
+
name: data.name || indexName,
|
|
42
|
+
dimensions: data.config?.dimensions || 0,
|
|
43
|
+
metric: data.config?.metric || "unknown",
|
|
44
|
+
vectorCount: data.vectorsCount || 0,
|
|
45
|
+
createdOn: data.created_on,
|
|
46
|
+
modifiedOn: data.modified_on,
|
|
47
|
+
};
|
|
48
|
+
} catch {
|
|
49
|
+
// Failed to parse JSON output
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vectorize index listing logic for jack MCP tools
|
|
3
|
+
*
|
|
4
|
+
* Lists Vectorize indexes configured in wrangler.jsonc with their metadata.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { getExistingVectorizeBindings } from "./vectorize-config.ts";
|
|
9
|
+
import { getVectorizeInfo } from "./vectorize-info.ts";
|
|
10
|
+
|
|
11
|
+
export interface VectorizeListEntry {
|
|
12
|
+
name: string;
|
|
13
|
+
binding: string;
|
|
14
|
+
dimensions?: number;
|
|
15
|
+
metric?: string;
|
|
16
|
+
vectorCount?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* List all Vectorize indexes configured for a project.
|
|
21
|
+
*
|
|
22
|
+
* Reads bindings from wrangler.jsonc and fetches additional metadata
|
|
23
|
+
* (dimensions, metric, vector count) via wrangler vectorize info for each index.
|
|
24
|
+
*/
|
|
25
|
+
export async function listVectorizeIndexes(projectDir: string): Promise<VectorizeListEntry[]> {
|
|
26
|
+
const wranglerPath = join(projectDir, "wrangler.jsonc");
|
|
27
|
+
|
|
28
|
+
// Get existing Vectorize bindings from wrangler.jsonc
|
|
29
|
+
const bindings = await getExistingVectorizeBindings(wranglerPath);
|
|
30
|
+
|
|
31
|
+
if (bindings.length === 0) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fetch detailed info for each index
|
|
36
|
+
const entries: VectorizeListEntry[] = [];
|
|
37
|
+
|
|
38
|
+
for (const binding of bindings) {
|
|
39
|
+
const entry: VectorizeListEntry = {
|
|
40
|
+
name: binding.index_name,
|
|
41
|
+
binding: binding.binding,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Try to get additional metadata via wrangler
|
|
45
|
+
const info = await getVectorizeInfo(binding.index_name);
|
|
46
|
+
if (info) {
|
|
47
|
+
entry.dimensions = info.dimensions;
|
|
48
|
+
entry.metric = info.metric;
|
|
49
|
+
entry.vectorCount = info.vectorCount;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
entries.push(entry);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return entries;
|
|
56
|
+
}
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
wrapResultsForMcp,
|
|
13
13
|
} from "../../lib/services/db-execute.ts";
|
|
14
14
|
import { listDatabases } from "../../lib/services/db-list.ts";
|
|
15
|
+
import { createVectorizeIndex } from "../../lib/services/vectorize-create.ts";
|
|
16
|
+
import { deleteVectorizeIndex } from "../../lib/services/vectorize-delete.ts";
|
|
17
|
+
import { getVectorizeInfo } from "../../lib/services/vectorize-info.ts";
|
|
18
|
+
import { listVectorizeIndexes } from "../../lib/services/vectorize-list.ts";
|
|
15
19
|
import { Events, track, withTelemetry } from "../../lib/telemetry.ts";
|
|
16
20
|
import type { DebugLogger, McpServerOptions } from "../types.ts";
|
|
17
21
|
import { formatErrorResponse, formatSuccessResponse } from "../utils.ts";
|
|
@@ -78,6 +82,43 @@ const ExecuteSqlSchema = z.object({
|
|
|
78
82
|
.describe("Database name (auto-detect from wrangler.jsonc if not provided)"),
|
|
79
83
|
});
|
|
80
84
|
|
|
85
|
+
const CreateVectorizeIndexSchema = z.object({
|
|
86
|
+
name: z.string().optional().describe("Index name (auto-generated if not provided)"),
|
|
87
|
+
dimensions: z.number().optional().default(768).describe("Vector dimensions (default: 768)"),
|
|
88
|
+
metric: z
|
|
89
|
+
.enum(["cosine", "euclidean", "dot-product"])
|
|
90
|
+
.optional()
|
|
91
|
+
.default("cosine")
|
|
92
|
+
.describe("Distance metric (default: cosine)"),
|
|
93
|
+
project_path: z
|
|
94
|
+
.string()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const ListVectorizeIndexesSchema = z.object({
|
|
100
|
+
project_path: z
|
|
101
|
+
.string()
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const DeleteVectorizeIndexSchema = z.object({
|
|
107
|
+
name: z.string().describe("Index name to delete"),
|
|
108
|
+
project_path: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const GetVectorizeInfoSchema = z.object({
|
|
115
|
+
name: z.string().describe("Index name"),
|
|
116
|
+
project_path: z
|
|
117
|
+
.string()
|
|
118
|
+
.optional()
|
|
119
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
120
|
+
});
|
|
121
|
+
|
|
81
122
|
export function registerTools(server: McpServer, _options: McpServerOptions, debug: DebugLogger) {
|
|
82
123
|
// Register tool list handler
|
|
83
124
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -212,6 +253,85 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
212
253
|
required: ["sql"],
|
|
213
254
|
},
|
|
214
255
|
},
|
|
256
|
+
{
|
|
257
|
+
name: "create_vectorize_index",
|
|
258
|
+
description:
|
|
259
|
+
"Create a new Vectorize index for vector similarity search. Returns deploy_required=true since binding needs deploy to activate.",
|
|
260
|
+
inputSchema: {
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: {
|
|
263
|
+
name: {
|
|
264
|
+
type: "string",
|
|
265
|
+
description: "Index name (auto-generated if not provided)",
|
|
266
|
+
},
|
|
267
|
+
dimensions: {
|
|
268
|
+
type: "number",
|
|
269
|
+
default: 768,
|
|
270
|
+
description: "Vector dimensions (default: 768 for bge-base-en-v1.5)",
|
|
271
|
+
},
|
|
272
|
+
metric: {
|
|
273
|
+
type: "string",
|
|
274
|
+
enum: ["cosine", "euclidean", "dot-product"],
|
|
275
|
+
default: "cosine",
|
|
276
|
+
description: "Distance metric (default: cosine)",
|
|
277
|
+
},
|
|
278
|
+
project_path: {
|
|
279
|
+
type: "string",
|
|
280
|
+
description: "Path to project directory (defaults to current directory)",
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "list_vectorize_indexes",
|
|
287
|
+
description: "List all Vectorize indexes for a project.",
|
|
288
|
+
inputSchema: {
|
|
289
|
+
type: "object",
|
|
290
|
+
properties: {
|
|
291
|
+
project_path: {
|
|
292
|
+
type: "string",
|
|
293
|
+
description: "Path to project directory (defaults to current directory)",
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: "delete_vectorize_index",
|
|
300
|
+
description: "Delete a Vectorize index.",
|
|
301
|
+
inputSchema: {
|
|
302
|
+
type: "object",
|
|
303
|
+
properties: {
|
|
304
|
+
name: {
|
|
305
|
+
type: "string",
|
|
306
|
+
description: "Index name to delete",
|
|
307
|
+
},
|
|
308
|
+
project_path: {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Path to project directory (defaults to current directory)",
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
required: ["name"],
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "get_vectorize_info",
|
|
318
|
+
description:
|
|
319
|
+
"Get information about a Vectorize index (dimensions, metric, vector count).",
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: "object",
|
|
322
|
+
properties: {
|
|
323
|
+
name: {
|
|
324
|
+
type: "string",
|
|
325
|
+
description: "Index name",
|
|
326
|
+
},
|
|
327
|
+
project_path: {
|
|
328
|
+
type: "string",
|
|
329
|
+
description: "Path to project directory (defaults to current directory)",
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
required: ["name"],
|
|
333
|
+
},
|
|
334
|
+
},
|
|
215
335
|
],
|
|
216
336
|
};
|
|
217
337
|
});
|
|
@@ -550,6 +670,168 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
550
670
|
};
|
|
551
671
|
}
|
|
552
672
|
|
|
673
|
+
case "create_vectorize_index": {
|
|
674
|
+
const args = CreateVectorizeIndexSchema.parse(request.params.arguments ?? {});
|
|
675
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
676
|
+
|
|
677
|
+
const wrappedCreateVectorizeIndex = withTelemetry(
|
|
678
|
+
"create_vectorize_index",
|
|
679
|
+
async (
|
|
680
|
+
projectDir: string,
|
|
681
|
+
name?: string,
|
|
682
|
+
dimensions?: number,
|
|
683
|
+
metric?: "cosine" | "euclidean" | "dot-product",
|
|
684
|
+
) => {
|
|
685
|
+
const result = await createVectorizeIndex(projectDir, {
|
|
686
|
+
name,
|
|
687
|
+
dimensions,
|
|
688
|
+
metric,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// Track business event
|
|
692
|
+
track(Events.SERVICE_CREATED, {
|
|
693
|
+
service_type: "vectorize",
|
|
694
|
+
platform: "mcp",
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
return {
|
|
698
|
+
index_name: result.indexName,
|
|
699
|
+
binding_name: result.bindingName,
|
|
700
|
+
dimensions: result.dimensions,
|
|
701
|
+
metric: result.metric,
|
|
702
|
+
created: result.created,
|
|
703
|
+
deploy_required: true,
|
|
704
|
+
};
|
|
705
|
+
},
|
|
706
|
+
{ platform: "mcp" },
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
const result = await wrappedCreateVectorizeIndex(
|
|
710
|
+
projectPath,
|
|
711
|
+
args.name,
|
|
712
|
+
args.dimensions,
|
|
713
|
+
args.metric,
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
return {
|
|
717
|
+
content: [
|
|
718
|
+
{
|
|
719
|
+
type: "text",
|
|
720
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
721
|
+
},
|
|
722
|
+
],
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
case "list_vectorize_indexes": {
|
|
727
|
+
const args = ListVectorizeIndexesSchema.parse(request.params.arguments ?? {});
|
|
728
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
729
|
+
|
|
730
|
+
const wrappedListVectorizeIndexes = withTelemetry(
|
|
731
|
+
"list_vectorize_indexes",
|
|
732
|
+
async (projectDir: string) => {
|
|
733
|
+
const indexes = await listVectorizeIndexes(projectDir);
|
|
734
|
+
return {
|
|
735
|
+
indexes: indexes.map((idx) => ({
|
|
736
|
+
name: idx.name,
|
|
737
|
+
binding: idx.binding,
|
|
738
|
+
dimensions: idx.dimensions,
|
|
739
|
+
metric: idx.metric,
|
|
740
|
+
vector_count: idx.vectorCount,
|
|
741
|
+
})),
|
|
742
|
+
};
|
|
743
|
+
},
|
|
744
|
+
{ platform: "mcp" },
|
|
745
|
+
);
|
|
746
|
+
|
|
747
|
+
const result = await wrappedListVectorizeIndexes(projectPath);
|
|
748
|
+
|
|
749
|
+
return {
|
|
750
|
+
content: [
|
|
751
|
+
{
|
|
752
|
+
type: "text",
|
|
753
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
754
|
+
},
|
|
755
|
+
],
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
case "delete_vectorize_index": {
|
|
760
|
+
const args = DeleteVectorizeIndexSchema.parse(request.params.arguments ?? {});
|
|
761
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
762
|
+
|
|
763
|
+
const wrappedDeleteVectorizeIndex = withTelemetry(
|
|
764
|
+
"delete_vectorize_index",
|
|
765
|
+
async (projectDir: string, indexName: string) => {
|
|
766
|
+
const result = await deleteVectorizeIndex(projectDir, indexName);
|
|
767
|
+
|
|
768
|
+
// Track business event
|
|
769
|
+
track(Events.SERVICE_DELETED, {
|
|
770
|
+
service_type: "vectorize",
|
|
771
|
+
platform: "mcp",
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
index_name: result.indexName,
|
|
776
|
+
deleted: result.deleted,
|
|
777
|
+
binding_removed: result.bindingRemoved,
|
|
778
|
+
};
|
|
779
|
+
},
|
|
780
|
+
{ platform: "mcp" },
|
|
781
|
+
);
|
|
782
|
+
|
|
783
|
+
const result = await wrappedDeleteVectorizeIndex(projectPath, args.name);
|
|
784
|
+
|
|
785
|
+
return {
|
|
786
|
+
content: [
|
|
787
|
+
{
|
|
788
|
+
type: "text",
|
|
789
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
790
|
+
},
|
|
791
|
+
],
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
case "get_vectorize_info": {
|
|
796
|
+
const args = GetVectorizeInfoSchema.parse(request.params.arguments ?? {});
|
|
797
|
+
|
|
798
|
+
const wrappedGetVectorizeInfo = withTelemetry(
|
|
799
|
+
"get_vectorize_info",
|
|
800
|
+
async (indexName: string) => {
|
|
801
|
+
const info = await getVectorizeInfo(indexName);
|
|
802
|
+
|
|
803
|
+
if (!info) {
|
|
804
|
+
throw new JackError(
|
|
805
|
+
JackErrorCode.RESOURCE_NOT_FOUND,
|
|
806
|
+
`Vectorize index '${indexName}' not found`,
|
|
807
|
+
"Use list_vectorize_indexes to see available indexes",
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
return {
|
|
812
|
+
name: info.name,
|
|
813
|
+
dimensions: info.dimensions,
|
|
814
|
+
metric: info.metric,
|
|
815
|
+
vector_count: info.vectorCount,
|
|
816
|
+
created_on: info.createdOn,
|
|
817
|
+
modified_on: info.modifiedOn,
|
|
818
|
+
};
|
|
819
|
+
},
|
|
820
|
+
{ platform: "mcp" },
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
const result = await wrappedGetVectorizeInfo(args.name);
|
|
824
|
+
|
|
825
|
+
return {
|
|
826
|
+
content: [
|
|
827
|
+
{
|
|
828
|
+
type: "text",
|
|
829
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
830
|
+
},
|
|
831
|
+
],
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
|
|
553
835
|
default:
|
|
554
836
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
555
837
|
}
|