@caelo-cms/mcp-server 0.10.21 → 0.10.23
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 +18 -8
- package/dist/admin-server.d.ts +6 -0
- package/dist/admin-server.d.ts.map +1 -0
- package/dist/admin-server.js +182 -0
- package/dist/admin-server.js.map +1 -0
- package/dist/admin.d.ts +3 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +20 -0
- package/dist/admin.js.map +1 -0
- package/dist/chat-bridge.d.ts +0 -10
- package/dist/chat-bridge.d.ts.map +1 -1
- package/dist/chat-bridge.js +23 -42
- package/dist/chat-bridge.js.map +1 -1
- package/dist/export.d.ts +23 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +93 -0
- package/dist/export.js.map +1 -0
- package/dist/http.d.ts +21 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +48 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +40 -10
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
# `@caelo-cms/mcp-server`
|
|
2
2
|
|
|
3
|
-
MCP
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
MCP servers for your Caelo CMS install. Two surfaces, selected by the
|
|
4
|
+
token's scope:
|
|
5
|
+
|
|
6
|
+
- **`caelo_chat`** (default mode, scope `chat`) — one tool that talks
|
|
7
|
+
to Caelo's own AI agent. You describe an outcome; Caelo's chat-runner
|
|
8
|
+
does the work.
|
|
9
|
+
- **Power-MCP** (`caelo-admin-mcp` binary / `caelo-mcp-server admin`,
|
|
10
|
+
scope `admin`) — the full chat-runner tool catalogue exposed
|
|
11
|
+
directly, so YOUR agent (Claude Code et al.) drives the tool loop and
|
|
12
|
+
Caelo makes no provider calls of its own. `caelo-mcp-server export`
|
|
13
|
+
additionally writes a CLAUDE.md + `.claude/skills/` tree generated
|
|
14
|
+
from the install's live context.
|
|
15
|
+
|
|
16
|
+
Every mode is a thin shim: calls become HTTPS POSTs against your admin
|
|
17
|
+
install's `/api/mcp/*` endpoints, which dispatch into the same
|
|
18
|
+
chat-runner machinery that powers the live-edit overlay. See the
|
|
19
|
+
[docs page](https://caelo-cms.com/mcp) for the full Power-MCP working
|
|
20
|
+
model (work sessions, preview branches, approval gates).
|
|
11
21
|
|
|
12
22
|
## Install
|
|
13
23
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-server.d.ts","sourceRoot":"","sources":["../src/admin-server.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAyED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAsI7E"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Issue #376 — the Power-MCP server (`caelo-admin-mcp` / `caelo-mcp-server
|
|
4
|
+
* admin`). Where the chat server exposes ONE tool that talks to Caelo's own
|
|
5
|
+
* AI, this server exposes the whole chat-runner tool catalogue so the
|
|
6
|
+
* CALLING agent (Claude Code et al.) drives the tool loop itself — no
|
|
7
|
+
* Caelo-side reasoning cost.
|
|
8
|
+
*
|
|
9
|
+
* The catalogue is fetched live from `/api/mcp/tools` at startup (an
|
|
10
|
+
* admin-scoped token is required; 'chat' tokens get a 401 with the fix).
|
|
11
|
+
* Two meta-tools are added locally:
|
|
12
|
+
*
|
|
13
|
+
* - `caelo_open_session` — opens (or resumes) the work session whose
|
|
14
|
+
* preview branch every subsequent tool call writes to. The session id
|
|
15
|
+
* is held here in process state so the agent doesn't thread it through
|
|
16
|
+
* every call; it also rides the response so a restarted server can
|
|
17
|
+
* resume via `chatSessionId`.
|
|
18
|
+
* - `caelo_get_context` — the composed site context (module model, tool
|
|
19
|
+
* playbook, staging rules, site memory, skills index) the agent should
|
|
20
|
+
* load once before working. For a checked-in variant, see
|
|
21
|
+
* `caelo-mcp-server export`.
|
|
22
|
+
*/
|
|
23
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
26
|
+
import { z } from "zod";
|
|
27
|
+
import { postAdmin, resolveTimeoutMs } from "./http.js";
|
|
28
|
+
const openSessionInput = z
|
|
29
|
+
.object({
|
|
30
|
+
title: z.string().min(1).max(200).optional(),
|
|
31
|
+
pageId: z.string().uuid().optional(),
|
|
32
|
+
chatSessionId: z.string().uuid().optional(),
|
|
33
|
+
})
|
|
34
|
+
.strict();
|
|
35
|
+
const OPEN_SESSION_TOOL = {
|
|
36
|
+
name: "caelo_open_session",
|
|
37
|
+
description: "Open (or resume) the Caelo work session your subsequent tool calls run in. Every write lands on the " +
|
|
38
|
+
"session's preview branch — invisible to the live site until the operator reviews and publishes in the " +
|
|
39
|
+
"Caelo admin. Call this ONCE before any other caelo tool; pass chatSessionId to resume an earlier " +
|
|
40
|
+
"session after a restart. Optional pageId binds the session to one page.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
title: { type: "string", description: "Session title shown in the Caelo admin chat list." },
|
|
45
|
+
pageId: { type: "string", description: "Optional page UUID to bind the session to." },
|
|
46
|
+
chatSessionId: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "Resume this existing session instead of creating a new one.",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const GET_CONTEXT_TOOL = {
|
|
54
|
+
name: "caelo_get_context",
|
|
55
|
+
description: "Fetch the Caelo install's composed site context: how pages/modules/content instances fit together, " +
|
|
56
|
+
"the tool playbook, staging rules, site memory (brand voice, glossary) and the active skills index. " +
|
|
57
|
+
"Load this once before working; load individual skills on demand via the load_skill tool.",
|
|
58
|
+
inputSchema: { type: "object", properties: {} },
|
|
59
|
+
};
|
|
60
|
+
export async function startAdminMcpServer(opts) {
|
|
61
|
+
// Fetch the live catalogue up front — a bad URL or a chat-scoped token
|
|
62
|
+
// should fail loudly at startup, not on the first tool call.
|
|
63
|
+
const catalogue = await postAdmin({
|
|
64
|
+
adminUrl: opts.adminUrl,
|
|
65
|
+
token: opts.token,
|
|
66
|
+
path: "/api/mcp/tools",
|
|
67
|
+
body: {},
|
|
68
|
+
timeoutMs: resolveTimeoutMs(60_000),
|
|
69
|
+
});
|
|
70
|
+
const remoteByName = new Map(catalogue.tools.map((t) => [t.name, t]));
|
|
71
|
+
let currentSession = null;
|
|
72
|
+
const server = new Server({ name: "caelo-admin-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
73
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
74
|
+
tools: [
|
|
75
|
+
OPEN_SESSION_TOOL,
|
|
76
|
+
GET_CONTEXT_TOOL,
|
|
77
|
+
...catalogue.tools.map((t) => ({
|
|
78
|
+
name: t.name,
|
|
79
|
+
description: t.description,
|
|
80
|
+
inputSchema: t.inputSchema,
|
|
81
|
+
})),
|
|
82
|
+
],
|
|
83
|
+
}));
|
|
84
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
85
|
+
const name = req.params.name;
|
|
86
|
+
try {
|
|
87
|
+
if (name === OPEN_SESSION_TOOL.name) {
|
|
88
|
+
const parsed = openSessionInput.safeParse(req.params.arguments ?? {});
|
|
89
|
+
if (!parsed.success) {
|
|
90
|
+
return errorResult(`invalid arguments: ${parsed.error.message}`);
|
|
91
|
+
}
|
|
92
|
+
currentSession = await postAdmin({
|
|
93
|
+
adminUrl: opts.adminUrl,
|
|
94
|
+
token: opts.token,
|
|
95
|
+
path: "/api/mcp/session",
|
|
96
|
+
body: parsed.data,
|
|
97
|
+
timeoutMs: resolveTimeoutMs(30_000),
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: JSON.stringify(currentSession, null, 2) +
|
|
104
|
+
"\nSession is active — subsequent caelo tool calls run on its preview branch. " +
|
|
105
|
+
"The operator reviews + publishes in the Caelo admin.",
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (name === GET_CONTEXT_TOOL.name) {
|
|
111
|
+
const context = await postAdmin({
|
|
112
|
+
adminUrl: opts.adminUrl,
|
|
113
|
+
token: opts.token,
|
|
114
|
+
path: "/api/mcp/context",
|
|
115
|
+
body: { includeSkillBodies: false },
|
|
116
|
+
timeoutMs: resolveTimeoutMs(60_000),
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{ type: "text", text: context.systemContext },
|
|
121
|
+
{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: JSON.stringify({ statusLine: context.statusLine, skills: context.skills }, null, 2),
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const remote = remoteByName.get(name);
|
|
129
|
+
if (!remote) {
|
|
130
|
+
return errorResult(`unknown tool: ${name}`);
|
|
131
|
+
}
|
|
132
|
+
if (!currentSession) {
|
|
133
|
+
return errorResult("no open work session — call caelo_open_session first. Every caelo write lands on a " +
|
|
134
|
+
"session's preview branch; without one there is nothing to write to.");
|
|
135
|
+
}
|
|
136
|
+
const result = await postAdmin({
|
|
137
|
+
adminUrl: opts.adminUrl,
|
|
138
|
+
token: opts.token,
|
|
139
|
+
path: "/api/mcp/tool",
|
|
140
|
+
body: {
|
|
141
|
+
toolName: name,
|
|
142
|
+
args: req.params.arguments ?? {},
|
|
143
|
+
chatSessionId: currentSession.chatSessionId,
|
|
144
|
+
},
|
|
145
|
+
timeoutMs: resolveTimeoutMs(120_000),
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
...(result.ok ? {} : { isError: true }),
|
|
149
|
+
content: [
|
|
150
|
+
{ type: "text", text: result.content },
|
|
151
|
+
...(result.image
|
|
152
|
+
? [
|
|
153
|
+
{
|
|
154
|
+
type: "image",
|
|
155
|
+
data: result.image.base64,
|
|
156
|
+
mimeType: result.image.mediaType,
|
|
157
|
+
},
|
|
158
|
+
]
|
|
159
|
+
: []),
|
|
160
|
+
{
|
|
161
|
+
type: "text",
|
|
162
|
+
text: JSON.stringify({
|
|
163
|
+
requestId: result.requestId,
|
|
164
|
+
cached: result.cached,
|
|
165
|
+
...(result.nextAction !== undefined ? { nextAction: result.nextAction } : {}),
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
173
|
+
return errorResult(`${name} failed: ${msg}`);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
const transport = new StdioServerTransport();
|
|
177
|
+
await server.connect(transport);
|
|
178
|
+
}
|
|
179
|
+
function errorResult(text) {
|
|
180
|
+
return { isError: true, content: [{ type: "text", text }] };
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=admin-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-server.js","sourceRoot":"","sources":["../src/admin-server.ts"],"names":[],"mappings":"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"}
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":""}
|
package/dist/admin.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
/**
|
|
4
|
+
* `caelo-admin-mcp` — bin entry for the Power-MCP server (issue #376).
|
|
5
|
+
* Equivalent to `caelo-mcp-server admin`; exists as its own binary so the
|
|
6
|
+
* `claude mcp add` snippet stays a single flag-free command.
|
|
7
|
+
*/
|
|
8
|
+
import { startAdminMcpServer } from "./admin-server.js";
|
|
9
|
+
const adminUrl = process.env.CAELO_ADMIN_URL;
|
|
10
|
+
const token = process.env.CAELO_MCP_TOKEN;
|
|
11
|
+
if (!adminUrl) {
|
|
12
|
+
console.error("CAELO_ADMIN_URL not set — point me at your admin install (e.g. https://admin.example.com)");
|
|
13
|
+
process.exit(2);
|
|
14
|
+
}
|
|
15
|
+
if (!token) {
|
|
16
|
+
console.error("CAELO_MCP_TOKEN not set — mint an ADMIN-scoped token at /security/mcp on your admin install");
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
await startAdminMcpServer({ adminUrl, token });
|
|
20
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":";AACA,mCAAmC;AAEnC;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAE1C,IAAI,CAAC,QAAQ,EAAE,CAAC;IACd,OAAO,CAAC,KAAK,CACX,2FAA2F,CAC5F,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CACX,6FAA6F,CAC9F,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,mBAAmB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/dist/chat-bridge.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP bridge — translates a `caelo_chat` MCP call into a single POST
|
|
3
|
-
* against the admin install's `/api/mcp/chat` endpoint. The endpoint
|
|
4
|
-
* dispatches `mcp.send_chat` (system-only op) which resolves the
|
|
5
|
-
* bearer to a Caelo actor and drives `runChatTurn`.
|
|
6
|
-
*
|
|
7
|
-
* 30-second client-side timeout — chat-runner turns longer than that
|
|
8
|
-
* are likely stuck (the runner has its own provider-call timeouts).
|
|
9
|
-
* MCP clients see a clean error instead of a hung connection.
|
|
10
|
-
*/
|
|
11
1
|
export interface SendChatOpts {
|
|
12
2
|
readonly adminUrl: string;
|
|
13
3
|
readonly token: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-bridge.d.ts","sourceRoot":"","sources":["../src/chat-bridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat-bridge.d.ts","sourceRoot":"","sources":["../src/chat-bridge.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzF,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAY1E"}
|
package/dist/chat-bridge.js
CHANGED
|
@@ -1,46 +1,27 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* HTTP bridge — translates a `caelo_chat` MCP call into a single POST
|
|
4
|
+
* against the admin install's `/api/mcp/chat` endpoint. The endpoint
|
|
5
|
+
* dispatches `mcp.send_chat` (system-only op) which resolves the
|
|
6
|
+
* bearer to a Caelo actor and drives `runChatTurn`.
|
|
7
|
+
*
|
|
8
|
+
* 30-second default client-side timeout (override with
|
|
9
|
+
* `CAELO_MCP_TIMEOUT_MS`) — chat-runner turns longer than that are
|
|
10
|
+
* likely stuck (the runner has its own provider-call timeouts). MCP
|
|
11
|
+
* clients see a clean error instead of a hung connection.
|
|
12
|
+
*/
|
|
13
|
+
import { postAdmin, resolveTimeoutMs } from "./http.js";
|
|
3
14
|
export async function sendChat(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
message: opts.message,
|
|
16
|
-
chatSessionId: opts.chatSessionId,
|
|
17
|
-
pageId: opts.pageId,
|
|
18
|
-
}),
|
|
19
|
-
signal: controller.signal,
|
|
20
|
-
});
|
|
21
|
-
if (!res.ok) {
|
|
22
|
-
const body = await safeText(res);
|
|
23
|
-
throw new Error(`HTTP ${res.status}: ${body || res.statusText}`);
|
|
24
|
-
}
|
|
25
|
-
const json = (await res.json());
|
|
26
|
-
return json;
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
if (e instanceof Error && e.name === "AbortError") {
|
|
30
|
-
throw new Error(`timeout after ${TIMEOUT_MS / 1000}s`);
|
|
31
|
-
}
|
|
32
|
-
throw e;
|
|
33
|
-
}
|
|
34
|
-
finally {
|
|
35
|
-
clearTimeout(timer);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
async function safeText(res) {
|
|
39
|
-
try {
|
|
40
|
-
return (await res.text()).slice(0, 500);
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return "";
|
|
44
|
-
}
|
|
15
|
+
return postAdmin({
|
|
16
|
+
adminUrl: opts.adminUrl,
|
|
17
|
+
token: opts.token,
|
|
18
|
+
path: "/api/mcp/chat",
|
|
19
|
+
body: {
|
|
20
|
+
message: opts.message,
|
|
21
|
+
chatSessionId: opts.chatSessionId,
|
|
22
|
+
pageId: opts.pageId,
|
|
23
|
+
},
|
|
24
|
+
timeoutMs: resolveTimeoutMs(30_000),
|
|
25
|
+
});
|
|
45
26
|
}
|
|
46
27
|
//# sourceMappingURL=chat-bridge.js.map
|
package/dist/chat-bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-bridge.js","sourceRoot":"","sources":["../src/chat-bridge.ts"],"names":[],"mappings":"AAAA,mCAAmC;
|
|
1
|
+
{"version":3,"file":"chat-bridge.js","sourceRoot":"","sources":["../src/chat-bridge.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAmBxD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAkB;IAC/C,OAAO,SAAS,CAAiB;QAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE;YACJ,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB;QACD,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ExportSkill {
|
|
2
|
+
readonly slug: string;
|
|
3
|
+
readonly displayName: string;
|
|
4
|
+
readonly description: string;
|
|
5
|
+
readonly allowlistedTools: string[];
|
|
6
|
+
readonly body?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ExportContext {
|
|
9
|
+
readonly systemContext: string;
|
|
10
|
+
readonly statusLine: string | null;
|
|
11
|
+
readonly skills: ReadonlyArray<ExportSkill>;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderClaudeMd(context: ExportContext, generatedAt: string): string;
|
|
14
|
+
export declare function renderSkillMd(skill: ExportSkill): string;
|
|
15
|
+
export interface RunExportOpts {
|
|
16
|
+
readonly adminUrl: string;
|
|
17
|
+
readonly token: string;
|
|
18
|
+
/** Directory the CLAUDE.md + .claude/skills tree lands in. */
|
|
19
|
+
readonly outDir: string;
|
|
20
|
+
}
|
|
21
|
+
/** Fetches the live context and writes the files. Returns written paths. */
|
|
22
|
+
export declare function runExport(opts: RunExportOpts): Promise<string[]>;
|
|
23
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CAC7C;AAMD,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA0BlF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAYxD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,4EAA4E;AAC5E,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BtE"}
|
package/dist/export.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Issue #376 — `caelo-mcp-server export`: writes a CLAUDE.md + one
|
|
4
|
+
* `.claude/skills/<slug>/SKILL.md` per active skill into a working
|
|
5
|
+
* directory, generated from the install's live context
|
|
6
|
+
* (`/api/mcp/context` with skill bodies included). Check the files into
|
|
7
|
+
* the repo an external agent (Claude Code) works from so the site
|
|
8
|
+
* context loads automatically at session start; re-run after skills or
|
|
9
|
+
* site memory change.
|
|
10
|
+
*
|
|
11
|
+
* The renderers are pure and exported for tests; `runExport` does the
|
|
12
|
+
* fetching + file I/O.
|
|
13
|
+
*
|
|
14
|
+
* Writing fetched content to disk is the feature, not an oversight
|
|
15
|
+
* (CodeQL flags the network→file flow): the source is the operator's OWN
|
|
16
|
+
* admin install, authenticated by their bearer, and the only
|
|
17
|
+
* path-influencing value is the skill slug — gated by SAFE_SLUG below so
|
|
18
|
+
* a hostile row cannot escape the out directory.
|
|
19
|
+
*/
|
|
20
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { postAdmin, resolveTimeoutMs } from "./http.js";
|
|
23
|
+
/** Path-safety gate for skill slugs — DB slugs already match this; a row
|
|
24
|
+
* that doesn't is skipped rather than allowed to escape the out dir. */
|
|
25
|
+
const SAFE_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
26
|
+
export function renderClaudeMd(context, generatedAt) {
|
|
27
|
+
const skillLines = context.skills.map((s) => `- ${s.slug}: ${s.description}`);
|
|
28
|
+
return [
|
|
29
|
+
"# Caelo site context",
|
|
30
|
+
"",
|
|
31
|
+
`<!-- Generated by \`caelo-mcp-server export\` at ${generatedAt}. Re-run to refresh; do not hand-edit. -->`,
|
|
32
|
+
"",
|
|
33
|
+
"This file describes the Caelo CMS install your `caelo-admin-mcp` MCP tools operate on.",
|
|
34
|
+
"Work happens through those tools: call `caelo_open_session` once, make changes with the",
|
|
35
|
+
"caelo tools (every write lands on the session's preview branch), and tell the operator to",
|
|
36
|
+
"review + publish in the Caelo admin. Never claim a change is live.",
|
|
37
|
+
"",
|
|
38
|
+
context.systemContext,
|
|
39
|
+
"",
|
|
40
|
+
"## Site status",
|
|
41
|
+
"",
|
|
42
|
+
context.statusLine ?? "Base setup complete.",
|
|
43
|
+
"",
|
|
44
|
+
"## Skills",
|
|
45
|
+
"",
|
|
46
|
+
"Full skill instructions live in `.claude/skills/<slug>/SKILL.md` — read the matching file",
|
|
47
|
+
"before the relevant work:",
|
|
48
|
+
"",
|
|
49
|
+
...skillLines,
|
|
50
|
+
"",
|
|
51
|
+
].join("\n");
|
|
52
|
+
}
|
|
53
|
+
export function renderSkillMd(skill) {
|
|
54
|
+
// JSON.stringify is YAML-compatible quoting — a description containing
|
|
55
|
+
// `#`, `:` or quotes must not break the frontmatter.
|
|
56
|
+
return [
|
|
57
|
+
"---",
|
|
58
|
+
`name: ${skill.slug}`,
|
|
59
|
+
`description: ${JSON.stringify(skill.description.replace(/\n/g, " "))}`,
|
|
60
|
+
"---",
|
|
61
|
+
"",
|
|
62
|
+
skill.body ?? "",
|
|
63
|
+
"",
|
|
64
|
+
].join("\n");
|
|
65
|
+
}
|
|
66
|
+
/** Fetches the live context and writes the files. Returns written paths. */
|
|
67
|
+
export async function runExport(opts) {
|
|
68
|
+
const context = await postAdmin({
|
|
69
|
+
adminUrl: opts.adminUrl,
|
|
70
|
+
token: opts.token,
|
|
71
|
+
path: "/api/mcp/context",
|
|
72
|
+
body: { includeSkillBodies: true },
|
|
73
|
+
timeoutMs: resolveTimeoutMs(60_000),
|
|
74
|
+
});
|
|
75
|
+
const written = [];
|
|
76
|
+
const claudeMdPath = join(opts.outDir, "CLAUDE.md");
|
|
77
|
+
await mkdir(opts.outDir, { recursive: true });
|
|
78
|
+
await writeFile(claudeMdPath, renderClaudeMd(context, new Date().toISOString()), "utf8");
|
|
79
|
+
written.push(claudeMdPath);
|
|
80
|
+
for (const skill of context.skills) {
|
|
81
|
+
if (!SAFE_SLUG.test(skill.slug)) {
|
|
82
|
+
console.error(`skipping skill with unsafe slug: ${JSON.stringify(skill.slug)}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const dir = join(opts.outDir, ".claude", "skills", skill.slug);
|
|
86
|
+
await mkdir(dir, { recursive: true });
|
|
87
|
+
const path = join(dir, "SKILL.md");
|
|
88
|
+
await writeFile(path, renderSkillMd(skill), "utf8");
|
|
89
|
+
written.push(path);
|
|
90
|
+
}
|
|
91
|
+
return written;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP plumbing for both MCP surfaces (chat + admin). One POST
|
|
3
|
+
* per call against the admin install's /api/mcp/* endpoints, bearer in
|
|
4
|
+
* the `x-caelo-mcp-token` header, with an abortable client-side timeout.
|
|
5
|
+
*
|
|
6
|
+
* Timeouts default per call site (chat 30s, tool execution 120s — bulk
|
|
7
|
+
* ops and media imports legitimately run long) and can be overridden
|
|
8
|
+
* globally via `CAELO_MCP_TIMEOUT_MS`.
|
|
9
|
+
*/
|
|
10
|
+
export interface AdminPostOpts {
|
|
11
|
+
readonly adminUrl: string;
|
|
12
|
+
readonly token: string;
|
|
13
|
+
/** Path under the admin origin, e.g. "/api/mcp/tool". */
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly body: unknown;
|
|
16
|
+
readonly timeoutMs: number;
|
|
17
|
+
}
|
|
18
|
+
/** The per-call default unless the operator set `CAELO_MCP_TIMEOUT_MS`. */
|
|
19
|
+
export declare function resolveTimeoutMs(defaultMs: number): number;
|
|
20
|
+
export declare function postAdmin<T>(opts: AdminPostOpts): Promise<T>;
|
|
21
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA6BlE"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/** The per-call default unless the operator set `CAELO_MCP_TIMEOUT_MS`. */
|
|
3
|
+
export function resolveTimeoutMs(defaultMs) {
|
|
4
|
+
const raw = process.env.CAELO_MCP_TIMEOUT_MS;
|
|
5
|
+
if (!raw)
|
|
6
|
+
return defaultMs;
|
|
7
|
+
const parsed = Number.parseInt(raw, 10);
|
|
8
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultMs;
|
|
9
|
+
}
|
|
10
|
+
export async function postAdmin(opts) {
|
|
11
|
+
const controller = new AbortController();
|
|
12
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs);
|
|
13
|
+
try {
|
|
14
|
+
const url = `${opts.adminUrl.replace(/\/+$/, "")}${opts.path}`;
|
|
15
|
+
const res = await fetch(url, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"content-type": "application/json",
|
|
19
|
+
"x-caelo-mcp-token": opts.token,
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(opts.body),
|
|
22
|
+
signal: controller.signal,
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
const body = await safeText(res);
|
|
26
|
+
throw new Error(`HTTP ${res.status}: ${body || res.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
return (await res.json());
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
32
|
+
throw new Error(`timeout after ${opts.timeoutMs / 1000}s (override with CAELO_MCP_TIMEOUT_MS)`);
|
|
33
|
+
}
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function safeText(res) {
|
|
41
|
+
try {
|
|
42
|
+
return (await res.text()).slice(0, 500);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAqBnC,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,IAAmB;IACpD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,mBAAmB,EAAE,IAAI,CAAC,KAAK;aAChC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,CAAC,SAAS,GAAG,IAAI,wCAAwC,CAC/E,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAa;IACnC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,17 +3,25 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @caelo-cms/mcp-server — entrypoint.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* server exposing exactly one tool (`caelo_chat`), and listens over
|
|
8
|
-
* stdio (Claude Code's default invocation pattern).
|
|
6
|
+
* Three modes, selected by the first argument:
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* the admin
|
|
8
|
+
* - (none) — the chat MCP server: exactly one tool (`caelo_chat`) that
|
|
9
|
+
* talks to Caelo's own AI agent. Works with any token scope.
|
|
10
|
+
* - `admin` — the Power-MCP server (issue #376): the full chat-runner
|
|
11
|
+
* tool catalogue for an external agent that drives the tool
|
|
12
|
+
* loop itself. Requires an admin-scoped token. Also
|
|
13
|
+
* available as the `caelo-admin-mcp` binary.
|
|
14
|
+
* - `export` — writes CLAUDE.md + .claude/skills/ files generated from
|
|
15
|
+
* the install's live context into `--out <dir>` (default:
|
|
16
|
+
* the current directory). Requires an admin-scoped token.
|
|
17
|
+
*
|
|
18
|
+
* Bridge model: every mode is a thin shim. Calls become HTTP POSTs
|
|
19
|
+
* against the admin install's `/api/mcp/*` endpoints, which dispatch
|
|
20
|
+
* system-scoped ops that resolve the bearer to a Caelo actor. The MCP
|
|
21
|
+
* server NEVER touches the database directly.
|
|
16
22
|
*/
|
|
23
|
+
import { startAdminMcpServer } from "./admin-server.js";
|
|
24
|
+
import { runExport } from "./export.js";
|
|
17
25
|
import { startMcpServer } from "./server.js";
|
|
18
26
|
const adminUrl = process.env.CAELO_ADMIN_URL;
|
|
19
27
|
const token = process.env.CAELO_MCP_TOKEN;
|
|
@@ -25,5 +33,27 @@ if (!token) {
|
|
|
25
33
|
console.error("CAELO_MCP_TOKEN not set — mint one at /security/mcp on your admin install");
|
|
26
34
|
process.exit(2);
|
|
27
35
|
}
|
|
28
|
-
|
|
36
|
+
const command = process.argv[2];
|
|
37
|
+
if (command === "export") {
|
|
38
|
+
const outFlag = process.argv.indexOf("--out");
|
|
39
|
+
const outDir = outFlag !== -1 ? process.argv[outFlag + 1] : undefined;
|
|
40
|
+
if (outFlag !== -1 && !outDir) {
|
|
41
|
+
console.error("--out needs a directory argument");
|
|
42
|
+
process.exit(2);
|
|
43
|
+
}
|
|
44
|
+
const written = await runExport({ adminUrl, token, outDir: outDir ?? process.cwd() });
|
|
45
|
+
for (const path of written)
|
|
46
|
+
console.log(path);
|
|
47
|
+
console.log(`exported ${written.length} file(s) — re-run after skills or site memory change`);
|
|
48
|
+
}
|
|
49
|
+
else if (command === "admin") {
|
|
50
|
+
await startAdminMcpServer({ adminUrl, token });
|
|
51
|
+
}
|
|
52
|
+
else if (command !== undefined) {
|
|
53
|
+
console.error(`unknown command: ${command} (expected no command, "admin", or "export")`);
|
|
54
|
+
process.exit(2);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await startMcpServer({ adminUrl, token });
|
|
58
|
+
}
|
|
29
59
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,mCAAmC;AAEnC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,mCAAmC;AAEnC;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAE1C,IAAI,CAAC,QAAQ,EAAE,CAAC;IACd,OAAO,CAAC,KAAK,CACX,2FAA2F,CAC5F,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtF,KAAK,MAAM,IAAI,IAAI,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,MAAM,sDAAsD,CAAC,CAAC;AAChG,CAAC;KAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;IAC/B,MAAM,mBAAmB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AACjD,CAAC;KAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;IACjC,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,8CAA8C,CAAC,CAAC;IACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;KAAM,CAAC;IACN,MAAM,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caelo-cms/mcp-server",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.23",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"description": "MCP
|
|
6
|
+
"description": "MCP servers for Caelo CMS: `caelo_chat` (talk to Caelo's own AI) and the admin-scoped Power-MCP (the full chat-runner tool catalogue, driven by your own agent). Lets Claude Code (or any MCP-aware client) drive a Caelo install from outside the browser.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/caelo-cms/caelo-cms.git",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
17
|
"bin": {
|
|
18
|
-
"caelo-mcp-server": "./dist/index.js"
|
|
18
|
+
"caelo-mcp-server": "./dist/index.js",
|
|
19
|
+
"caelo-admin-mcp": "./dist/admin.js"
|
|
19
20
|
},
|
|
20
21
|
"exports": {
|
|
21
22
|
".": {
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
39
|
-
"zod": "4.3
|
|
40
|
+
"zod": "4.4.3"
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
42
43
|
"access": "public"
|