@soldy_ai/mcp 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/client.d.ts +103 -0
- package/dist/client.js +165 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.d.ts +6 -0
- package/dist/files.js +49 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/brands.d.ts +3 -0
- package/dist/resources/brands.js +170 -0
- package/dist/resources/brands.js.map +1 -0
- package/dist/resources/materials.d.ts +3 -0
- package/dist/resources/materials.js +134 -0
- package/dist/resources/materials.js.map +1 -0
- package/dist/resources/messages.d.ts +3 -0
- package/dist/resources/messages.js +135 -0
- package/dist/resources/messages.js.map +1 -0
- package/dist/resources/projects.d.ts +3 -0
- package/dist/resources/projects.js +78 -0
- package/dist/resources/projects.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +171 -0
- package/dist/server.js.map +1 -0
- package/dist/subscriptions.d.ts +45 -0
- package/dist/subscriptions.js +275 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/tools/brand.d.ts +3 -0
- package/dist/tools/brand.js +141 -0
- package/dist/tools/brand.js.map +1 -0
- package/dist/tools/material.d.ts +2 -0
- package/dist/tools/material.js +23 -0
- package/dist/tools/material.js.map +1 -0
- package/dist/tools/message.d.ts +3 -0
- package/dist/tools/message.js +241 -0
- package/dist/tools/message.js.map +1 -0
- package/dist/tools/project.d.ts +3 -0
- package/dist/tools/project.js +240 -0
- package/dist/tools/project.js.map +1 -0
- package/dist/tools/subscribe.d.ts +12 -0
- package/dist/tools/subscribe.js +74 -0
- package/dist/tools/subscribe.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export function registerMaterialResources(server, client) {
|
|
3
|
+
server.resource("project-materials", new ResourceTemplate("soldy://project/{project_id}/materials", {
|
|
4
|
+
list: async () => {
|
|
5
|
+
try {
|
|
6
|
+
const projects = await client.listProjects();
|
|
7
|
+
return {
|
|
8
|
+
resources: projects.map((p) => ({
|
|
9
|
+
uri: `soldy://project/${p.id}/materials`,
|
|
10
|
+
name: `${p.name} — Materials`,
|
|
11
|
+
description: `Generated assets for ${p.name}`,
|
|
12
|
+
mimeType: "application/json",
|
|
13
|
+
})),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error("[resource:project-materials] list failed:", err);
|
|
18
|
+
return { resources: [] };
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
complete: {
|
|
22
|
+
project_id: async (value) => {
|
|
23
|
+
try {
|
|
24
|
+
const projects = await client.listProjects();
|
|
25
|
+
return projects
|
|
26
|
+
.filter((p) => p.id.startsWith(value))
|
|
27
|
+
.map((p) => p.id);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}), {
|
|
35
|
+
title: "Project Materials",
|
|
36
|
+
description: "All generated assets for a project",
|
|
37
|
+
mimeType: "application/json",
|
|
38
|
+
}, async (uri, { project_id }) => {
|
|
39
|
+
const id = Array.isArray(project_id) ? project_id[0] : project_id;
|
|
40
|
+
try {
|
|
41
|
+
const materials = await client.getMaterials(id);
|
|
42
|
+
return {
|
|
43
|
+
contents: [
|
|
44
|
+
{
|
|
45
|
+
uri: uri.href,
|
|
46
|
+
mimeType: "application/json",
|
|
47
|
+
text: JSON.stringify({ count: materials.length, materials }, null, 2),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
contents: [
|
|
55
|
+
{
|
|
56
|
+
uri: uri.href,
|
|
57
|
+
mimeType: "application/json",
|
|
58
|
+
text: JSON.stringify({
|
|
59
|
+
error: err instanceof Error ? err.message : "Failed to fetch",
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
server.resource("run-materials", new ResourceTemplate("soldy://project/{project_id}/runs/{run_id}/materials", {
|
|
67
|
+
list: undefined,
|
|
68
|
+
complete: {
|
|
69
|
+
project_id: async (value) => {
|
|
70
|
+
try {
|
|
71
|
+
const projects = await client.listProjects();
|
|
72
|
+
return projects
|
|
73
|
+
.filter((p) => p.id.startsWith(value))
|
|
74
|
+
.map((p) => p.id);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
run_id: async (value, context) => {
|
|
81
|
+
try {
|
|
82
|
+
const projectId = context?.arguments?.project_id;
|
|
83
|
+
if (!projectId)
|
|
84
|
+
return [];
|
|
85
|
+
const groups = await client.getMaterialsGrouped(projectId);
|
|
86
|
+
return groups
|
|
87
|
+
.map((g) => g.run_id)
|
|
88
|
+
.filter((r) => Boolean(r) && r.startsWith(value));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
}), {
|
|
96
|
+
title: "Run Materials",
|
|
97
|
+
description: "Generated assets for a specific agent run. Use project-level materials to discover run_ids first.",
|
|
98
|
+
mimeType: "application/json",
|
|
99
|
+
}, async (uri, { project_id, run_id }) => {
|
|
100
|
+
const pid = Array.isArray(project_id) ? project_id[0] : project_id;
|
|
101
|
+
const rid = Array.isArray(run_id) ? run_id[0] : run_id;
|
|
102
|
+
try {
|
|
103
|
+
const groups = await client.getMaterialsGrouped(pid);
|
|
104
|
+
const match = groups.find((g) => g.run_id === rid);
|
|
105
|
+
return {
|
|
106
|
+
contents: [
|
|
107
|
+
{
|
|
108
|
+
uri: uri.href,
|
|
109
|
+
mimeType: "application/json",
|
|
110
|
+
text: JSON.stringify({
|
|
111
|
+
run_id: rid,
|
|
112
|
+
count: match?.materials.length ?? 0,
|
|
113
|
+
materials: match?.materials ?? [],
|
|
114
|
+
}, null, 2),
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
return {
|
|
121
|
+
contents: [
|
|
122
|
+
{
|
|
123
|
+
uri: uri.href,
|
|
124
|
+
mimeType: "application/json",
|
|
125
|
+
text: JSON.stringify({
|
|
126
|
+
error: err instanceof Error ? err.message : "Failed to fetch",
|
|
127
|
+
}),
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=materials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materials.js","sourceRoot":"","sources":["../../src/resources/materials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export function registerMessageResources(server, client) {
|
|
3
|
+
server.resource("project-messages", new ResourceTemplate("soldy://project/{project_id}/messages", {
|
|
4
|
+
list: async () => {
|
|
5
|
+
try {
|
|
6
|
+
const projects = await client.listProjects();
|
|
7
|
+
return {
|
|
8
|
+
resources: projects.map((p) => ({
|
|
9
|
+
uri: `soldy://project/${p.id}/messages`,
|
|
10
|
+
name: `${p.name} — Messages`,
|
|
11
|
+
description: `Conversation history for ${p.name}`,
|
|
12
|
+
mimeType: "application/json",
|
|
13
|
+
})),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error("[resource:project-messages] list failed:", err);
|
|
18
|
+
return { resources: [] };
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
complete: {
|
|
22
|
+
project_id: async (value) => {
|
|
23
|
+
try {
|
|
24
|
+
const projects = await client.listProjects();
|
|
25
|
+
return projects
|
|
26
|
+
.filter((p) => p.id.startsWith(value))
|
|
27
|
+
.map((p) => p.id);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}), {
|
|
35
|
+
title: "Project Messages",
|
|
36
|
+
description: "Conversation history for a project",
|
|
37
|
+
mimeType: "application/json",
|
|
38
|
+
}, async (uri, { project_id }) => {
|
|
39
|
+
const id = Array.isArray(project_id) ? project_id[0] : project_id;
|
|
40
|
+
try {
|
|
41
|
+
const { messages, total } = await client.listMessages(id);
|
|
42
|
+
return {
|
|
43
|
+
contents: [
|
|
44
|
+
{
|
|
45
|
+
uri: uri.href,
|
|
46
|
+
mimeType: "application/json",
|
|
47
|
+
text: JSON.stringify({ total, messages }, null, 2),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
contents: [
|
|
55
|
+
{
|
|
56
|
+
uri: uri.href,
|
|
57
|
+
mimeType: "application/json",
|
|
58
|
+
text: JSON.stringify({
|
|
59
|
+
error: err instanceof Error ? err.message : "Failed to fetch",
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
server.resource("run-messages", new ResourceTemplate("soldy://project/{project_id}/runs/{run_id}/messages", {
|
|
67
|
+
list: undefined,
|
|
68
|
+
complete: {
|
|
69
|
+
project_id: async (value) => {
|
|
70
|
+
try {
|
|
71
|
+
const projects = await client.listProjects();
|
|
72
|
+
return projects
|
|
73
|
+
.filter((p) => p.id.startsWith(value))
|
|
74
|
+
.map((p) => p.id);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
run_id: async (value, context) => {
|
|
81
|
+
try {
|
|
82
|
+
const projectId = context?.arguments?.project_id;
|
|
83
|
+
if (!projectId)
|
|
84
|
+
return [];
|
|
85
|
+
const { messages } = await client.listMessages(projectId, 1, 100);
|
|
86
|
+
const runIds = [
|
|
87
|
+
...new Set(messages.map((m) => m.run_id).filter(Boolean)),
|
|
88
|
+
];
|
|
89
|
+
return runIds.filter((r) => r.startsWith(value));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
}), {
|
|
97
|
+
title: "Run Messages",
|
|
98
|
+
description: "Messages for a specific agent run. Use project-level messages to discover run_ids first.",
|
|
99
|
+
mimeType: "application/json",
|
|
100
|
+
}, async (uri, { project_id, run_id }) => {
|
|
101
|
+
const pid = Array.isArray(project_id) ? project_id[0] : project_id;
|
|
102
|
+
const rid = Array.isArray(run_id) ? run_id[0] : run_id;
|
|
103
|
+
try {
|
|
104
|
+
const { messages } = await client.listMessages(pid, 1, 200);
|
|
105
|
+
const runMessages = messages.filter((m) => m.run_id === rid);
|
|
106
|
+
return {
|
|
107
|
+
contents: [
|
|
108
|
+
{
|
|
109
|
+
uri: uri.href,
|
|
110
|
+
mimeType: "application/json",
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
run_id: rid,
|
|
113
|
+
count: runMessages.length,
|
|
114
|
+
messages: runMessages,
|
|
115
|
+
}, null, 2),
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
return {
|
|
122
|
+
contents: [
|
|
123
|
+
{
|
|
124
|
+
uri: uri.href,
|
|
125
|
+
mimeType: "application/json",
|
|
126
|
+
text: JSON.stringify({
|
|
127
|
+
error: err instanceof Error ? err.message : "Failed to fetch",
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/resources/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export function registerProjectResources(server, client) {
|
|
3
|
+
server.resource("project-status", new ResourceTemplate("soldy://project/{project_id}/status", {
|
|
4
|
+
list: async () => {
|
|
5
|
+
try {
|
|
6
|
+
const projects = await client.listProjects();
|
|
7
|
+
return {
|
|
8
|
+
resources: projects.map((p) => ({
|
|
9
|
+
uri: `soldy://project/${p.id}/status`,
|
|
10
|
+
name: `${p.name} — Status`,
|
|
11
|
+
description: `Status: ${p.status} | Ratio: ${p.ratio}`,
|
|
12
|
+
mimeType: "application/json",
|
|
13
|
+
})),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error("[resource:project-status] list failed:", err);
|
|
18
|
+
return { resources: [] };
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
complete: {
|
|
22
|
+
project_id: async (value) => {
|
|
23
|
+
try {
|
|
24
|
+
const projects = await client.listProjects();
|
|
25
|
+
return projects
|
|
26
|
+
.filter((p) => p.id.startsWith(value))
|
|
27
|
+
.map((p) => p.id);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}), {
|
|
35
|
+
title: "Project Status",
|
|
36
|
+
description: "Current status of a project",
|
|
37
|
+
mimeType: "application/json",
|
|
38
|
+
}, async (uri, { project_id }) => {
|
|
39
|
+
const id = Array.isArray(project_id) ? project_id[0] : project_id;
|
|
40
|
+
try {
|
|
41
|
+
const project = await client.getProject(id);
|
|
42
|
+
if (!project) {
|
|
43
|
+
return {
|
|
44
|
+
contents: [
|
|
45
|
+
{
|
|
46
|
+
uri: uri.href,
|
|
47
|
+
mimeType: "application/json",
|
|
48
|
+
text: JSON.stringify({ error: "Project not found" }),
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
contents: [
|
|
55
|
+
{
|
|
56
|
+
uri: uri.href,
|
|
57
|
+
mimeType: "application/json",
|
|
58
|
+
text: JSON.stringify(project, null, 2),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return {
|
|
65
|
+
contents: [
|
|
66
|
+
{
|
|
67
|
+
uri: uri.href,
|
|
68
|
+
mimeType: "application/json",
|
|
69
|
+
text: JSON.stringify({
|
|
70
|
+
error: err instanceof Error ? err.message : "Failed to fetch",
|
|
71
|
+
}),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/resources/projects.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { SoldyAPIClient } from "./client.js";
|
|
4
|
+
import { registerBrandResources } from "./resources/brands.js";
|
|
5
|
+
import { registerMaterialResources } from "./resources/materials.js";
|
|
6
|
+
import { registerMessageResources } from "./resources/messages.js";
|
|
7
|
+
import { registerProjectResources } from "./resources/projects.js";
|
|
8
|
+
import { extractBrandTaskId, extractProjectId, SubscriptionBridge, } from "./subscriptions.js";
|
|
9
|
+
import { registerBrandTools } from "./tools/brand.js";
|
|
10
|
+
import { registerMaterialTools } from "./tools/material.js";
|
|
11
|
+
import { registerMessageTools } from "./tools/message.js";
|
|
12
|
+
import { registerProjectTools } from "./tools/project.js";
|
|
13
|
+
import { registerSubscribeTools } from "./tools/subscribe.js";
|
|
14
|
+
export function createServer(apiUrl, apiKey) {
|
|
15
|
+
const server = new McpServer({ name: "Soldy AI", version: "0.1.0" }, {
|
|
16
|
+
capabilities: { tools: {}, prompts: {}, resources: { subscribe: true } },
|
|
17
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
18
|
+
});
|
|
19
|
+
const client = new SoldyAPIClient(apiUrl, apiKey);
|
|
20
|
+
const bridge = new SubscriptionBridge(client, apiUrl, apiKey);
|
|
21
|
+
// Tools
|
|
22
|
+
registerBrandTools(server, client);
|
|
23
|
+
registerProjectTools(server, client);
|
|
24
|
+
registerMessageTools(server, client);
|
|
25
|
+
registerMaterialTools(server, apiUrl);
|
|
26
|
+
registerSubscribeTools(server, bridge);
|
|
27
|
+
// Resources
|
|
28
|
+
registerBrandResources(server, client);
|
|
29
|
+
registerProjectResources(server, client);
|
|
30
|
+
registerMessageResources(server, client);
|
|
31
|
+
registerMaterialResources(server, client);
|
|
32
|
+
// Standard MCP resources/subscribe & resources/unsubscribe handlers.
|
|
33
|
+
// McpServer does not register these automatically — only list/read are
|
|
34
|
+
// wired up by the high-level API. We register on the low-level Server
|
|
35
|
+
// instance so clients can use the standard subscription protocol.
|
|
36
|
+
server.server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
37
|
+
const uri = request.params.uri;
|
|
38
|
+
const projectId = extractProjectId(uri);
|
|
39
|
+
if (projectId) {
|
|
40
|
+
await bridge.subscribeProject(projectId);
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
const taskId = extractBrandTaskId(uri);
|
|
44
|
+
if (taskId) {
|
|
45
|
+
bridge.subscribeBrandTask(taskId);
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
// For other resources (soldy://brands, etc.), acknowledge silently
|
|
49
|
+
return {};
|
|
50
|
+
});
|
|
51
|
+
server.server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
52
|
+
const uri = request.params.uri;
|
|
53
|
+
const projectId = extractProjectId(uri);
|
|
54
|
+
if (projectId) {
|
|
55
|
+
bridge.unsubscribeProject(projectId);
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
const taskId = extractBrandTaskId(uri);
|
|
59
|
+
if (taskId) {
|
|
60
|
+
bridge.unsubscribeBrandTask(taskId);
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
return {};
|
|
64
|
+
});
|
|
65
|
+
// Workflow prompt
|
|
66
|
+
server.prompt("soldy_workflow", "Recommended workflow for creating video ads with Soldy", () => ({
|
|
67
|
+
messages: [
|
|
68
|
+
{
|
|
69
|
+
role: "user",
|
|
70
|
+
content: {
|
|
71
|
+
type: "text",
|
|
72
|
+
text: WORKFLOW_PROMPT,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
}));
|
|
77
|
+
return { server, bridge };
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Server-level instructions — injected into the MCP server metadata so agents
|
|
81
|
+
// always see them, regardless of which tools they discover first.
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
const SERVER_INSTRUCTIONS = `# Soldy AI MCP Server
|
|
84
|
+
|
|
85
|
+
## Available Resources (read & subscribe)
|
|
86
|
+
|
|
87
|
+
This server exposes MCP resources you can read and subscribe to for real-time updates.
|
|
88
|
+
Use resources instead of polling tools whenever possible.
|
|
89
|
+
|
|
90
|
+
### Resource URI Scheme
|
|
91
|
+
|
|
92
|
+
| URI | Description | Subscribable |
|
|
93
|
+
|-----|-------------|:---:|
|
|
94
|
+
| \`soldy://brands\` | All brands in the workspace | ✓ |
|
|
95
|
+
| \`soldy://brand/{brand_id}\` | Single brand detail | ✓ |
|
|
96
|
+
| \`soldy://brand/task/{task_id}\` | Brand extraction task status | ✓ |
|
|
97
|
+
| \`soldy://project/{project_id}/status\` | Project status | ✓ |
|
|
98
|
+
| \`soldy://project/{project_id}/messages\` | Conversation history | ✓ |
|
|
99
|
+
| \`soldy://project/{project_id}/materials\` | Generated assets (videos, images, etc.) | ✓ |
|
|
100
|
+
| \`soldy://project/{project_id}/runs/{run_id}/messages\` | Messages for a specific agent run | ✓ |
|
|
101
|
+
| \`soldy://project/{project_id}/runs/{run_id}/materials\` | Materials for a specific agent run | ✓ |
|
|
102
|
+
|
|
103
|
+
### Subscription Pattern (preferred over polling)
|
|
104
|
+
|
|
105
|
+
Instead of calling get_project_status in a loop, subscribe for real-time push notifications:
|
|
106
|
+
|
|
107
|
+
1. Call \`watch_project(project_id)\` or \`watch_brand_task(task_id)\`
|
|
108
|
+
2. You will receive resource update notifications when data changes
|
|
109
|
+
3. Read the notified resource URI to get updated data
|
|
110
|
+
|
|
111
|
+
### Recommended Workflow
|
|
112
|
+
|
|
113
|
+
- **Brand extraction**: \`extract_brand\` → \`watch_brand_task\` → wait for notification → read \`soldy://brand/task/{task_id}\`
|
|
114
|
+
- **Video generation**: \`send_message\` → \`watch_project\` → wait for notifications → read \`soldy://project/{id}/status\` or \`soldy://project/{id}/materials\`
|
|
115
|
+
|
|
116
|
+
### Polling Fallback
|
|
117
|
+
|
|
118
|
+
If subscription is not available in your client, you can still use:
|
|
119
|
+
- \`get_project_status\` — check project status
|
|
120
|
+
- \`get_brand_task_result\` — check brand task status
|
|
121
|
+
- \`list_messages\` — get conversation history
|
|
122
|
+
- \`get_project_materials\` — get generated assets
|
|
123
|
+
`;
|
|
124
|
+
const WORKFLOW_PROMPT = `# Soldy Video Ad Workflow
|
|
125
|
+
|
|
126
|
+
## Quick Start (3 steps)
|
|
127
|
+
1. create_project → get project_id
|
|
128
|
+
2. send_message with your prompt + material_urls (product images/videos)
|
|
129
|
+
3. watch_project to subscribe → read resources when notified
|
|
130
|
+
|
|
131
|
+
## Full Workflow with Brand
|
|
132
|
+
|
|
133
|
+
### Step 1: Brand Setup (recommended for best results)
|
|
134
|
+
If the user provides a product URL or brand name:
|
|
135
|
+
- Use extract_brand with the product/brand URL to auto-extract brand identity
|
|
136
|
+
- Use watch_brand_task to subscribe for completion (preferred) or poll get_brand_task_result
|
|
137
|
+
- This gives the agent brand context (colors, tone, positioning)
|
|
138
|
+
|
|
139
|
+
If user already has brands: list_brands to find the right brand_id
|
|
140
|
+
|
|
141
|
+
### Step 2: Create Project
|
|
142
|
+
- create_project with a descriptive name
|
|
143
|
+
|
|
144
|
+
### Step 3: Send Message with Materials
|
|
145
|
+
- send_message with:
|
|
146
|
+
- content: describe what to generate
|
|
147
|
+
- ratio (required): "9:16" (TikTok/Reels/Shorts), "16:9" (YouTube), "1:1" (Instagram), "4:3", "3:4", "3:2", "2:3", "21:9" (ultra-wide)
|
|
148
|
+
- material_urls: product images, videos (local paths auto-uploaded)
|
|
149
|
+
- brand_id: the brand from step 1
|
|
150
|
+
|
|
151
|
+
### Step 4: Monitor Progress (prefer subscription over polling)
|
|
152
|
+
- **Preferred**: watch_project → wait for resource update notifications
|
|
153
|
+
- **Fallback**: get_project_status to poll status
|
|
154
|
+
- If status is "pause": agent needs credits or approval → use continue_project
|
|
155
|
+
- If status is "error": check the error, retry with send_message
|
|
156
|
+
- If status is "completed": proceed to step 5
|
|
157
|
+
|
|
158
|
+
### Step 5: Get Results
|
|
159
|
+
- Read resource: soldy://project/{id}/materials
|
|
160
|
+
- Or use tool: get_project_materials
|
|
161
|
+
|
|
162
|
+
### Step 6: Iterate
|
|
163
|
+
- send_message again to refine, change style, adjust duration, etc.
|
|
164
|
+
|
|
165
|
+
## Tips
|
|
166
|
+
- Always pass brand_id in send_message when a brand exists
|
|
167
|
+
- ratio is required in send_message — choose based on target platform
|
|
168
|
+
- Product URLs in text are NOT automatically extracted — use extract_brand explicitly
|
|
169
|
+
- Local file paths (./image.jpg, /path/to/video.mp4) are uploaded automatically
|
|
170
|
+
- Use watch_project / watch_brand_task for real-time updates instead of polling`;
|
|
171
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { SoldyAPIClient } from "./client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bridges WebSocket project subscriptions to MCP resource update notifications.
|
|
5
|
+
*
|
|
6
|
+
* When an MCP client subscribes to a resource URI (e.g. `soldy://project/{id}/status`),
|
|
7
|
+
* this bridge connects to the API WebSocket, subscribes to the project, and forwards
|
|
8
|
+
* relevant events as `sendResourceUpdated` notifications.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SubscriptionBridge {
|
|
11
|
+
private client;
|
|
12
|
+
private apiKey;
|
|
13
|
+
private ws;
|
|
14
|
+
private subscribedProjects;
|
|
15
|
+
private connecting;
|
|
16
|
+
private reconnectTimer;
|
|
17
|
+
private reconnectDelay;
|
|
18
|
+
private maxReconnectDelay;
|
|
19
|
+
private server;
|
|
20
|
+
/** Brand task polling: taskId → { interval, lastStatus } */
|
|
21
|
+
private brandTaskPolls;
|
|
22
|
+
private static readonly BRAND_TASK_POLL_MS;
|
|
23
|
+
constructor(client: SoldyAPIClient, _apiUrl: string, apiKey: string);
|
|
24
|
+
/** Attach the low-level MCP Server instance for sending notifications. */
|
|
25
|
+
setServer(server: Server): void;
|
|
26
|
+
/** Subscribe to a project's WebSocket events. Call when MCP client subscribes to a resource. */
|
|
27
|
+
subscribeProject(projectId: string): Promise<void>;
|
|
28
|
+
/** Unsubscribe from a project. Call when no more MCP subscriptions reference it. */
|
|
29
|
+
unsubscribeProject(projectId: string): void;
|
|
30
|
+
/** Subscribe to brand task status changes via polling. */
|
|
31
|
+
subscribeBrandTask(taskId: string): void;
|
|
32
|
+
/** Stop polling a brand task. */
|
|
33
|
+
unsubscribeBrandTask(taskId: string): void;
|
|
34
|
+
/** Disconnect the WebSocket and stop all polling. */
|
|
35
|
+
disconnect(): void;
|
|
36
|
+
private ensureConnected;
|
|
37
|
+
private connect;
|
|
38
|
+
private scheduleReconnect;
|
|
39
|
+
private sendProjectSubscribe;
|
|
40
|
+
private handleMessage;
|
|
41
|
+
}
|
|
42
|
+
/** Extract project_id from a soldy://project/... resource URI. */
|
|
43
|
+
export declare function extractProjectId(uri: string): string | null;
|
|
44
|
+
/** Extract task_id from a soldy://brand/task/... resource URI. */
|
|
45
|
+
export declare function extractBrandTaskId(uri: string): string | null;
|