@manfred-kunze-dev/backbone-mcp-server 2.6.0-dev.4

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.
@@ -0,0 +1,252 @@
1
+ import { z } from "zod";
2
+ import { readFile } from "node:fs/promises";
3
+ import { basename, extname } from "node:path";
4
+ import { formatErrorForMcp } from "../errors.js";
5
+ const IMAGE_MIME_TYPES = {
6
+ ".png": "image/png",
7
+ ".jpg": "image/jpeg",
8
+ ".jpeg": "image/jpeg",
9
+ ".gif": "image/gif",
10
+ ".webp": "image/webp",
11
+ };
12
+ export function register(server, client) {
13
+ // ── create_extraction ───────────────────────────────────────────────────
14
+ server.tool("backbone_create_extraction", "Extract structured data from text and/or images using a schema and AI model. Supports text-only, vision (images), or combined extraction. Use a vision-capable model (e.g. openai/gpt-4o) when providing images.", {
15
+ projectId: z.string().describe("The project ID"),
16
+ schemaId: z.string().describe("The schema ID to extract with"),
17
+ schemaVersionId: z
18
+ .string()
19
+ .optional()
20
+ .describe("Specific schema version ID (uses latest active version if omitted)"),
21
+ inputText: z
22
+ .string()
23
+ .optional()
24
+ .describe("The text to extract structured data from (required unless inputImages provided)"),
25
+ inputImages: z
26
+ .array(z.object({
27
+ type: z.enum(["base64", "file"]).describe("Source type: 'base64' for pre-encoded data, 'file' for local file path"),
28
+ data: z.string().optional().describe("Base64-encoded image data (when type='base64')"),
29
+ path: z.string().optional().describe("Local file path to image (when type='file')"),
30
+ mimeType: z.string().optional().describe("MIME type (auto-detected for files, required for base64)"),
31
+ }))
32
+ .optional()
33
+ .describe("Images for vision extraction (max 10). Requires a vision-capable model."),
34
+ model: z.string().describe("AI model in 'provider/model' format"),
35
+ async: z
36
+ .boolean()
37
+ .optional()
38
+ .default(false)
39
+ .describe("If true, submit as async extraction and return immediately (not supported with images)"),
40
+ }, async ({ projectId, schemaId, schemaVersionId, inputText, inputImages, model, async: isAsync }) => {
41
+ try {
42
+ // Resolve images: read local files and convert to base64
43
+ const resolvedImages = [];
44
+ if (inputImages?.length) {
45
+ for (const img of inputImages) {
46
+ if (img.type === "file") {
47
+ if (!img.path)
48
+ throw new Error("path is required for type='file'");
49
+ const fileBuffer = await readFile(img.path);
50
+ const ext = extname(img.path).toLowerCase();
51
+ const mimeType = img.mimeType ?? IMAGE_MIME_TYPES[ext];
52
+ if (!mimeType)
53
+ throw new Error(`Cannot determine MIME type for ${basename(img.path)}. Supported: ${Object.keys(IMAGE_MIME_TYPES).join(", ")}`);
54
+ resolvedImages.push({ data: fileBuffer.toString("base64"), mimeType });
55
+ }
56
+ else {
57
+ if (!img.data)
58
+ throw new Error("data is required for type='base64'");
59
+ if (!img.mimeType)
60
+ throw new Error("mimeType is required for type='base64'");
61
+ resolvedImages.push({ data: img.data, mimeType: img.mimeType });
62
+ }
63
+ }
64
+ }
65
+ const body = {
66
+ schemaId,
67
+ model,
68
+ ...(inputText && { inputText }),
69
+ ...(resolvedImages.length > 0 && { inputImages: resolvedImages }),
70
+ ...(schemaVersionId && { schemaVersionId }),
71
+ };
72
+ if (isAsync) {
73
+ const { data } = await client.POST("/v1/projects/{projectId}/extractions/async", {
74
+ params: { path: { projectId } },
75
+ body,
76
+ });
77
+ const result = data;
78
+ return {
79
+ content: [
80
+ {
81
+ type: "text",
82
+ text: `Extraction submitted (id: ${result.id}, status: ${result.status}). Poll with backbone_get_extraction to check progress.`,
83
+ },
84
+ ],
85
+ };
86
+ }
87
+ const { data } = await client.POST("/v1/projects/{projectId}/extractions", {
88
+ params: { path: { projectId } },
89
+ body,
90
+ });
91
+ const result = data;
92
+ if (result.status === "PENDING" || result.status === "PROCESSING") {
93
+ return {
94
+ content: [
95
+ {
96
+ type: "text",
97
+ text: `Extraction submitted (id: ${result.id}, status: ${result.status}). Poll with backbone_get_extraction to check progress.`,
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ return { content: formatExtractionResult(result) };
103
+ }
104
+ catch (error) {
105
+ return {
106
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
107
+ isError: true,
108
+ };
109
+ }
110
+ });
111
+ // ── get_extraction ──────────────────────────────────────────────────────
112
+ server.tool("backbone_get_extraction", "Get an extraction by its ID. Use this to check the status of async extractions or retrieve results.", {
113
+ projectId: z.string().describe("The project ID"),
114
+ extractionId: z.string().describe("The extraction ID"),
115
+ }, async ({ projectId, extractionId }) => {
116
+ try {
117
+ const { data } = await client.GET("/v1/projects/{projectId}/extractions/{id}", {
118
+ params: { path: { projectId, id: extractionId } },
119
+ });
120
+ return { content: formatExtractionResult(data) };
121
+ }
122
+ catch (error) {
123
+ return {
124
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
125
+ isError: true,
126
+ };
127
+ }
128
+ });
129
+ // ── list_extractions ────────────────────────────────────────────────────
130
+ server.tool("backbone_list_extractions", "List extractions within a project with optional filtering by status, schema version, or search term.", {
131
+ projectId: z.string().describe("The project ID"),
132
+ status: z
133
+ .enum(["PENDING", "PROCESSING", "COMPLETED", "FAILED"])
134
+ .optional()
135
+ .describe("Filter by extraction status"),
136
+ schemaVersionId: z.string().optional().describe("Filter by schema version ID"),
137
+ search: z.string().optional().describe("Search by model name"),
138
+ page: z.number().optional().default(0).describe("Page number (0-based)"),
139
+ size: z.number().optional().default(20).describe("Page size"),
140
+ sort: z.string().optional().describe("Sort field and direction (default: createdAt,desc)"),
141
+ }, async ({ projectId, status, schemaVersionId, search, page, size, sort }) => {
142
+ try {
143
+ const { data } = await client.GET("/v1/projects/{projectId}/extractions", {
144
+ params: {
145
+ path: { projectId },
146
+ query: {
147
+ status,
148
+ schemaVersionId,
149
+ search,
150
+ page,
151
+ size,
152
+ sort: sort ? [sort] : undefined,
153
+ },
154
+ },
155
+ });
156
+ const result = data;
157
+ const lines = (result.content ?? []).map((e) => `- ${e.id} [${e.status}] model=${e.model} schema=${e.schemaId}${e.errorMessage ? ` error: ${e.errorMessage}` : ""}`);
158
+ return {
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: `Extractions (${result.totalElements} total, page ${(result.number ?? 0) + 1}/${result.totalPages}):\n${lines.join("\n") || "(none)"}`,
163
+ },
164
+ ],
165
+ };
166
+ }
167
+ catch (error) {
168
+ return {
169
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
170
+ isError: true,
171
+ };
172
+ }
173
+ });
174
+ // ── estimate_tokens ─────────────────────────────────────────────────────
175
+ server.tool("backbone_estimate_tokens", "Estimate token usage for an extraction without executing it. Useful for cost estimation.", {
176
+ projectId: z.string().describe("The project ID"),
177
+ schemaId: z.string().describe("The schema ID"),
178
+ schemaVersionId: z.string().optional().describe("Specific schema version ID"),
179
+ inputText: z.string().describe("The text to estimate tokens for"),
180
+ }, async ({ projectId, schemaId, schemaVersionId, inputText }) => {
181
+ try {
182
+ const { data } = await client.POST("/v1/projects/{projectId}/extractions/estimate", {
183
+ params: { path: { projectId } },
184
+ body: {
185
+ schemaId,
186
+ inputText,
187
+ ...(schemaVersionId && { schemaVersionId }),
188
+ },
189
+ });
190
+ const result = data;
191
+ return {
192
+ content: [
193
+ {
194
+ type: "text",
195
+ text: `Token estimate:\n Input tokens: ${result.inputTokens}\n Estimated output tokens: ${result.estimatedOutputTokens}\n Strategy: ${result.strategy}`,
196
+ },
197
+ ],
198
+ };
199
+ }
200
+ catch (error) {
201
+ return {
202
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
203
+ isError: true,
204
+ };
205
+ }
206
+ });
207
+ // ── rerun_extraction ────────────────────────────────────────────────────
208
+ server.tool("backbone_rerun_extraction", "Re-run an existing extraction with the same configuration. Creates a new extraction.", {
209
+ projectId: z.string().describe("The project ID"),
210
+ extractionId: z.string().describe("The extraction ID to re-run"),
211
+ }, async ({ projectId, extractionId }) => {
212
+ try {
213
+ const { data } = await client.POST("/v1/projects/{projectId}/extractions/{id}/rerun", {
214
+ params: { path: { projectId, id: extractionId } },
215
+ });
216
+ return { content: formatExtractionResult(data) };
217
+ }
218
+ catch (error) {
219
+ return {
220
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
221
+ isError: true,
222
+ };
223
+ }
224
+ });
225
+ }
226
+ function formatExtractionResult(extraction) {
227
+ const parts = [];
228
+ parts.push({
229
+ type: "text",
230
+ text: `Extraction ${extraction.id} [${extraction.status}]\nModel: ${extraction.model}${extraction.strategy ? `\nStrategy: ${extraction.strategy}` : ""}`,
231
+ });
232
+ if (extraction.status === "COMPLETED" && extraction.result) {
233
+ parts.push({
234
+ type: "text",
235
+ text: `Result:\n${JSON.stringify(extraction.result, null, 2)}`,
236
+ });
237
+ }
238
+ if (extraction.status === "FAILED" && extraction.errorMessage) {
239
+ parts.push({
240
+ type: "text",
241
+ text: `Error: ${extraction.errorMessage}`,
242
+ });
243
+ }
244
+ if (extraction.estimatedInputTokens != null) {
245
+ parts.push({
246
+ type: "text",
247
+ text: `Tokens: ~${extraction.estimatedInputTokens} input, ~${extraction.estimatedOutputTokens} output`,
248
+ });
249
+ }
250
+ return parts;
251
+ }
252
+ //# sourceMappingURL=extraction.js.map
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function register(server: McpServer, client: ApiClient): void;
4
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1,129 @@
1
+ import { z } from "zod";
2
+ import { formatErrorForMcp } from "../errors.js";
3
+ export function register(server, client) {
4
+ // ── list_projects ───────────────────────────────────────────────────────
5
+ server.tool("backbone_list_projects", "List projects in the organization with optional search and pagination.", {
6
+ search: z.string().optional().describe("Filter projects by name"),
7
+ page: z.number().optional().default(0).describe("Page number (0-based)"),
8
+ size: z.number().optional().default(20).describe("Page size"),
9
+ sort: z.string().optional().describe("Sort field and direction, e.g. 'name,asc'"),
10
+ }, async ({ search, page, size, sort }) => {
11
+ try {
12
+ const { data } = await client.GET("/v1/projects", {
13
+ params: {
14
+ query: {
15
+ search,
16
+ page,
17
+ size,
18
+ sort: sort ? [sort] : undefined,
19
+ },
20
+ },
21
+ });
22
+ const result = data;
23
+ const lines = (result.content ?? []).map((p) => `- ${p.name} (id: ${p.id})${p.description ? ` — ${p.description}` : ""}`);
24
+ return {
25
+ content: [
26
+ {
27
+ type: "text",
28
+ text: `Projects (${result.totalElements} total, page ${(result.number ?? 0) + 1}/${result.totalPages}):\n${lines.join("\n") || "(none)"}`,
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ catch (error) {
34
+ return {
35
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
36
+ isError: true,
37
+ };
38
+ }
39
+ });
40
+ // ── get_project ─────────────────────────────────────────────────────────
41
+ server.tool("backbone_get_project", "Get a project by its ID.", {
42
+ projectId: z.string().describe("The project ID"),
43
+ }, async ({ projectId }) => {
44
+ try {
45
+ const { data } = await client.GET("/v1/projects/{id}", {
46
+ params: { path: { id: projectId } },
47
+ });
48
+ return {
49
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
50
+ };
51
+ }
52
+ catch (error) {
53
+ return {
54
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
55
+ isError: true,
56
+ };
57
+ }
58
+ });
59
+ // ── create_project ──────────────────────────────────────────────────────
60
+ server.tool("backbone_create_project", "Create a new project in the organization.", {
61
+ name: z.string().min(1).max(255).describe("Project name"),
62
+ description: z.string().max(1000).optional().describe("Project description"),
63
+ }, async ({ name, description }) => {
64
+ try {
65
+ const { data } = await client.POST("/v1/projects", {
66
+ body: {
67
+ name,
68
+ ...(description !== undefined && { description }),
69
+ },
70
+ });
71
+ return {
72
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
73
+ };
74
+ }
75
+ catch (error) {
76
+ return {
77
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
78
+ isError: true,
79
+ };
80
+ }
81
+ });
82
+ // ── update_project ──────────────────────────────────────────────────────
83
+ server.tool("backbone_update_project", "Update an existing project.", {
84
+ projectId: z.string().describe("The project ID"),
85
+ name: z.string().min(1).max(255).optional().describe("New project name"),
86
+ description: z.string().max(1000).optional().describe("New project description"),
87
+ }, async ({ projectId, name, description }) => {
88
+ try {
89
+ const body = {};
90
+ if (name !== undefined)
91
+ body.name = name;
92
+ if (description !== undefined)
93
+ body.description = description;
94
+ const { data } = await client.PUT("/v1/projects/{id}", {
95
+ params: { path: { id: projectId } },
96
+ body: body,
97
+ });
98
+ return {
99
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
100
+ };
101
+ }
102
+ catch (error) {
103
+ return {
104
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
105
+ isError: true,
106
+ };
107
+ }
108
+ });
109
+ // ── delete_project ──────────────────────────────────────────────────────
110
+ server.tool("backbone_delete_project", "Delete a project and all its associated data (schemas, extractions). This action is irreversible.", {
111
+ projectId: z.string().describe("The project ID to delete"),
112
+ }, async ({ projectId }) => {
113
+ try {
114
+ await client.DELETE("/v1/projects/{id}", {
115
+ params: { path: { id: projectId } },
116
+ });
117
+ return {
118
+ content: [{ type: "text", text: `Project ${projectId} deleted successfully.` }],
119
+ };
120
+ }
121
+ catch (error) {
122
+ return {
123
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
124
+ isError: true,
125
+ };
126
+ }
127
+ });
128
+ }
129
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function register(server: McpServer, client: ApiClient): void;
4
+ //# sourceMappingURL=schema-testing.d.ts.map
@@ -0,0 +1,102 @@
1
+ import { z } from "zod";
2
+ import { formatErrorForMcp } from "../errors.js";
3
+ import { ensureOpenAiCompatible } from "../schema-compat.js";
4
+ /* ── helpers ─────────────────────────────────────────────────────────────── */
5
+ function formatTestResult(result) {
6
+ const parts = [];
7
+ parts.push(`Success: ${result.success}`);
8
+ if (result.extractedData) {
9
+ parts.push(`Extracted data:\n${JSON.stringify(result.extractedData, null, 2)}`);
10
+ }
11
+ if (result.error) {
12
+ parts.push(`Error: ${result.error}`);
13
+ }
14
+ if (result.modelUsed) {
15
+ parts.push(`Model: ${result.modelUsed}`);
16
+ }
17
+ if (result.inputTokens != null || result.outputTokens != null) {
18
+ parts.push(`Tokens: ${result.inputTokens ?? 0} input, ${result.outputTokens ?? 0} output`);
19
+ }
20
+ if (result.processingDurationMs != null) {
21
+ parts.push(`Processing time: ${result.processingDurationMs}ms`);
22
+ }
23
+ return parts.join("\n");
24
+ }
25
+ export function register(server, client) {
26
+ // ── validate_schema ─────────────────────────────────────────────────────
27
+ server.tool("backbone_validate_schema", "Validate a JSON Schema definition without persisting it. Returns validation errors and warnings.", {
28
+ projectId: z.string().describe("The project ID"),
29
+ schemaId: z.string().describe("The schema ID"),
30
+ jsonSchema: z.unknown().describe("The JSON Schema to validate"),
31
+ }, async ({ projectId, schemaId, jsonSchema }) => {
32
+ try {
33
+ const { data } = await client.POST("/v1/projects/{projectId}/schemas/{schemaId}/validate", {
34
+ params: { path: { projectId, schemaId } },
35
+ body: {
36
+ jsonSchema: ensureOpenAiCompatible(jsonSchema),
37
+ },
38
+ });
39
+ const result = data;
40
+ const parts = [];
41
+ parts.push(`Valid: ${result.valid}`);
42
+ if (result.errors && result.errors.length > 0) {
43
+ parts.push(`\nErrors:\n${result.errors.map((e) => ` - ${e}`).join("\n")}`);
44
+ }
45
+ if (result.warnings && result.warnings.length > 0) {
46
+ parts.push(`\nWarnings:\n${result.warnings.map((w) => ` - ${w}`).join("\n")}`);
47
+ }
48
+ return {
49
+ content: [{ type: "text", text: parts.join("\n") }],
50
+ };
51
+ }
52
+ catch (error) {
53
+ return {
54
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
55
+ isError: true,
56
+ };
57
+ }
58
+ });
59
+ // ── test_schema ─────────────────────────────────────────────────────────
60
+ server.tool("backbone_test_schema", "Test a JSON Schema against sample text using AI extraction. Returns the extraction result and token usage without creating a persistent extraction.", {
61
+ projectId: z.string().describe("The project ID"),
62
+ schemaId: z.string().describe("The schema ID"),
63
+ jsonSchema: z.unknown().describe("The JSON Schema to test"),
64
+ sampleText: z.string().describe("Sample text to extract data from"),
65
+ model: z.string().describe("AI model in 'provider/model' format (e.g. 'openai/gpt-4o')"),
66
+ }, async ({ projectId, schemaId, jsonSchema, sampleText, model }) => {
67
+ try {
68
+ // Create a temporary version with this schema content, then test
69
+ // The API uses stored schema versions; we create one, test, then the caller can delete
70
+ // Actually the test endpoint accepts text + model + optional schemaVersionId
71
+ // We first need to create a version, then test against it
72
+ // For simplicity, we create a version inline and use its ID
73
+ const versionResult = await client.POST("/v1/projects/{projectId}/schemas/{schemaId}/versions", {
74
+ params: { path: { projectId, schemaId } },
75
+ body: {
76
+ jsonSchema: ensureOpenAiCompatible(jsonSchema),
77
+ changeDescription: "Test version",
78
+ },
79
+ });
80
+ const version = versionResult.data;
81
+ const { data } = await client.POST("/v1/projects/{projectId}/schemas/{schemaId}/test", {
82
+ params: { path: { projectId, schemaId } },
83
+ body: {
84
+ jsonSchema: ensureOpenAiCompatible(jsonSchema),
85
+ sampleText,
86
+ model,
87
+ },
88
+ });
89
+ const result = data;
90
+ return {
91
+ content: [{ type: "text", text: formatTestResult(result) }],
92
+ };
93
+ }
94
+ catch (error) {
95
+ return {
96
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
97
+ isError: true,
98
+ };
99
+ }
100
+ });
101
+ }
102
+ //# sourceMappingURL=schema-testing.js.map
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function register(server: McpServer, client: ApiClient): void;
4
+ //# sourceMappingURL=schema-versions.d.ts.map
@@ -0,0 +1,129 @@
1
+ import { z } from "zod";
2
+ import { formatErrorForMcp } from "../errors.js";
3
+ import { ensureOpenAiCompatible } from "../schema-compat.js";
4
+ export function register(server, client) {
5
+ // ── create_schema_version ───────────────────────────────────────────────
6
+ server.tool("backbone_create_schema_version", "Create a new version for a schema. The new version becomes the active one.", {
7
+ projectId: z.string().describe("The project ID"),
8
+ schemaId: z.string().describe("The schema ID"),
9
+ jsonSchema: z.unknown().describe("The JSON Schema definition for this version"),
10
+ changeDescription: z
11
+ .string()
12
+ .optional()
13
+ .describe("Description of what changed in this version"),
14
+ }, async ({ projectId, schemaId, jsonSchema, changeDescription }) => {
15
+ try {
16
+ const { data } = await client.POST("/v1/projects/{projectId}/schemas/{schemaId}/versions", {
17
+ params: { path: { projectId, schemaId } },
18
+ body: {
19
+ jsonSchema: ensureOpenAiCompatible(jsonSchema),
20
+ ...(changeDescription && { changeDescription }),
21
+ },
22
+ });
23
+ return {
24
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
25
+ };
26
+ }
27
+ catch (error) {
28
+ return {
29
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
30
+ isError: true,
31
+ };
32
+ }
33
+ });
34
+ // ── list_schema_versions ────────────────────────────────────────────────
35
+ server.tool("backbone_list_schema_versions", "List all versions of a schema with pagination.", {
36
+ projectId: z.string().describe("The project ID"),
37
+ schemaId: z.string().describe("The schema ID"),
38
+ page: z.number().optional().default(0).describe("Page number (0-based)"),
39
+ size: z.number().optional().default(20).describe("Page size"),
40
+ }, async ({ projectId, schemaId, page, size }) => {
41
+ try {
42
+ const { data } = await client.GET("/v1/projects/{projectId}/schemas/{schemaId}/versions", {
43
+ params: {
44
+ path: { projectId, schemaId },
45
+ query: { page, size },
46
+ },
47
+ });
48
+ const result = data;
49
+ const lines = (result.content ?? []).map((v) => `- v${v.versionNumber} (id: ${v.id}) ${v.isActive ? "[ACTIVE]" : "[inactive]"}${v.changeDescription ? ` — ${v.changeDescription}` : ""}`);
50
+ return {
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: `Schema versions (${result.totalElements} total, page ${(result.number ?? 0) + 1}/${result.totalPages}):\n${lines.join("\n") || "(none)"}`,
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ catch (error) {
60
+ return {
61
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
62
+ isError: true,
63
+ };
64
+ }
65
+ });
66
+ // ── get_schema_version ──────────────────────────────────────────────────
67
+ server.tool("backbone_get_schema_version", "Get a specific schema version by its ID.", {
68
+ projectId: z.string().describe("The project ID"),
69
+ schemaId: z.string().describe("The schema ID"),
70
+ versionId: z.string().describe("The version ID"),
71
+ }, async ({ projectId, schemaId, versionId }) => {
72
+ try {
73
+ const { data } = await client.GET("/v1/projects/{projectId}/schemas/{schemaId}/versions/{versionId}", {
74
+ params: { path: { projectId, schemaId, versionId } },
75
+ });
76
+ return {
77
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
78
+ };
79
+ }
80
+ catch (error) {
81
+ return {
82
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
83
+ isError: true,
84
+ };
85
+ }
86
+ });
87
+ // ── get_latest_schema_version ───────────────────────────────────────────
88
+ server.tool("backbone_get_latest_schema_version", "Get the latest active version of a schema.", {
89
+ projectId: z.string().describe("The project ID"),
90
+ schemaId: z.string().describe("The schema ID"),
91
+ }, async ({ projectId, schemaId }) => {
92
+ try {
93
+ const { data } = await client.GET("/v1/projects/{projectId}/schemas/{schemaId}/versions/latest", {
94
+ params: { path: { projectId, schemaId } },
95
+ });
96
+ return {
97
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
98
+ };
99
+ }
100
+ catch (error) {
101
+ return {
102
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
103
+ isError: true,
104
+ };
105
+ }
106
+ });
107
+ // ── activate_schema_version ─────────────────────────────────────────────
108
+ server.tool("backbone_activate_schema_version", "Re-activate a historical schema version by creating a copy as the newest active version.", {
109
+ projectId: z.string().describe("The project ID"),
110
+ schemaId: z.string().describe("The schema ID"),
111
+ versionId: z.string().describe("The version ID to activate"),
112
+ }, async ({ projectId, schemaId, versionId }) => {
113
+ try {
114
+ const { data } = await client.PUT("/v1/projects/{projectId}/schemas/{schemaId}/versions/{versionId}/activate", {
115
+ params: { path: { projectId, schemaId, versionId } },
116
+ });
117
+ return {
118
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
119
+ };
120
+ }
121
+ catch (error) {
122
+ return {
123
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
124
+ isError: true,
125
+ };
126
+ }
127
+ });
128
+ }
129
+ //# sourceMappingURL=schema-versions.js.map
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../client.js";
3
+ export declare function register(server: McpServer, client: ApiClient): void;
4
+ //# sourceMappingURL=schemas.d.ts.map