@spexly/mcp-server 1.0.2 → 1.1.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/dist/index.js +65 -44
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -33,30 +33,30 @@ const { apiKey: API_KEY, apiUrl: API_URL } = parseArgs();
|
|
|
33
33
|
// Import event types from centralized module
|
|
34
34
|
import { EVENT_TYPES } from './eventTypes.js';
|
|
35
35
|
const SPEXLY_DIR = path.join(os.homedir(), '.spexly');
|
|
36
|
-
const
|
|
37
|
-
function
|
|
36
|
+
const AGENTS_FILE = path.join(SPEXLY_DIR, 'agents.json');
|
|
37
|
+
function loadAgentMap() {
|
|
38
38
|
try {
|
|
39
|
-
if (!fs.existsSync(
|
|
39
|
+
if (!fs.existsSync(AGENTS_FILE))
|
|
40
40
|
return new Map();
|
|
41
|
-
return new Map(Object.entries(JSON.parse(fs.readFileSync(
|
|
41
|
+
return new Map(Object.entries(JSON.parse(fs.readFileSync(AGENTS_FILE, 'utf-8'))));
|
|
42
42
|
}
|
|
43
43
|
catch {
|
|
44
44
|
return new Map();
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
function
|
|
47
|
+
function saveAgent(id, agent) {
|
|
48
48
|
try {
|
|
49
49
|
fs.mkdirSync(SPEXLY_DIR, { recursive: true });
|
|
50
|
-
const data =
|
|
51
|
-
data.set(
|
|
52
|
-
fs.writeFileSync(
|
|
50
|
+
const data = loadAgentMap();
|
|
51
|
+
data.set(id, agent);
|
|
52
|
+
fs.writeFileSync(AGENTS_FILE, JSON.stringify(Object.fromEntries(data), null, 2));
|
|
53
53
|
}
|
|
54
54
|
catch (err) {
|
|
55
|
-
console.error('[WARN] Failed to save
|
|
55
|
+
console.error('[WARN] Failed to save agent:', err);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
return
|
|
58
|
+
function getAgent(id) {
|
|
59
|
+
return loadAgentMap().get(id);
|
|
60
60
|
}
|
|
61
61
|
// ============================================
|
|
62
62
|
// API Client
|
|
@@ -86,20 +86,23 @@ async function apiRequest(method, path, body) {
|
|
|
86
86
|
// ============================================
|
|
87
87
|
const server = new McpServer({
|
|
88
88
|
name: "spexly",
|
|
89
|
-
version: "1.
|
|
89
|
+
version: "1.1.0"
|
|
90
90
|
});
|
|
91
91
|
// Tool: register_agent
|
|
92
|
-
server.
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
server.registerTool("register_agent", {
|
|
93
|
+
description: "Register yourself as an agent with Spexly for status monitoring. " +
|
|
94
|
+
"CALL THIS ONCE at the start of a conversation. " +
|
|
95
|
+
"Use the same id for all calls in this conversation - it must be consistent. " +
|
|
96
|
+
"This is IDEMPOTENT - safe to call multiple times with the same id.",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
id: z.string().describe("Unique, consistent identifier for this agent (use the same value for all calls)"),
|
|
99
|
+
name: z.string().describe("Descriptive name for this agent (e.g., 'Implementing MCP Server')"),
|
|
100
|
+
workspace: z.string().optional().describe("Optional workspace name for grouping agents (immutable after registration)"),
|
|
101
|
+
parentId: z.string().optional().describe("Optional parent agent id for hierarchical agents")
|
|
102
|
+
}
|
|
103
|
+
}, async ({ id, name, workspace, parentId }) => {
|
|
101
104
|
// Check if already registered
|
|
102
|
-
const existing =
|
|
105
|
+
const existing = getAgent(id);
|
|
103
106
|
if (existing) {
|
|
104
107
|
return {
|
|
105
108
|
content: [{
|
|
@@ -113,17 +116,29 @@ server.tool("register_agent", "Register yourself as an agent with Spexly for sta
|
|
|
113
116
|
}]
|
|
114
117
|
};
|
|
115
118
|
}
|
|
119
|
+
// Resolve parentId through mapping if provided
|
|
120
|
+
let resolvedParentId = null;
|
|
121
|
+
if (parentId) {
|
|
122
|
+
const parentAgent = getAgent(parentId);
|
|
123
|
+
if (!parentAgent) {
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: `Error: Parent agent "${parentId}" not found. Register the parent first.` }],
|
|
126
|
+
isError: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
resolvedParentId = parentAgent.agentId;
|
|
130
|
+
}
|
|
116
131
|
// Register new agent
|
|
117
132
|
const result = await apiRequest("POST", "/agents/register", {
|
|
118
133
|
name,
|
|
119
134
|
workspace: workspace || null,
|
|
120
|
-
parentId:
|
|
135
|
+
parentId: resolvedParentId
|
|
121
136
|
});
|
|
122
137
|
if (!result.ok) {
|
|
123
138
|
return { content: [{ type: "text", text: `Error: ${result.error}` }], isError: true };
|
|
124
139
|
}
|
|
125
140
|
// Persist the mapping
|
|
126
|
-
|
|
141
|
+
saveAgent(id, {
|
|
127
142
|
agentId: result.data.id,
|
|
128
143
|
name: result.data.name,
|
|
129
144
|
workspace: result.data.workspace || null,
|
|
@@ -142,16 +157,19 @@ server.tool("register_agent", "Register yourself as an agent with Spexly for sta
|
|
|
142
157
|
};
|
|
143
158
|
});
|
|
144
159
|
// Tool: update_agent
|
|
145
|
-
server.
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
160
|
+
server.registerTool("update_agent", {
|
|
161
|
+
description: "Update the name of a registered agent. " +
|
|
162
|
+
"Use this to rename an agent if the context has changed. " +
|
|
163
|
+
"Use the same id as your register_agent call.",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
id: z.string().describe("Unique, consistent identifier for this agent (use the same value for all calls)"),
|
|
166
|
+
name: z.string().describe("New descriptive name for this agent")
|
|
167
|
+
}
|
|
168
|
+
}, async ({ id, name }) => {
|
|
169
|
+
const agent = getAgent(id);
|
|
152
170
|
if (!agent) {
|
|
153
171
|
return {
|
|
154
|
-
content: [{ type: "text", text: "Error: No agent registered
|
|
172
|
+
content: [{ type: "text", text: "Error: No agent registered with this id. Call register_agent first." }],
|
|
155
173
|
isError: true
|
|
156
174
|
};
|
|
157
175
|
}
|
|
@@ -160,7 +178,7 @@ server.tool("update_agent", "Update the name of a registered agent. " +
|
|
|
160
178
|
return { content: [{ type: "text", text: `Error: ${result.error}` }], isError: true };
|
|
161
179
|
}
|
|
162
180
|
// Update local cache
|
|
163
|
-
|
|
181
|
+
saveAgent(id, {
|
|
164
182
|
...agent,
|
|
165
183
|
name: result.data.name
|
|
166
184
|
});
|
|
@@ -177,16 +195,19 @@ server.tool("update_agent", "Update the name of a registered agent. " +
|
|
|
177
195
|
};
|
|
178
196
|
});
|
|
179
197
|
// Tool: report_event
|
|
180
|
-
server.
|
|
181
|
-
"
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
server.registerTool("report_event", {
|
|
199
|
+
description: "Report your current status to the Spexly monitoring dashboard. " +
|
|
200
|
+
"CALL THIS whenever your working state changes: " +
|
|
201
|
+
"task_start (beginning work), task_complete (finished), thinking (reasoning NOT working), " +
|
|
202
|
+
"error (problem), idle (waiting), blocked (stuck), needs_input (need clarification). " +
|
|
203
|
+
"Use the same id as your register_agent call.",
|
|
204
|
+
inputSchema: {
|
|
205
|
+
id: z.string().describe("Unique, consistent identifier for this agent (use the same value for all calls)"),
|
|
206
|
+
eventType: z.enum(EVENT_TYPES).describe("Your current state"),
|
|
207
|
+
message: z.string().optional().describe("Brief description of what you're doing")
|
|
208
|
+
}
|
|
209
|
+
}, async ({ id, eventType, message }) => {
|
|
210
|
+
const agent = getAgent(id);
|
|
190
211
|
if (!agent) {
|
|
191
212
|
return {
|
|
192
213
|
content: [{ type: "text", text: "Error: Not registered. Call register_agent first." }],
|
|
@@ -216,7 +237,7 @@ async function main() {
|
|
|
216
237
|
const transport = new StdioServerTransport();
|
|
217
238
|
await server.connect(transport);
|
|
218
239
|
console.error("Spexly MCP server running");
|
|
219
|
-
console.error(`
|
|
240
|
+
console.error(`Agents file: ${AGENTS_FILE}`);
|
|
220
241
|
}
|
|
221
242
|
main().catch((err) => {
|
|
222
243
|
console.error("Fatal error:", err);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spexly/mcp-server",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Spexly MCP Server - AI agent status monitoring via Model Context Protocol",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"spexly-mcp": "
|
|
7
|
+
"spexly-mcp": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
@@ -44,4 +44,4 @@
|
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=18.0.0"
|
|
46
46
|
}
|
|
47
|
-
}
|
|
47
|
+
}
|