@meshy-ai/meshy-mcp-server 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/.env.example +14 -0
- package/LICENSE +21 -0
- package/README.md +108 -0
- package/dist/constants.d.ts +123 -0
- package/dist/constants.js +169 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +130 -0
- package/dist/instructions.d.ts +6 -0
- package/dist/instructions.js +90 -0
- package/dist/schemas/balance.d.ts +11 -0
- package/dist/schemas/balance.js +8 -0
- package/dist/schemas/common.d.ts +38 -0
- package/dist/schemas/common.js +52 -0
- package/dist/schemas/generation.d.ts +219 -0
- package/dist/schemas/generation.js +217 -0
- package/dist/schemas/image.d.ts +55 -0
- package/dist/schemas/image.js +46 -0
- package/dist/schemas/output.d.ts +75 -0
- package/dist/schemas/output.js +41 -0
- package/dist/schemas/postprocessing.d.ts +135 -0
- package/dist/schemas/postprocessing.js +123 -0
- package/dist/schemas/printing.d.ts +63 -0
- package/dist/schemas/printing.js +54 -0
- package/dist/schemas/tasks.d.ts +123 -0
- package/dist/schemas/tasks.js +85 -0
- package/dist/services/error-handler.d.ts +32 -0
- package/dist/services/error-handler.js +141 -0
- package/dist/services/file-utils.d.ts +15 -0
- package/dist/services/file-utils.js +55 -0
- package/dist/services/meshy-client.d.ts +54 -0
- package/dist/services/meshy-client.js +172 -0
- package/dist/services/output-manager.d.ts +52 -0
- package/dist/services/output-manager.js +284 -0
- package/dist/tools/balance.d.ts +9 -0
- package/dist/tools/balance.js +61 -0
- package/dist/tools/generation.d.ts +9 -0
- package/dist/tools/generation.js +419 -0
- package/dist/tools/image.d.ts +9 -0
- package/dist/tools/image.js +154 -0
- package/dist/tools/postprocessing.d.ts +9 -0
- package/dist/tools/postprocessing.js +405 -0
- package/dist/tools/printing.d.ts +9 -0
- package/dist/tools/printing.js +338 -0
- package/dist/tools/tasks.d.ts +9 -0
- package/dist/tools/tasks.js +1074 -0
- package/dist/tools/workspace.d.ts +9 -0
- package/dist/tools/workspace.js +161 -0
- package/dist/types.d.ts +261 -0
- package/dist/types.js +4 -0
- package/dist/utils/endpoints.d.ts +16 -0
- package/dist/utils/endpoints.js +38 -0
- package/dist/utils/request-builder.d.ts +15 -0
- package/dist/utils/request-builder.js +24 -0
- package/dist/utils/response-formatter.d.ts +27 -0
- package/dist/utils/response-formatter.js +37 -0
- package/dist/utils/slicer-detector.d.ts +29 -0
- package/dist/utils/slicer-detector.js +237 -0
- package/package.json +64 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace tools (list models)
|
|
3
|
+
*/
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { MeshyClient } from "../services/meshy-client.js";
|
|
6
|
+
/**
|
|
7
|
+
* Register workspace tools with the MCP server
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerWorkspaceTools(server: McpServer, client: MeshyClient): void;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace tools (list models)
|
|
3
|
+
*/
|
|
4
|
+
import { handleMeshyError } from "../services/error-handler.js";
|
|
5
|
+
import { ListModelsInputSchema } from "../schemas/tasks.js";
|
|
6
|
+
import { ResponseFormat, TaskStatus, CHARACTER_LIMIT } from "../constants.js";
|
|
7
|
+
/**
|
|
8
|
+
* Register workspace tools with the MCP server
|
|
9
|
+
*/
|
|
10
|
+
export function registerWorkspaceTools(server, client) {
|
|
11
|
+
// List models tool
|
|
12
|
+
server.registerTool("meshy_list_models", {
|
|
13
|
+
title: "List Workspace Models",
|
|
14
|
+
description: `Browse 3D models in your workspace with filtering and pagination.
|
|
15
|
+
|
|
16
|
+
This tool lists all completed models in your workspace. Only shows models with status SUCCEEDED.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
- workspace_id (string, optional): Workspace ID (uses default workspace if omitted)
|
|
20
|
+
- filter (enum): Filter by visibility - "all", "published", or "private" (default: "all")
|
|
21
|
+
- limit (number): Results per page, 1-100 (default: 20)
|
|
22
|
+
- offset (number): Skip N results for pagination (default: 0)
|
|
23
|
+
- response_format (enum): Output format - "markdown" or "json" (default: "markdown")
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
{
|
|
27
|
+
"page_count": 20,
|
|
28
|
+
"offset": 0,
|
|
29
|
+
"models": [
|
|
30
|
+
{
|
|
31
|
+
"id": "abc-123",
|
|
32
|
+
"name": "Dragon model",
|
|
33
|
+
"thumbnail_url": "https://...",
|
|
34
|
+
"created_at": "2026-03-02T10:00:00Z",
|
|
35
|
+
"vertex_count": 45231,
|
|
36
|
+
"face_count": 89456,
|
|
37
|
+
"is_published": false
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"has_more": true,
|
|
41
|
+
"next_offset": 20
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Use Cases:
|
|
45
|
+
- Browse your generated models
|
|
46
|
+
- Find models by creation date
|
|
47
|
+
- Filter published vs private models
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
- List recent models: { limit: 10 }
|
|
51
|
+
- List published models: { filter: "published" }
|
|
52
|
+
- Get second page: { limit: 20, offset: 20 }
|
|
53
|
+
|
|
54
|
+
Error Handling:
|
|
55
|
+
- Automatically truncates if response exceeds size limit`,
|
|
56
|
+
inputSchema: ListModelsInputSchema,
|
|
57
|
+
annotations: {
|
|
58
|
+
readOnlyHint: true,
|
|
59
|
+
destructiveHint: false,
|
|
60
|
+
idempotentHint: true,
|
|
61
|
+
openWorldHint: true
|
|
62
|
+
}
|
|
63
|
+
}, async (params) => {
|
|
64
|
+
try {
|
|
65
|
+
const pageSize = params.limit;
|
|
66
|
+
const pageNum = Math.floor(params.offset / pageSize) + 1;
|
|
67
|
+
const queryParams = {
|
|
68
|
+
status: TaskStatus.SUCCEEDED,
|
|
69
|
+
page_size: pageSize,
|
|
70
|
+
page_num: pageNum
|
|
71
|
+
};
|
|
72
|
+
// API returns Task[] directly
|
|
73
|
+
const response = await client.get("/openapi/v2/text-to-3d", queryParams);
|
|
74
|
+
const tasks = Array.isArray(response) ? response : [];
|
|
75
|
+
let filteredTasks = tasks;
|
|
76
|
+
if (params.filter === "published") {
|
|
77
|
+
filteredTasks = filteredTasks.filter(task => task.model_urls && task.is_published);
|
|
78
|
+
}
|
|
79
|
+
else if (params.filter === "private") {
|
|
80
|
+
filteredTasks = filteredTasks.filter(task => task.model_urls && !task.is_published);
|
|
81
|
+
}
|
|
82
|
+
const models = filteredTasks
|
|
83
|
+
.filter(task => task.model_urls)
|
|
84
|
+
.map(task => ({
|
|
85
|
+
id: task.id,
|
|
86
|
+
name: task.name || task.prompt || "Untitled Model",
|
|
87
|
+
thumbnail_url: task.thumbnail_url || "",
|
|
88
|
+
created_at: task.created_at,
|
|
89
|
+
vertex_count: task.vertex_count,
|
|
90
|
+
face_count: task.face_count,
|
|
91
|
+
is_published: task.is_published || false
|
|
92
|
+
}));
|
|
93
|
+
const output = {
|
|
94
|
+
page_count: models.length,
|
|
95
|
+
offset: params.offset,
|
|
96
|
+
models,
|
|
97
|
+
has_more: tasks.length >= pageSize,
|
|
98
|
+
next_offset: tasks.length >= pageSize
|
|
99
|
+
? params.offset + tasks.length
|
|
100
|
+
: undefined
|
|
101
|
+
};
|
|
102
|
+
// Helper to render models as markdown
|
|
103
|
+
const renderModelsMarkdown = (modelList, totalCount, truncated = false) => {
|
|
104
|
+
const lines = [`# Workspace Models`, ""];
|
|
105
|
+
lines.push(`**Showing**: ${totalCount} models on this page (offset: ${output.offset})`);
|
|
106
|
+
if (truncated)
|
|
107
|
+
lines.push(`*(truncated from ${models.length} results)*`);
|
|
108
|
+
lines.push("");
|
|
109
|
+
for (const model of modelList) {
|
|
110
|
+
lines.push(`## ${model.name}`);
|
|
111
|
+
lines.push(`- **ID**: ${model.id}`);
|
|
112
|
+
lines.push(`- **Created**: ${new Date(model.created_at).toLocaleString()}`);
|
|
113
|
+
if (model.vertex_count && model.face_count) {
|
|
114
|
+
lines.push(`- **Geometry**: ${model.vertex_count.toLocaleString()} vertices, ${model.face_count.toLocaleString()} faces`);
|
|
115
|
+
}
|
|
116
|
+
lines.push(`- **Published**: ${model.is_published ? 'Yes' : 'No'}`);
|
|
117
|
+
lines.push(`- **Thumbnail**: ${model.thumbnail_url}`);
|
|
118
|
+
lines.push("");
|
|
119
|
+
}
|
|
120
|
+
if (output.has_more) {
|
|
121
|
+
lines.push(`**More results available**. Use offset=${output.next_offset} to see next page.`);
|
|
122
|
+
}
|
|
123
|
+
return lines.join("\n");
|
|
124
|
+
};
|
|
125
|
+
let textContent;
|
|
126
|
+
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
127
|
+
textContent = renderModelsMarkdown(output.models, output.page_count);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
textContent = JSON.stringify(output, null, 2);
|
|
131
|
+
}
|
|
132
|
+
// Check character limit — re-render in same format with fewer models
|
|
133
|
+
if (textContent.length > CHARACTER_LIMIT) {
|
|
134
|
+
const truncatedModels = output.models.slice(0, Math.max(1, Math.floor(output.models.length / 2)));
|
|
135
|
+
output.models = truncatedModels;
|
|
136
|
+
output.page_count = truncatedModels.length;
|
|
137
|
+
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
138
|
+
textContent = renderModelsMarkdown(truncatedModels, truncatedModels.length, true) +
|
|
139
|
+
`\n\n[Response truncated. Use smaller limit to see more results.]`;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
textContent = JSON.stringify(output, null, 2) +
|
|
143
|
+
`\n\n[Response truncated. Use smaller limit to see more results.]`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: "text", text: textContent }],
|
|
148
|
+
structuredContent: output
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return {
|
|
153
|
+
isError: true,
|
|
154
|
+
content: [{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: handleMeshyError(error)
|
|
157
|
+
}]
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for Meshy API
|
|
3
|
+
*/
|
|
4
|
+
import { TaskStatus, TaskPhase, Topology, AIModel, ModelType, SymmetryMode, PoseMode } from "./constants.js";
|
|
5
|
+
export interface TextureUrlsObject {
|
|
6
|
+
base_color?: string;
|
|
7
|
+
metallic?: string;
|
|
8
|
+
roughness?: string;
|
|
9
|
+
normal?: string;
|
|
10
|
+
ao?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface TaskError {
|
|
13
|
+
code?: string;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateTaskApiResponse {
|
|
17
|
+
result: string;
|
|
18
|
+
}
|
|
19
|
+
export interface TextTo3DApiRequest {
|
|
20
|
+
mode: string;
|
|
21
|
+
prompt: string;
|
|
22
|
+
ai_model: string;
|
|
23
|
+
moderation: boolean;
|
|
24
|
+
model_type?: string;
|
|
25
|
+
target_polycount?: number;
|
|
26
|
+
topology?: string;
|
|
27
|
+
symmetry_mode?: string;
|
|
28
|
+
should_remesh?: boolean;
|
|
29
|
+
pose_mode?: string;
|
|
30
|
+
target_formats?: string[];
|
|
31
|
+
auto_size?: boolean;
|
|
32
|
+
origin_at?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ImageTo3DApiRequest {
|
|
35
|
+
image_url: string;
|
|
36
|
+
enable_pbr: boolean;
|
|
37
|
+
moderation: boolean;
|
|
38
|
+
ai_model?: string;
|
|
39
|
+
model_type?: string;
|
|
40
|
+
pose_mode?: string;
|
|
41
|
+
topology?: string;
|
|
42
|
+
target_polycount?: number;
|
|
43
|
+
should_remesh?: boolean;
|
|
44
|
+
symmetry_mode?: string;
|
|
45
|
+
should_texture?: boolean;
|
|
46
|
+
texture_prompt?: string;
|
|
47
|
+
texture_image_url?: string;
|
|
48
|
+
image_enhancement?: boolean;
|
|
49
|
+
remove_lighting?: boolean;
|
|
50
|
+
save_pre_remeshed_model?: boolean;
|
|
51
|
+
target_formats?: string[];
|
|
52
|
+
auto_size?: boolean;
|
|
53
|
+
origin_at?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface TextTo3DRefineApiRequest {
|
|
56
|
+
mode: string;
|
|
57
|
+
preview_task_id: string;
|
|
58
|
+
enable_pbr: boolean;
|
|
59
|
+
ai_model: string;
|
|
60
|
+
texture_prompt?: string;
|
|
61
|
+
texture_image_url?: string;
|
|
62
|
+
remove_lighting?: boolean;
|
|
63
|
+
target_formats?: string[];
|
|
64
|
+
auto_size?: boolean;
|
|
65
|
+
origin_at?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface MultiImageTo3DApiRequest {
|
|
68
|
+
image_urls: string[];
|
|
69
|
+
enable_pbr: boolean;
|
|
70
|
+
moderation: boolean;
|
|
71
|
+
ai_model?: string;
|
|
72
|
+
model_type?: string;
|
|
73
|
+
pose_mode?: string;
|
|
74
|
+
topology?: string;
|
|
75
|
+
target_polycount?: number;
|
|
76
|
+
should_remesh?: boolean;
|
|
77
|
+
symmetry_mode?: string;
|
|
78
|
+
should_texture?: boolean;
|
|
79
|
+
texture_prompt?: string;
|
|
80
|
+
texture_image_url?: string;
|
|
81
|
+
image_enhancement?: boolean;
|
|
82
|
+
remove_lighting?: boolean;
|
|
83
|
+
save_pre_remeshed_model?: boolean;
|
|
84
|
+
target_formats?: string[];
|
|
85
|
+
auto_size?: boolean;
|
|
86
|
+
origin_at?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface RemeshApiRequest {
|
|
89
|
+
target_formats: string[];
|
|
90
|
+
resize_height: number;
|
|
91
|
+
convert_format_only: boolean;
|
|
92
|
+
input_task_id?: string;
|
|
93
|
+
model_url?: string;
|
|
94
|
+
topology?: string;
|
|
95
|
+
target_polycount?: number;
|
|
96
|
+
auto_size?: boolean;
|
|
97
|
+
origin_at?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface RetextureApiRequest {
|
|
100
|
+
enable_original_uv: boolean;
|
|
101
|
+
enable_pbr: boolean;
|
|
102
|
+
input_task_id?: string;
|
|
103
|
+
model_url?: string;
|
|
104
|
+
text_style_prompt?: string;
|
|
105
|
+
image_style_url?: string;
|
|
106
|
+
ai_model?: string;
|
|
107
|
+
remove_lighting?: boolean;
|
|
108
|
+
target_formats?: string[];
|
|
109
|
+
}
|
|
110
|
+
export interface RigApiRequest {
|
|
111
|
+
height_meters: number;
|
|
112
|
+
input_task_id?: string;
|
|
113
|
+
model_url?: string;
|
|
114
|
+
texture_image_url?: string;
|
|
115
|
+
}
|
|
116
|
+
export interface AnimateApiRequest {
|
|
117
|
+
rig_task_id: string;
|
|
118
|
+
action_id: number;
|
|
119
|
+
post_process?: {
|
|
120
|
+
operation_type: string;
|
|
121
|
+
fps?: number;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export interface MultiColorPrintApiRequest {
|
|
125
|
+
input_task_id: string;
|
|
126
|
+
max_colors?: number;
|
|
127
|
+
max_depth?: number;
|
|
128
|
+
}
|
|
129
|
+
export interface TextToImageApiRequest {
|
|
130
|
+
ai_model: string;
|
|
131
|
+
prompt: string;
|
|
132
|
+
generate_multi_view: boolean;
|
|
133
|
+
aspect_ratio: string;
|
|
134
|
+
pose_mode?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface ImageToImageApiRequest {
|
|
137
|
+
ai_model: string;
|
|
138
|
+
prompt: string;
|
|
139
|
+
reference_image_urls: string[];
|
|
140
|
+
generate_multi_view: boolean;
|
|
141
|
+
}
|
|
142
|
+
export interface Task {
|
|
143
|
+
id: string;
|
|
144
|
+
name?: string;
|
|
145
|
+
type?: string;
|
|
146
|
+
status: TaskStatus;
|
|
147
|
+
phase: TaskPhase;
|
|
148
|
+
progress: number;
|
|
149
|
+
created_at: string | number;
|
|
150
|
+
started_at?: string | number;
|
|
151
|
+
updated_at?: string;
|
|
152
|
+
finished_at?: string | number;
|
|
153
|
+
model_urls?: {
|
|
154
|
+
glb?: string;
|
|
155
|
+
fbx?: string;
|
|
156
|
+
usdz?: string;
|
|
157
|
+
obj?: string;
|
|
158
|
+
mtl?: string;
|
|
159
|
+
blend?: string;
|
|
160
|
+
stl?: string;
|
|
161
|
+
"3mf"?: string;
|
|
162
|
+
};
|
|
163
|
+
thumbnail_url?: string;
|
|
164
|
+
texture_urls?: TextureUrlsObject[] | TextureUrlsObject;
|
|
165
|
+
video_url?: string;
|
|
166
|
+
vertex_count?: number;
|
|
167
|
+
face_count?: number;
|
|
168
|
+
aabb?: {
|
|
169
|
+
min: [number, number, number];
|
|
170
|
+
max: [number, number, number];
|
|
171
|
+
};
|
|
172
|
+
prompt?: string;
|
|
173
|
+
preceding_tasks?: number;
|
|
174
|
+
task_error?: TaskError;
|
|
175
|
+
is_published?: boolean;
|
|
176
|
+
result?: {
|
|
177
|
+
rigged_character_glb_url?: string;
|
|
178
|
+
rigged_character_fbx_url?: string;
|
|
179
|
+
basic_animations?: {
|
|
180
|
+
walking_glb_url?: string;
|
|
181
|
+
walking_fbx_url?: string;
|
|
182
|
+
walking_armature_glb_url?: string;
|
|
183
|
+
running_glb_url?: string;
|
|
184
|
+
running_fbx_url?: string;
|
|
185
|
+
running_armature_glb_url?: string;
|
|
186
|
+
};
|
|
187
|
+
animation_glb_url?: string;
|
|
188
|
+
animation_fbx_url?: string;
|
|
189
|
+
processed_usdz_url?: string;
|
|
190
|
+
processed_armature_fbx_url?: string;
|
|
191
|
+
processed_animation_fps_fbx_url?: string;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export interface TextTo3DArgs {
|
|
195
|
+
prompt: string;
|
|
196
|
+
ai_model: AIModel;
|
|
197
|
+
model_type?: ModelType;
|
|
198
|
+
topology?: Topology;
|
|
199
|
+
target_polycount?: number;
|
|
200
|
+
symmetry_mode?: SymmetryMode;
|
|
201
|
+
should_remesh?: boolean;
|
|
202
|
+
pose_mode?: PoseMode;
|
|
203
|
+
}
|
|
204
|
+
export interface ImageTo3DArgs {
|
|
205
|
+
image_url: string;
|
|
206
|
+
ai_model?: AIModel;
|
|
207
|
+
model_type?: ModelType;
|
|
208
|
+
pose_mode?: PoseMode;
|
|
209
|
+
enable_pbr: boolean;
|
|
210
|
+
topology?: Topology;
|
|
211
|
+
target_polycount?: number;
|
|
212
|
+
should_remesh?: boolean;
|
|
213
|
+
symmetry_mode?: SymmetryMode;
|
|
214
|
+
should_texture?: boolean;
|
|
215
|
+
texture_prompt?: string;
|
|
216
|
+
texture_image_url?: string;
|
|
217
|
+
image_enhancement?: boolean;
|
|
218
|
+
remove_lighting?: boolean;
|
|
219
|
+
save_pre_remeshed_model?: boolean;
|
|
220
|
+
}
|
|
221
|
+
export interface CreateTaskRequest {
|
|
222
|
+
mode: string;
|
|
223
|
+
args: TextTo3DArgs | ImageTo3DArgs;
|
|
224
|
+
}
|
|
225
|
+
export interface CreateTaskResponse {
|
|
226
|
+
id: string;
|
|
227
|
+
status: TaskStatus;
|
|
228
|
+
created_at: string;
|
|
229
|
+
}
|
|
230
|
+
export interface GetTaskResponse extends Task {
|
|
231
|
+
}
|
|
232
|
+
export interface ListTasksResponse {
|
|
233
|
+
tasks: Task[];
|
|
234
|
+
total: number;
|
|
235
|
+
limit: number;
|
|
236
|
+
offset: number;
|
|
237
|
+
}
|
|
238
|
+
export interface PaginationParams {
|
|
239
|
+
limit: number;
|
|
240
|
+
offset: number;
|
|
241
|
+
}
|
|
242
|
+
export interface BalanceResponse {
|
|
243
|
+
balance: number;
|
|
244
|
+
}
|
|
245
|
+
export interface PaginatedResponse<T> {
|
|
246
|
+
total: number;
|
|
247
|
+
count: number;
|
|
248
|
+
offset: number;
|
|
249
|
+
items: T[];
|
|
250
|
+
has_more: boolean;
|
|
251
|
+
next_offset?: number;
|
|
252
|
+
}
|
|
253
|
+
export interface ModelSummary {
|
|
254
|
+
id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
thumbnail_url: string;
|
|
257
|
+
created_at: string | number;
|
|
258
|
+
vertex_count?: number;
|
|
259
|
+
face_count?: number;
|
|
260
|
+
is_published: boolean;
|
|
261
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared task endpoint mapping
|
|
3
|
+
*/
|
|
4
|
+
import { TaskType } from "../constants.js";
|
|
5
|
+
/**
|
|
6
|
+
* All endpoint base paths in priority order for auto-inference
|
|
7
|
+
*/
|
|
8
|
+
export declare const ALL_TASK_ENDPOINTS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Task types that have list endpoints (excludes rigging and animation which have no list API)
|
|
11
|
+
*/
|
|
12
|
+
export declare const LIST_CAPABLE_TASK_TYPES: TaskType[];
|
|
13
|
+
/**
|
|
14
|
+
* Map task type to its API endpoint base path
|
|
15
|
+
*/
|
|
16
|
+
export declare function getTaskEndpoint(taskType: TaskType): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared task endpoint mapping
|
|
3
|
+
*/
|
|
4
|
+
import { TaskType } from "../constants.js";
|
|
5
|
+
const TASK_ENDPOINTS = {
|
|
6
|
+
[TaskType.TEXT_TO_3D]: "/openapi/v2/text-to-3d",
|
|
7
|
+
[TaskType.IMAGE_TO_3D]: "/openapi/v1/image-to-3d",
|
|
8
|
+
[TaskType.MULTI_IMAGE_TO_3D]: "/openapi/v1/multi-image-to-3d",
|
|
9
|
+
[TaskType.REMESH]: "/openapi/v1/remesh",
|
|
10
|
+
[TaskType.RETEXTURE]: "/openapi/v1/retexture",
|
|
11
|
+
[TaskType.RIGGING]: "/openapi/v1/rigging",
|
|
12
|
+
[TaskType.ANIMATION]: "/openapi/v1/animations",
|
|
13
|
+
[TaskType.TEXT_TO_IMAGE]: "/openapi/v1/text-to-image",
|
|
14
|
+
[TaskType.IMAGE_TO_IMAGE]: "/openapi/v1/image-to-image",
|
|
15
|
+
[TaskType.MULTI_COLOR_PRINT]: "/openapi/v1/print/multi-color"
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* All endpoint base paths in priority order for auto-inference
|
|
19
|
+
*/
|
|
20
|
+
export const ALL_TASK_ENDPOINTS = Object.values(TASK_ENDPOINTS);
|
|
21
|
+
/**
|
|
22
|
+
* Task types that have list endpoints (excludes rigging and animation which have no list API)
|
|
23
|
+
*/
|
|
24
|
+
export const LIST_CAPABLE_TASK_TYPES = [
|
|
25
|
+
TaskType.TEXT_TO_3D,
|
|
26
|
+
TaskType.IMAGE_TO_3D,
|
|
27
|
+
TaskType.MULTI_IMAGE_TO_3D,
|
|
28
|
+
TaskType.REMESH,
|
|
29
|
+
TaskType.RETEXTURE,
|
|
30
|
+
TaskType.TEXT_TO_IMAGE,
|
|
31
|
+
TaskType.IMAGE_TO_IMAGE
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Map task type to its API endpoint base path
|
|
35
|
+
*/
|
|
36
|
+
export function getTaskEndpoint(taskType) {
|
|
37
|
+
return TASK_ENDPOINTS[taskType];
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API request body builder.
|
|
3
|
+
* Constructs a request object from required fields and optional parameters,
|
|
4
|
+
* omitting undefined values automatically.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Build an API request body by merging required fields with optional parameters.
|
|
8
|
+
* Undefined values in optionalParams are automatically excluded.
|
|
9
|
+
*
|
|
10
|
+
* @param requiredFields - Fields that are always included in the request
|
|
11
|
+
* @param optionalParams - Fields that are included only if defined
|
|
12
|
+
* @param excludeKeys - Keys to exclude from optionalParams (e.g., "response_format")
|
|
13
|
+
* @returns A flat record suitable for passing to client.post()
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildApiRequest(requiredFields: Record<string, unknown>, optionalParams: Record<string, unknown>, excludeKeys?: string[]): Record<string, unknown>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API request body builder.
|
|
3
|
+
* Constructs a request object from required fields and optional parameters,
|
|
4
|
+
* omitting undefined values automatically.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Build an API request body by merging required fields with optional parameters.
|
|
8
|
+
* Undefined values in optionalParams are automatically excluded.
|
|
9
|
+
*
|
|
10
|
+
* @param requiredFields - Fields that are always included in the request
|
|
11
|
+
* @param optionalParams - Fields that are included only if defined
|
|
12
|
+
* @param excludeKeys - Keys to exclude from optionalParams (e.g., "response_format")
|
|
13
|
+
* @returns A flat record suitable for passing to client.post()
|
|
14
|
+
*/
|
|
15
|
+
export function buildApiRequest(requiredFields, optionalParams, excludeKeys = ["response_format"]) {
|
|
16
|
+
const request = { ...requiredFields };
|
|
17
|
+
const excludeSet = new Set(excludeKeys);
|
|
18
|
+
for (const [key, value] of Object.entries(optionalParams)) {
|
|
19
|
+
if (value !== undefined && !excludeSet.has(key)) {
|
|
20
|
+
request[key] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return request;
|
|
24
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared response formatting for task creation tools.
|
|
3
|
+
*/
|
|
4
|
+
import { ResponseFormat } from "../constants.js";
|
|
5
|
+
export interface TaskCreatedOutput {
|
|
6
|
+
[x: string]: unknown;
|
|
7
|
+
task_id: string;
|
|
8
|
+
status: string;
|
|
9
|
+
message: string;
|
|
10
|
+
estimated_time: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Format a task creation response with consistent structure across all tools.
|
|
14
|
+
*
|
|
15
|
+
* @param output - Structured output data
|
|
16
|
+
* @param responseFormat - Desired response format (markdown or json)
|
|
17
|
+
* @param title - Markdown title (e.g., "3D Generation Task Created")
|
|
18
|
+
* @param body - Additional markdown body text (e.g., "Your 3D model is being generated...")
|
|
19
|
+
* @param nextStepHint - Optional hint for the task_type parameter in next steps
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatTaskCreatedResponse(output: TaskCreatedOutput, responseFormat: ResponseFormat, title: string, body: string, nextStepHint?: string): {
|
|
22
|
+
content: {
|
|
23
|
+
type: "text";
|
|
24
|
+
text: string;
|
|
25
|
+
}[];
|
|
26
|
+
structuredContent: TaskCreatedOutput;
|
|
27
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared response formatting for task creation tools.
|
|
3
|
+
*/
|
|
4
|
+
import { ResponseFormat } from "../constants.js";
|
|
5
|
+
/**
|
|
6
|
+
* Format a task creation response with consistent structure across all tools.
|
|
7
|
+
*
|
|
8
|
+
* @param output - Structured output data
|
|
9
|
+
* @param responseFormat - Desired response format (markdown or json)
|
|
10
|
+
* @param title - Markdown title (e.g., "3D Generation Task Created")
|
|
11
|
+
* @param body - Additional markdown body text (e.g., "Your 3D model is being generated...")
|
|
12
|
+
* @param nextStepHint - Optional hint for the task_type parameter in next steps
|
|
13
|
+
*/
|
|
14
|
+
export function formatTaskCreatedResponse(output, responseFormat, title, body, nextStepHint) {
|
|
15
|
+
let textContent;
|
|
16
|
+
if (responseFormat === ResponseFormat.MARKDOWN) {
|
|
17
|
+
const taskTypeParam = nextStepHint ? ` and task_type "${nextStepHint}"` : "";
|
|
18
|
+
textContent = `# ${title}
|
|
19
|
+
|
|
20
|
+
**Task ID**: ${output.task_id}
|
|
21
|
+
**Status**: ${output.status}
|
|
22
|
+
**Estimated Time**: ${output.estimated_time}
|
|
23
|
+
|
|
24
|
+
${body}
|
|
25
|
+
|
|
26
|
+
**Next Steps**:
|
|
27
|
+
1. **Recommended**: Use \`meshy_get_task_status\` with task_id "${output.task_id}"${taskTypeParam} to automatically wait for completion.
|
|
28
|
+
2. **Alternative**: Use \`meshy_get_task_status\` with wait=false to check once.`;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
textContent = JSON.stringify(output, null, 2);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: textContent }],
|
|
35
|
+
structuredContent: output
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform slicer detection utilities.
|
|
3
|
+
* Detects installed 3D printing slicer software and returns launch commands.
|
|
4
|
+
* Does NOT execute launches — returns commands for the agent to run.
|
|
5
|
+
*/
|
|
6
|
+
import { SlicerType } from "../constants.js";
|
|
7
|
+
export interface DetectedSlicer {
|
|
8
|
+
type: SlicerType;
|
|
9
|
+
displayName: string;
|
|
10
|
+
supportsMulticolor: boolean;
|
|
11
|
+
path: string;
|
|
12
|
+
launchCommand: string;
|
|
13
|
+
urlScheme?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Detect all installed slicer software on the current system.
|
|
17
|
+
* Returns an array sorted with multicolor-capable slicers first.
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectInstalledSlicers(): DetectedSlicer[];
|
|
20
|
+
/**
|
|
21
|
+
* Detect a specific slicer by type.
|
|
22
|
+
* Returns null if not installed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function detectSlicer(type: SlicerType): DetectedSlicer | null;
|
|
25
|
+
/**
|
|
26
|
+
* Get the best slicer for multicolor printing from a list of installed slicers.
|
|
27
|
+
* Returns null if no multicolor-capable slicer is installed.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getBestMulticolorSlicer(installed: DetectedSlicer[]): DetectedSlicer | null;
|