mcpill 1.2.4 → 1.5.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/CHANGELOG.md +17 -0
- package/README.md +19 -1
- package/dist/cli.js +565 -165
- package/package.json +6 -1
- package/src/__tests__/init.test.ts +0 -75
- package/src/__tests__/loaders/config.test.ts +0 -54
- package/src/__tests__/loaders/prompts.test.ts +0 -116
- package/src/__tests__/loaders/resources.test.ts +0 -86
- package/src/__tests__/loaders/tools.test.ts +0 -128
- package/src/__tests__/pack.test.ts +0 -98
- package/src/__tests__/validate.test.ts +0 -152
- package/src/cli.ts +0 -76
- package/src/commands/compile.ts +0 -166
- package/src/commands/init.ts +0 -353
- package/src/commands/pack.ts +0 -38
- package/src/commands/publish.ts +0 -17
- package/src/commands/run.ts +0 -105
- package/src/commands/validate.ts +0 -59
- package/src/compiler/merge-tools.ts +0 -99
- package/src/compiler/parse.ts +0 -236
- package/src/compiler/serialize.ts +0 -100
- package/src/compiler/types.ts +0 -27
- package/src/loaders/config.ts +0 -25
- package/src/loaders/prompts.ts +0 -60
- package/src/loaders/resources.ts +0 -54
- package/src/loaders/tools.ts +0 -68
- package/src/templates/prompts/greeting.md +0 -11
- package/src/templates/server.md +0 -9
- package/src/templates/tools/echo.md +0 -15
- package/tsconfig.json +0 -10
- package/tsup.config.ts +0 -13
- package/vitest.config.ts +0 -12
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import os from "os";
|
|
5
|
-
import { runValidate } from "../commands/validate.js";
|
|
6
|
-
|
|
7
|
-
// Sets up a minimal valid .<name>/ pill dir using CJS tools.js so dynamic
|
|
8
|
-
// import works without a mcpill-runtime resolution in the temp tree.
|
|
9
|
-
function scaffoldValid(mcpillDir: string) {
|
|
10
|
-
fs.mkdirSync(mcpillDir, { recursive: true });
|
|
11
|
-
fs.writeFileSync(
|
|
12
|
-
path.join(mcpillDir, "tools.js"),
|
|
13
|
-
`module.exports = [{ name: "t", description: "d", schema: {}, handler: async () => ({}) }]`
|
|
14
|
-
);
|
|
15
|
-
fs.writeFileSync(
|
|
16
|
-
path.join(mcpillDir, "prompts.json"),
|
|
17
|
-
JSON.stringify([{ name: "p", args: {}, messages: [] }])
|
|
18
|
-
);
|
|
19
|
-
fs.writeFileSync(
|
|
20
|
-
path.join(mcpillDir, "resources.md"),
|
|
21
|
-
"uri: config://app\n---\nContent."
|
|
22
|
-
);
|
|
23
|
-
fs.writeFileSync(
|
|
24
|
-
path.join(mcpillDir, "mcpill.config.json"),
|
|
25
|
-
JSON.stringify({ name: "srv", transport: "stdio", port: 3333 })
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe("runValidate", () => {
|
|
30
|
-
const dirs: string[] = [];
|
|
31
|
-
|
|
32
|
-
function mkTmp(): string {
|
|
33
|
-
const d = fs.mkdtempSync(path.join(os.tmpdir(), "mcpill-validate-"));
|
|
34
|
-
dirs.push(d);
|
|
35
|
-
return d;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function mockExit() {
|
|
39
|
-
return vi
|
|
40
|
-
.spyOn(process, "exit")
|
|
41
|
-
.mockImplementation((_code?: number | string | null) => {
|
|
42
|
-
throw new Error("process.exit called");
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
vi.restoreAllMocks();
|
|
48
|
-
for (const d of dirs.splice(0)) {
|
|
49
|
-
fs.rmSync(d, { recursive: true, force: true });
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("passes on a valid scaffolded pill dir", async () => {
|
|
54
|
-
const base = mkTmp();
|
|
55
|
-
const mcpillDir = path.join(base, ".mcpill", "server");
|
|
56
|
-
scaffoldValid(mcpillDir);
|
|
57
|
-
|
|
58
|
-
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
59
|
-
await runValidate(base);
|
|
60
|
-
expect(logSpy).toHaveBeenCalledWith("✓ Valid: 1 tools, 1 prompts, 1 resources");
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("exits with code 1 when no pill directories found", async () => {
|
|
64
|
-
const base = mkTmp();
|
|
65
|
-
const exitSpy = mockExit();
|
|
66
|
-
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
67
|
-
|
|
68
|
-
await expect(runValidate(base)).rejects.toThrow("process.exit called");
|
|
69
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
70
|
-
expect(errSpy).toHaveBeenCalledWith(
|
|
71
|
-
"No pill directories found — run mcpill compile first"
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("collects and prints tool error then exits 1", async () => {
|
|
76
|
-
const base = mkTmp();
|
|
77
|
-
const mcpillDir = path.join(base, ".mcpill", "server");
|
|
78
|
-
scaffoldValid(mcpillDir);
|
|
79
|
-
// Break tools.js: handler is not a function
|
|
80
|
-
fs.writeFileSync(
|
|
81
|
-
path.join(mcpillDir, "tools.js"),
|
|
82
|
-
`module.exports = [{ name: "t", description: "d", schema: {}, handler: "bad" }]`
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const exitSpy = mockExit();
|
|
86
|
-
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
87
|
-
|
|
88
|
-
await expect(runValidate(base)).rejects.toThrow("process.exit called");
|
|
89
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
90
|
-
expect(errSpy).toHaveBeenCalledWith("Tool 't': handler must be a function");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("collects and prints prompt error then exits 1", async () => {
|
|
94
|
-
const base = mkTmp();
|
|
95
|
-
const mcpillDir = path.join(base, ".mcpill", "server");
|
|
96
|
-
scaffoldValid(mcpillDir);
|
|
97
|
-
fs.writeFileSync(path.join(mcpillDir, "prompts.json"), "not json {{{");
|
|
98
|
-
|
|
99
|
-
const exitSpy = mockExit();
|
|
100
|
-
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
101
|
-
|
|
102
|
-
await expect(runValidate(base)).rejects.toThrow("process.exit called");
|
|
103
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
104
|
-
expect(
|
|
105
|
-
errSpy.mock.calls.some((c) =>
|
|
106
|
-
String(c[0]).startsWith("prompts.json is not valid JSON:")
|
|
107
|
-
)
|
|
108
|
-
).toBe(true);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("collects and prints resource error then exits 1", async () => {
|
|
112
|
-
const base = mkTmp();
|
|
113
|
-
const mcpillDir = path.join(base, ".mcpill", "server");
|
|
114
|
-
scaffoldValid(mcpillDir);
|
|
115
|
-
// Block missing uri
|
|
116
|
-
fs.writeFileSync(
|
|
117
|
-
path.join(mcpillDir, "resources.md"),
|
|
118
|
-
"name: No Uri\n---\nContent."
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const exitSpy = mockExit();
|
|
122
|
-
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
123
|
-
|
|
124
|
-
await expect(runValidate(base)).rejects.toThrow("process.exit called");
|
|
125
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
126
|
-
expect(errSpy).toHaveBeenCalledWith(
|
|
127
|
-
"resources.md block 1 is missing required frontmatter field: uri"
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("collects errors from multiple loaders before exiting", async () => {
|
|
132
|
-
const base = mkTmp();
|
|
133
|
-
const mcpillDir = path.join(base, ".mcpill", "server");
|
|
134
|
-
scaffoldValid(mcpillDir);
|
|
135
|
-
// Break both tools and prompts
|
|
136
|
-
fs.writeFileSync(
|
|
137
|
-
path.join(mcpillDir, "tools.js"),
|
|
138
|
-
`module.exports = [{ description: "d", schema: {}, handler: async () => ({}) }]`
|
|
139
|
-
);
|
|
140
|
-
fs.writeFileSync(path.join(mcpillDir, "prompts.json"), "bad json");
|
|
141
|
-
|
|
142
|
-
const exitSpy = mockExit();
|
|
143
|
-
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
144
|
-
|
|
145
|
-
await expect(runValidate(base)).rejects.toThrow("process.exit called");
|
|
146
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
147
|
-
// Both errors must have been printed
|
|
148
|
-
const messages = errSpy.mock.calls.map((c) => String(c[0]));
|
|
149
|
-
expect(messages.some((m) => m.includes("Tool at index 0 is missing"))).toBe(true);
|
|
150
|
-
expect(messages.some((m) => m.startsWith("prompts.json is not valid JSON:"))).toBe(true);
|
|
151
|
-
});
|
|
152
|
-
});
|
package/src/cli.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { fileURLToPath } from "url";
|
|
3
|
-
import { dirname, join } from "path";
|
|
4
|
-
import { readFileSync } from "fs";
|
|
5
|
-
import { runInit } from "./commands/init.js";
|
|
6
|
-
import { runServer } from "./commands/run.js";
|
|
7
|
-
import { runValidate } from "./commands/validate.js";
|
|
8
|
-
import { runCompile } from "./commands/compile.js";
|
|
9
|
-
import { runPack } from "./commands/pack.js";
|
|
10
|
-
import { runPublish } from "./commands/publish.js";
|
|
11
|
-
|
|
12
|
-
const pkgDir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const pkg = JSON.parse(
|
|
14
|
-
readFileSync(join(pkgDir, "../package.json"), "utf-8")
|
|
15
|
-
) as { version: string };
|
|
16
|
-
|
|
17
|
-
const program = new Command();
|
|
18
|
-
|
|
19
|
-
program.name("mcpill").version(pkg.version);
|
|
20
|
-
|
|
21
|
-
program
|
|
22
|
-
.command("init")
|
|
23
|
-
.description("Scaffold a new .mcpill/ directory")
|
|
24
|
-
.option("--dir <path>", "Target directory")
|
|
25
|
-
.action(async (opts: { dir?: string }) => {
|
|
26
|
-
await runInit(opts);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
program
|
|
30
|
-
.command("run")
|
|
31
|
-
.description("Start the MCP server")
|
|
32
|
-
.option("--transport <transport>", "Transport type: stdio or http")
|
|
33
|
-
.option("--port <n>", "Port number (HTTP only)", parseInt)
|
|
34
|
-
.option("--dir <path>", "Directory containing .mcpill/")
|
|
35
|
-
.action(
|
|
36
|
-
async (opts: { transport?: "stdio" | "http"; port?: number; dir?: string }) => {
|
|
37
|
-
await runServer(opts);
|
|
38
|
-
}
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
.command("validate")
|
|
43
|
-
.description("Validate .mcpill/ configuration")
|
|
44
|
-
.option("--dir <path>", "Directory containing .mcpill/")
|
|
45
|
-
.action(async (opts: { dir?: string }) => {
|
|
46
|
-
const { resolve } = await import("path");
|
|
47
|
-
await runValidate(resolve(opts.dir ?? process.cwd()));
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
program
|
|
51
|
-
.command("compile")
|
|
52
|
-
.description("Compile server.md ↔ .mcpill/ files")
|
|
53
|
-
.option("--dir <path>", "Directory containing server.md and .mcpill/")
|
|
54
|
-
.option("--to-md", "Reverse: generate server.md from .mcpill/ files")
|
|
55
|
-
.option("--strict", "Error on missing tool handlers instead of generating stubs")
|
|
56
|
-
.action(async (opts: { dir?: string; toMd?: boolean; strict?: boolean }) => {
|
|
57
|
-
await runCompile(opts);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
program
|
|
61
|
-
.command("pack")
|
|
62
|
-
.description("Prepare pill for npm distribution")
|
|
63
|
-
.option("--dir <path>", "pill project root", ".")
|
|
64
|
-
.action(({ dir }: { dir: string }) => runPack(dir));
|
|
65
|
-
|
|
66
|
-
program
|
|
67
|
-
.command("publish")
|
|
68
|
-
.description("Pack and publish pill to npm")
|
|
69
|
-
.option("--dir <path>", "pill project root", ".")
|
|
70
|
-
.option("--access <level>", "npm access level", "public")
|
|
71
|
-
.action(({ dir, access }: { dir: string; access: string }) => runPublish(dir, access));
|
|
72
|
-
|
|
73
|
-
program.parseAsync(process.argv).catch((err) => {
|
|
74
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
75
|
-
process.exit(1);
|
|
76
|
-
});
|
package/src/commands/compile.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { resolve, join } from 'path';
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
3
|
-
import { pathToFileURL } from 'url';
|
|
4
|
-
import { parseServerDir, parseKvBlock } from '../compiler/parse.js';
|
|
5
|
-
import { serializeServerDir } from '../compiler/serialize.js';
|
|
6
|
-
import { extractHandlers, mergeHandlers } from '../compiler/merge-tools.js';
|
|
7
|
-
import { loadConfig } from '../loaders/config.js';
|
|
8
|
-
import { loadResources } from '../loaders/resources.js';
|
|
9
|
-
import type { ServerDoc, ToolDoc } from '../compiler/types.js';
|
|
10
|
-
|
|
11
|
-
const zodTypeNameMap: Record<string, 'string' | 'number' | 'boolean'> = {
|
|
12
|
-
ZodString: 'string',
|
|
13
|
-
ZodNumber: 'number',
|
|
14
|
-
ZodBoolean: 'boolean',
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
function generateToolsJs(tools: ToolDoc[]): string {
|
|
18
|
-
const lines: string[] = [`import { z } from 'mcpill-runtime';\n\nexport default [`];
|
|
19
|
-
|
|
20
|
-
for (const tool of tools) {
|
|
21
|
-
const schemaLines = Object.entries(tool.schema).map(([key, def]) => {
|
|
22
|
-
const zodCall = def.description
|
|
23
|
-
? `z.${def.type}().describe(${JSON.stringify(def.description)})`
|
|
24
|
-
: `z.${def.type}()`;
|
|
25
|
-
return ` ${key}: ${zodCall},`;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Indent handler lines 6 spaces; dedent+trim is applied on extract so this round-trips cleanly.
|
|
29
|
-
const handlerBody = (tool.handler ?? '').split('\n').map((l) => ` ${l}`).join('\n');
|
|
30
|
-
|
|
31
|
-
lines.push(
|
|
32
|
-
` {`,
|
|
33
|
-
` name: ${JSON.stringify(tool.name)},`,
|
|
34
|
-
` description: ${JSON.stringify(tool.description)},`,
|
|
35
|
-
` schema: {`,
|
|
36
|
-
...schemaLines,
|
|
37
|
-
` },`,
|
|
38
|
-
` handler:`,
|
|
39
|
-
` // @handler:${tool.name}`,
|
|
40
|
-
handlerBody,
|
|
41
|
-
` // @end-handler:${tool.name}`,
|
|
42
|
-
` ,`,
|
|
43
|
-
` },`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
lines.push(`];`);
|
|
48
|
-
return lines.join('\n') + '\n';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function serializeResourcesMd(resources: ServerDoc['resources']): string {
|
|
52
|
-
if (resources.length === 0) return '';
|
|
53
|
-
return (
|
|
54
|
-
resources
|
|
55
|
-
.map((r) => {
|
|
56
|
-
let fm = `uri: ${r.uri}`;
|
|
57
|
-
if (r.name) fm += `\nname: ${r.name}`;
|
|
58
|
-
if (r.mimeType) fm += `\nmimeType: ${r.mimeType}`;
|
|
59
|
-
return `${fm}\n---\n${r.content}`;
|
|
60
|
-
})
|
|
61
|
-
.join('\n---\n') + '\n'
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export async function runCompile(opts: {
|
|
66
|
-
dir?: string;
|
|
67
|
-
toMd?: boolean;
|
|
68
|
-
strict?: boolean;
|
|
69
|
-
}): Promise<void> {
|
|
70
|
-
const baseDir = resolve(opts.dir ?? process.cwd());
|
|
71
|
-
const mcpillDir = join(baseDir, '.mcpill');
|
|
72
|
-
const serverDir = join(mcpillDir, 'server');
|
|
73
|
-
|
|
74
|
-
if (opts.toMd) {
|
|
75
|
-
const configPath = join(serverDir, 'mcpill.config.json');
|
|
76
|
-
if (!existsSync(configPath)) {
|
|
77
|
-
throw new Error('No pill found — run mcpill compile first');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const config = await loadConfig(serverDir);
|
|
81
|
-
const resources = await loadResources(serverDir);
|
|
82
|
-
|
|
83
|
-
const promptsPath = join(serverDir, 'prompts.json');
|
|
84
|
-
const prompts = JSON.parse(readFileSync(promptsPath, 'utf-8')) as ServerDoc['prompts'];
|
|
85
|
-
|
|
86
|
-
const toolsPath = join(serverDir, 'tools.js');
|
|
87
|
-
const handlers = existsSync(toolsPath)
|
|
88
|
-
? extractHandlers(readFileSync(toolsPath, 'utf-8'))
|
|
89
|
-
: new Map<string, string>();
|
|
90
|
-
|
|
91
|
-
let tools: ToolDoc[] = [];
|
|
92
|
-
if (existsSync(toolsPath)) {
|
|
93
|
-
const mod = (await import(pathToFileURL(toolsPath).href)) as {
|
|
94
|
-
default: Array<{ name: string; description: string; schema: Record<string, unknown> }>;
|
|
95
|
-
};
|
|
96
|
-
tools = mod.default.map((t) => {
|
|
97
|
-
const schema: ToolDoc['schema'] = {};
|
|
98
|
-
for (const [key, val] of Object.entries(t.schema)) {
|
|
99
|
-
const def = (val as { _def: { typeName: string; description?: string } })._def;
|
|
100
|
-
const type = zodTypeNameMap[def.typeName] ?? 'string';
|
|
101
|
-
schema[key] = def.description ? { type, description: def.description } : { type };
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
name: t.name,
|
|
105
|
-
description: t.description,
|
|
106
|
-
schema,
|
|
107
|
-
handler: handlers.get(t.name),
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const doc: ServerDoc = {
|
|
113
|
-
config: {
|
|
114
|
-
name: config.name,
|
|
115
|
-
transport: config.transport,
|
|
116
|
-
...(config.port !== 3333 ? { port: config.port } : {}),
|
|
117
|
-
},
|
|
118
|
-
tools,
|
|
119
|
-
prompts,
|
|
120
|
-
resources,
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
serializeServerDir(doc, mcpillDir);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Forward direction: .mcpill/server.md + .mcpill/server/tools/ + .mcpill/server/prompts/ → .mcpill/server/
|
|
128
|
-
const doc = parseServerDir(mcpillDir);
|
|
129
|
-
|
|
130
|
-
const toolsJsPath = join(serverDir, 'tools.js');
|
|
131
|
-
const existing = existsSync(toolsJsPath)
|
|
132
|
-
? extractHandlers(readFileSync(toolsJsPath, 'utf-8'))
|
|
133
|
-
: new Map<string, string>();
|
|
134
|
-
|
|
135
|
-
const { doc: mergedDoc, stubbed } = mergeHandlers(doc, existing);
|
|
136
|
-
|
|
137
|
-
// If PILL.md declares a name/transport in its ## Server section, let it win
|
|
138
|
-
// over whatever server.md still has (catches cases where the agent forgets to update server.md).
|
|
139
|
-
const pillMdPath = join(baseDir, 'PILL.md');
|
|
140
|
-
if (existsSync(pillMdPath)) {
|
|
141
|
-
const pillContent = readFileSync(pillMdPath, 'utf-8');
|
|
142
|
-
const serverSection = ('\n' + pillContent).split('\n## ').find((s) => s.startsWith('Server\n'));
|
|
143
|
-
if (serverSection) {
|
|
144
|
-
const kv = parseKvBlock(serverSection.slice('Server\n'.length));
|
|
145
|
-
if (kv['name']) mergedDoc.config.name = kv['name'];
|
|
146
|
-
if (kv['transport'] === 'stdio' || kv['transport'] === 'http') {
|
|
147
|
-
mergedDoc.config.transport = kv['transport'];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (opts.strict && stubbed.length > 0) {
|
|
153
|
-
throw new Error('Missing handlers for: ' + stubbed.join(', '));
|
|
154
|
-
}
|
|
155
|
-
for (const name of stubbed) {
|
|
156
|
-
console.warn(`⚠ Stub generated for tool: ${name}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
mkdirSync(serverDir, { recursive: true });
|
|
160
|
-
writeFileSync(join(serverDir, 'mcpill.config.json'), JSON.stringify(mergedDoc.config, null, 2));
|
|
161
|
-
writeFileSync(join(serverDir, 'prompts.json'), JSON.stringify(mergedDoc.prompts, null, 2));
|
|
162
|
-
writeFileSync(join(serverDir, 'resources.md'), serializeResourcesMd(mergedDoc.resources));
|
|
163
|
-
writeFileSync(toolsJsPath, generateToolsJs(mergedDoc.tools));
|
|
164
|
-
|
|
165
|
-
console.log(`✓ .mcpill/server/ updated from .mcpill/server.md, .mcpill/server/tools/, .mcpill/server/prompts/`);
|
|
166
|
-
}
|