apteva 0.4.8 → 0.4.10
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/auth/middleware.ts +1 -0
- package/src/mcp-platform.ts +499 -0
- package/src/routes/api/agent-utils.ts +13 -1
- package/src/routes/api/meta-agent.ts +16 -10
- package/src/routes/api.ts +6 -0
package/package.json
CHANGED
package/src/auth/middleware.ts
CHANGED
|
@@ -25,6 +25,7 @@ const PUBLIC_PATHS = [
|
|
|
25
25
|
"/api/features", // Feature flags needed before auth
|
|
26
26
|
"/api/telemetry", // Agents POST telemetry here
|
|
27
27
|
"/api/telemetry/stream", // SSE doesn't support auth headers
|
|
28
|
+
"/api/mcp/platform", // Built-in MCP server for agent communication
|
|
28
29
|
];
|
|
29
30
|
|
|
30
31
|
// Path prefixes that don't require authentication (for agent communication)
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
// Built-in MCP server that exposes the Apteva platform API as MCP tools
|
|
2
|
+
// This allows the meta agent (Apteva Assistant) to control the platform
|
|
3
|
+
|
|
4
|
+
import { AgentDB, ProjectDB, McpServerDB, TelemetryDB, generateId } from "./db";
|
|
5
|
+
import { getProvidersWithStatus, PROVIDERS } from "./providers";
|
|
6
|
+
import { startAgentProcess, setAgentStatus, toApiAgent, META_AGENT_ID, agentFetch } from "./routes/api/agent-utils";
|
|
7
|
+
import { agentProcesses } from "./server";
|
|
8
|
+
|
|
9
|
+
// MCP Protocol version
|
|
10
|
+
const PROTOCOL_VERSION = "2024-11-05";
|
|
11
|
+
|
|
12
|
+
interface JsonRpcRequest {
|
|
13
|
+
jsonrpc: "2.0";
|
|
14
|
+
id: number;
|
|
15
|
+
method: string;
|
|
16
|
+
params?: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface JsonRpcResponse {
|
|
20
|
+
jsonrpc: "2.0";
|
|
21
|
+
id: number;
|
|
22
|
+
result?: unknown;
|
|
23
|
+
error?: { code: number; message: string; data?: unknown };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Tool definitions
|
|
27
|
+
const PLATFORM_TOOLS = [
|
|
28
|
+
{
|
|
29
|
+
name: "list_agents",
|
|
30
|
+
description: "List all agents on the platform. Optionally filter by project ID.",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
project_id: { type: "string", description: "Filter by project ID (optional)" },
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "get_agent",
|
|
40
|
+
description: "Get detailed information about a specific agent by ID.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
agent_id: { type: "string", description: "The agent ID" },
|
|
45
|
+
},
|
|
46
|
+
required: ["agent_id"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "create_agent",
|
|
51
|
+
description: "Create a new AI agent. Requires a name, provider, and model. The provider must have an API key configured.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
name: { type: "string", description: "Agent name" },
|
|
56
|
+
provider: { type: "string", description: "LLM provider ID (e.g. anthropic, openai, groq, gemini, xai, together, fireworks, ollama)" },
|
|
57
|
+
model: { type: "string", description: "Model ID (e.g. claude-sonnet-4-5, gpt-4o, llama-3.3-70b-versatile)" },
|
|
58
|
+
system_prompt: { type: "string", description: "System prompt for the agent (optional)" },
|
|
59
|
+
project_id: { type: "string", description: "Project ID to assign the agent to (optional)" },
|
|
60
|
+
features: {
|
|
61
|
+
type: "object",
|
|
62
|
+
description: "Feature flags (optional). All default to false.",
|
|
63
|
+
properties: {
|
|
64
|
+
memory: { type: "boolean" },
|
|
65
|
+
tasks: { type: "boolean" },
|
|
66
|
+
vision: { type: "boolean" },
|
|
67
|
+
mcp: { type: "boolean" },
|
|
68
|
+
files: { type: "boolean" },
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
required: ["name", "provider", "model"],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "update_agent",
|
|
77
|
+
description: "Update an existing agent's configuration. Only provide fields you want to change.",
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
agent_id: { type: "string", description: "The agent ID to update" },
|
|
82
|
+
name: { type: "string", description: "New name" },
|
|
83
|
+
model: { type: "string", description: "New model ID" },
|
|
84
|
+
provider: { type: "string", description: "New provider ID" },
|
|
85
|
+
system_prompt: { type: "string", description: "New system prompt" },
|
|
86
|
+
project_id: { type: "string", description: "New project ID (or null to unassign)" },
|
|
87
|
+
features: { type: "object", description: "Feature flags to update" },
|
|
88
|
+
},
|
|
89
|
+
required: ["agent_id"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "delete_agent",
|
|
94
|
+
description: "Delete an agent. The agent must be stopped first.",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
agent_id: { type: "string", description: "The agent ID to delete" },
|
|
99
|
+
},
|
|
100
|
+
required: ["agent_id"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "start_agent",
|
|
105
|
+
description: "Start a stopped agent. The agent's provider must have an API key configured.",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
agent_id: { type: "string", description: "The agent ID to start" },
|
|
110
|
+
},
|
|
111
|
+
required: ["agent_id"],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "stop_agent",
|
|
116
|
+
description: "Stop a running agent.",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
properties: {
|
|
120
|
+
agent_id: { type: "string", description: "The agent ID to stop" },
|
|
121
|
+
},
|
|
122
|
+
required: ["agent_id"],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "list_projects",
|
|
127
|
+
description: "List all projects with their agent counts.",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "create_project",
|
|
135
|
+
description: "Create a new project for organizing agents.",
|
|
136
|
+
inputSchema: {
|
|
137
|
+
type: "object",
|
|
138
|
+
properties: {
|
|
139
|
+
name: { type: "string", description: "Project name" },
|
|
140
|
+
description: { type: "string", description: "Project description (optional)" },
|
|
141
|
+
color: { type: "string", description: "Hex color code (optional, default #6366f1)" },
|
|
142
|
+
},
|
|
143
|
+
required: ["name"],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "list_providers",
|
|
148
|
+
description: "List all available LLM providers and their configuration status (which have API keys).",
|
|
149
|
+
inputSchema: {
|
|
150
|
+
type: "object",
|
|
151
|
+
properties: {},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "list_mcp_servers",
|
|
156
|
+
description: "List all configured MCP servers (tool integrations).",
|
|
157
|
+
inputSchema: {
|
|
158
|
+
type: "object",
|
|
159
|
+
properties: {},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "get_dashboard_stats",
|
|
164
|
+
description: "Get platform overview stats: agent counts, task counts, provider counts.",
|
|
165
|
+
inputSchema: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: {},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "send_message",
|
|
172
|
+
description: "Send a chat message to a running agent and get the response.",
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: {
|
|
176
|
+
agent_id: { type: "string", description: "The agent ID to message" },
|
|
177
|
+
message: { type: "string", description: "The message to send" },
|
|
178
|
+
},
|
|
179
|
+
required: ["agent_id", "message"],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
// Tool execution handlers
|
|
185
|
+
async function executeTool(name: string, args: Record<string, any>): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
|
|
186
|
+
try {
|
|
187
|
+
switch (name) {
|
|
188
|
+
case "list_agents": {
|
|
189
|
+
const agents = args.project_id
|
|
190
|
+
? AgentDB.findByProject(args.project_id)
|
|
191
|
+
: AgentDB.findAll();
|
|
192
|
+
// Exclude meta agent from list
|
|
193
|
+
const filtered = agents.filter(a => a.id !== META_AGENT_ID);
|
|
194
|
+
const result = filtered.map(a => ({
|
|
195
|
+
id: a.id,
|
|
196
|
+
name: a.name,
|
|
197
|
+
provider: a.provider,
|
|
198
|
+
model: a.model,
|
|
199
|
+
status: a.status,
|
|
200
|
+
port: a.port,
|
|
201
|
+
projectId: a.project_id,
|
|
202
|
+
}));
|
|
203
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case "get_agent": {
|
|
207
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
208
|
+
if (!agent) {
|
|
209
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
210
|
+
}
|
|
211
|
+
return { content: [{ type: "text", text: JSON.stringify(toApiAgent(agent), null, 2) }] };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
case "create_agent": {
|
|
215
|
+
// Validate provider exists
|
|
216
|
+
const providerId = args.provider as keyof typeof PROVIDERS;
|
|
217
|
+
const provider = PROVIDERS[providerId];
|
|
218
|
+
if (!provider || provider.type !== "llm") {
|
|
219
|
+
return { content: [{ type: "text", text: `Invalid provider: ${args.provider}. Valid providers: ${Object.values(PROVIDERS).filter(p => p.type === "llm").map(p => p.id).join(", ")}` }], isError: true };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const id = generateId();
|
|
223
|
+
const agent = AgentDB.create({
|
|
224
|
+
id,
|
|
225
|
+
name: args.name,
|
|
226
|
+
model: args.model,
|
|
227
|
+
provider: args.provider,
|
|
228
|
+
system_prompt: args.system_prompt || `You are ${args.name}, a helpful AI assistant.`,
|
|
229
|
+
features: {
|
|
230
|
+
memory: args.features?.memory ?? false,
|
|
231
|
+
tasks: args.features?.tasks ?? false,
|
|
232
|
+
vision: args.features?.vision ?? false,
|
|
233
|
+
operator: false,
|
|
234
|
+
mcp: args.features?.mcp ?? false,
|
|
235
|
+
realtime: false,
|
|
236
|
+
files: args.features?.files ?? false,
|
|
237
|
+
agents: false,
|
|
238
|
+
},
|
|
239
|
+
mcp_servers: [],
|
|
240
|
+
skills: [],
|
|
241
|
+
project_id: args.project_id || null,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return { content: [{ type: "text", text: `Agent created successfully:\n${JSON.stringify({ id: agent.id, name: agent.name, provider: agent.provider, model: agent.model, port: agent.port }, null, 2)}` }] };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case "update_agent": {
|
|
248
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
249
|
+
if (!agent) {
|
|
250
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const updates: any = {};
|
|
254
|
+
if (args.name !== undefined) updates.name = args.name;
|
|
255
|
+
if (args.model !== undefined) updates.model = args.model;
|
|
256
|
+
if (args.provider !== undefined) updates.provider = args.provider;
|
|
257
|
+
if (args.system_prompt !== undefined) updates.system_prompt = args.system_prompt;
|
|
258
|
+
if (args.project_id !== undefined) updates.project_id = args.project_id;
|
|
259
|
+
if (args.features !== undefined) {
|
|
260
|
+
updates.features = { ...agent.features, ...args.features };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const updated = AgentDB.update(args.agent_id, updates);
|
|
264
|
+
return { content: [{ type: "text", text: `Agent updated: ${JSON.stringify({ id: updated?.id, name: updated?.name }, null, 2)}` }] };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
case "delete_agent": {
|
|
268
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
269
|
+
if (!agent) {
|
|
270
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
271
|
+
}
|
|
272
|
+
if (agent.status === "running") {
|
|
273
|
+
return { content: [{ type: "text", text: "Cannot delete a running agent. Stop it first." }], isError: true };
|
|
274
|
+
}
|
|
275
|
+
if (agent.id === META_AGENT_ID) {
|
|
276
|
+
return { content: [{ type: "text", text: "Cannot delete the Apteva Assistant." }], isError: true };
|
|
277
|
+
}
|
|
278
|
+
AgentDB.delete(args.agent_id);
|
|
279
|
+
return { content: [{ type: "text", text: `Agent deleted: ${agent.name} (${agent.id})` }] };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
case "start_agent": {
|
|
283
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
284
|
+
if (!agent) {
|
|
285
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
286
|
+
}
|
|
287
|
+
if (agent.status === "running") {
|
|
288
|
+
return { content: [{ type: "text", text: `Agent ${agent.name} is already running on port ${agent.port}` }] };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const result = await startAgentProcess(agent);
|
|
292
|
+
if (!result.success) {
|
|
293
|
+
return { content: [{ type: "text", text: `Failed to start agent: ${result.error}` }], isError: true };
|
|
294
|
+
}
|
|
295
|
+
return { content: [{ type: "text", text: `Agent ${agent.name} started on port ${result.port}` }] };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
case "stop_agent": {
|
|
299
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
300
|
+
if (!agent) {
|
|
301
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
302
|
+
}
|
|
303
|
+
if (agent.status === "stopped") {
|
|
304
|
+
return { content: [{ type: "text", text: `Agent ${agent.name} is already stopped` }] };
|
|
305
|
+
}
|
|
306
|
+
if (agent.id === META_AGENT_ID) {
|
|
307
|
+
return { content: [{ type: "text", text: "Cannot stop yourself (the Apteva Assistant)." }], isError: true };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const proc = agentProcesses.get(args.agent_id);
|
|
311
|
+
if (proc) {
|
|
312
|
+
proc.proc.kill();
|
|
313
|
+
agentProcesses.delete(args.agent_id);
|
|
314
|
+
}
|
|
315
|
+
setAgentStatus(args.agent_id, "stopped", "meta_agent");
|
|
316
|
+
return { content: [{ type: "text", text: `Agent ${agent.name} stopped` }] };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
case "list_projects": {
|
|
320
|
+
const projects = ProjectDB.findAll();
|
|
321
|
+
const agentCounts = ProjectDB.getAgentCounts();
|
|
322
|
+
const result = projects.map(p => ({
|
|
323
|
+
id: p.id,
|
|
324
|
+
name: p.name,
|
|
325
|
+
description: p.description,
|
|
326
|
+
color: p.color,
|
|
327
|
+
agentCount: agentCounts.get(p.id) || 0,
|
|
328
|
+
}));
|
|
329
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
case "create_project": {
|
|
333
|
+
const project = ProjectDB.create({
|
|
334
|
+
name: args.name,
|
|
335
|
+
description: args.description || null,
|
|
336
|
+
color: args.color,
|
|
337
|
+
});
|
|
338
|
+
return { content: [{ type: "text", text: `Project created: ${JSON.stringify({ id: project.id, name: project.name, color: project.color }, null, 2)}` }] };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
case "list_providers": {
|
|
342
|
+
const providers = getProvidersWithStatus();
|
|
343
|
+
const llmProviders = providers.filter(p => p.type === "llm");
|
|
344
|
+
const result = llmProviders.map(p => ({
|
|
345
|
+
id: p.id,
|
|
346
|
+
name: p.name,
|
|
347
|
+
hasKey: p.hasKey,
|
|
348
|
+
models: p.models,
|
|
349
|
+
}));
|
|
350
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
case "list_mcp_servers": {
|
|
354
|
+
const servers = McpServerDB.findAll();
|
|
355
|
+
const result = servers.map(s => ({
|
|
356
|
+
id: s.id,
|
|
357
|
+
name: s.name,
|
|
358
|
+
type: s.type,
|
|
359
|
+
status: s.status,
|
|
360
|
+
url: s.url,
|
|
361
|
+
}));
|
|
362
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
case "get_dashboard_stats": {
|
|
366
|
+
const agentCount = AgentDB.count();
|
|
367
|
+
const runningCount = AgentDB.countRunning();
|
|
368
|
+
const projectCount = ProjectDB.count();
|
|
369
|
+
const providers = getProvidersWithStatus().filter(p => p.type === "llm");
|
|
370
|
+
const configuredProviders = providers.filter(p => p.hasKey).length;
|
|
371
|
+
const mcpServers = McpServerDB.findAll().length;
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
content: [{
|
|
375
|
+
type: "text",
|
|
376
|
+
text: JSON.stringify({
|
|
377
|
+
agents: { total: agentCount - 1, running: runningCount }, // -1 for meta agent
|
|
378
|
+
projects: projectCount,
|
|
379
|
+
providers: { total: providers.length, configured: configuredProviders },
|
|
380
|
+
mcpServers,
|
|
381
|
+
}, null, 2),
|
|
382
|
+
}],
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
case "send_message": {
|
|
387
|
+
const agent = AgentDB.findById(args.agent_id);
|
|
388
|
+
if (!agent) {
|
|
389
|
+
return { content: [{ type: "text", text: `Agent not found: ${args.agent_id}` }], isError: true };
|
|
390
|
+
}
|
|
391
|
+
if (agent.status !== "running" || !agent.port) {
|
|
392
|
+
return { content: [{ type: "text", text: `Agent ${agent.name} is not running` }], isError: true };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
const res = await agentFetch(args.agent_id, agent.port, "/chat", {
|
|
397
|
+
method: "POST",
|
|
398
|
+
headers: { "Content-Type": "application/json" },
|
|
399
|
+
body: JSON.stringify({ message: args.message }),
|
|
400
|
+
signal: AbortSignal.timeout(60000),
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
if (!res.ok) {
|
|
404
|
+
const err = await res.text().catch(() => "Unknown error");
|
|
405
|
+
return { content: [{ type: "text", text: `Agent responded with error: ${err}` }], isError: true };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const data = await res.json();
|
|
409
|
+
const reply = data.response || data.message || JSON.stringify(data);
|
|
410
|
+
return { content: [{ type: "text", text: reply }] };
|
|
411
|
+
} catch (err) {
|
|
412
|
+
return { content: [{ type: "text", text: `Failed to communicate with agent: ${err}` }], isError: true };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
default:
|
|
417
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
418
|
+
}
|
|
419
|
+
} catch (err) {
|
|
420
|
+
return { content: [{ type: "text", text: `Tool execution error: ${err}` }], isError: true };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Main MCP request handler
|
|
425
|
+
export async function handlePlatformMcpRequest(req: Request): Promise<Response> {
|
|
426
|
+
const corsHeaders = {
|
|
427
|
+
"Access-Control-Allow-Origin": "*",
|
|
428
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
429
|
+
"Access-Control-Allow-Headers": "Content-Type, Mcp-Session-Id",
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
if (req.method === "OPTIONS") {
|
|
433
|
+
return new Response(null, { headers: corsHeaders });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let body: JsonRpcRequest;
|
|
437
|
+
try {
|
|
438
|
+
body = await req.json() as JsonRpcRequest;
|
|
439
|
+
} catch {
|
|
440
|
+
return new Response(JSON.stringify({
|
|
441
|
+
jsonrpc: "2.0",
|
|
442
|
+
id: 0,
|
|
443
|
+
error: { code: -32700, message: "Parse error" },
|
|
444
|
+
}), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const { method, params, id } = body;
|
|
448
|
+
|
|
449
|
+
let result: unknown;
|
|
450
|
+
let error: { code: number; message: string } | undefined;
|
|
451
|
+
|
|
452
|
+
switch (method) {
|
|
453
|
+
case "initialize": {
|
|
454
|
+
result = {
|
|
455
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
456
|
+
capabilities: {
|
|
457
|
+
tools: { listChanged: false },
|
|
458
|
+
},
|
|
459
|
+
serverInfo: {
|
|
460
|
+
name: "apteva-platform",
|
|
461
|
+
version: "1.0.0",
|
|
462
|
+
},
|
|
463
|
+
instructions: "This MCP server provides tools to control the Apteva AI agent platform. You can create, start, stop, and manage agents, projects, and view system status.",
|
|
464
|
+
};
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
case "notifications/initialized": {
|
|
469
|
+
// Acknowledgement - no response needed for notifications, but since this is HTTP we return ok
|
|
470
|
+
result = {};
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
case "tools/list": {
|
|
475
|
+
result = { tools: PLATFORM_TOOLS };
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
case "tools/call": {
|
|
480
|
+
const { name, arguments: args } = params as { name: string; arguments: Record<string, any> };
|
|
481
|
+
result = await executeTool(name, args || {});
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
default: {
|
|
486
|
+
error = { code: -32601, message: `Method not found: ${method}` };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const response: JsonRpcResponse = {
|
|
491
|
+
jsonrpc: "2.0",
|
|
492
|
+
id: id || 0,
|
|
493
|
+
...(error ? { error } : { result }),
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
return new Response(JSON.stringify(response), {
|
|
497
|
+
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
|
498
|
+
});
|
|
499
|
+
}
|
|
@@ -147,6 +147,18 @@ export function buildAgentConfig(agent: Agent, providerKey: string) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// Auto-inject built-in platform MCP server for meta agent
|
|
151
|
+
if (agent.id === META_AGENT_ID) {
|
|
152
|
+
const baseUrl = `http://localhost:${process.env.PORT || 4280}`;
|
|
153
|
+
mcpServers.push({
|
|
154
|
+
name: "Apteva Platform",
|
|
155
|
+
type: "http",
|
|
156
|
+
url: `${baseUrl}/api/mcp/platform`,
|
|
157
|
+
headers: {},
|
|
158
|
+
enabled: true,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
150
162
|
return {
|
|
151
163
|
id: agent.id,
|
|
152
164
|
name: agent.name,
|
|
@@ -215,7 +227,7 @@ export function buildAgentConfig(agent: Agent, providerKey: string) {
|
|
|
215
227
|
max_actions_per_turn: 5,
|
|
216
228
|
},
|
|
217
229
|
mcp: {
|
|
218
|
-
enabled: features.mcp,
|
|
230
|
+
enabled: features.mcp || agent.id === META_AGENT_ID,
|
|
219
231
|
base_url: "http://localhost:3000/mcp",
|
|
220
232
|
timeout: "30s",
|
|
221
233
|
retry_count: 3,
|
|
@@ -47,23 +47,29 @@ export async function handleMetaAgentRoutes(
|
|
|
47
47
|
name: "Apteva Assistant",
|
|
48
48
|
model: defaultModel,
|
|
49
49
|
provider: providerId,
|
|
50
|
-
system_prompt: `You are the Apteva Assistant,
|
|
50
|
+
system_prompt: `You are the Apteva Assistant, an AI that manages the Apteva agent platform.
|
|
51
51
|
|
|
52
|
-
You
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
- Troubleshooting common issues
|
|
52
|
+
You have tools to control the platform directly:
|
|
53
|
+
- Create, configure, start, and stop AI agents
|
|
54
|
+
- Manage projects and organize agents into them
|
|
55
|
+
- View system status, configured providers, and MCP servers
|
|
56
|
+
- Send messages to other running agents
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
Use your tools proactively when users ask you to do things. For example:
|
|
59
|
+
- "Create a GPT agent" → use create_agent with provider "openai" and model "gpt-4o"
|
|
60
|
+
- "Start my agent" → use start_agent
|
|
61
|
+
- "How many agents do I have?" → use get_dashboard_stats or list_agents
|
|
62
|
+
|
|
63
|
+
Available providers: anthropic (Claude), openai (GPT), groq (Llama), gemini (Gemini), xai (Grok), together, fireworks, ollama (local).
|
|
64
|
+
Use list_providers to see which have API keys configured.
|
|
65
|
+
|
|
66
|
+
Be concise and action-oriented. Confirm what you did after taking actions. Use markdown formatting.`,
|
|
61
67
|
features: {
|
|
62
68
|
memory: false,
|
|
63
69
|
tasks: false,
|
|
64
70
|
vision: false,
|
|
65
71
|
operator: false,
|
|
66
|
-
mcp:
|
|
72
|
+
mcp: true,
|
|
67
73
|
realtime: false,
|
|
68
74
|
files: false,
|
|
69
75
|
agents: false,
|
package/src/routes/api.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { handleSkillRoutes } from "./api/skills";
|
|
|
10
10
|
import { handleIntegrationRoutes } from "./api/integrations";
|
|
11
11
|
import { handleMetaAgentRoutes } from "./api/meta-agent";
|
|
12
12
|
import { handleTelemetryRoutes } from "./api/telemetry";
|
|
13
|
+
import { handlePlatformMcpRequest } from "../mcp-platform";
|
|
13
14
|
|
|
14
15
|
// Re-export for backward compatibility (server.ts dynamic import)
|
|
15
16
|
export { startAgentProcess } from "./api/agent-utils";
|
|
@@ -21,6 +22,11 @@ export async function handleApiRequest(
|
|
|
21
22
|
): Promise<Response> {
|
|
22
23
|
const method = req.method;
|
|
23
24
|
|
|
25
|
+
// Built-in platform MCP server (for meta agent)
|
|
26
|
+
if (path === "/api/mcp/platform" && method === "POST") {
|
|
27
|
+
return handlePlatformMcpRequest(req);
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
return (
|
|
25
31
|
(await handleSystemRoutes(req, path, method, authContext)) ??
|
|
26
32
|
(await handleProviderRoutes(req, path, method, authContext)) ??
|