@modootoday/pmcp 0.1.4 → 0.2.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/README.md +3 -2
- package/dist/{chunk-SLTUWTII.js → chunk-2NOO5RSP.js} +2 -2
- package/dist/chunk-3NNRQ5A4.js +698 -0
- package/dist/{chunk-AJNIMNCV.js → chunk-Y32X35YV.js} +10 -4
- package/dist/cli.js +48 -17
- package/dist/index.d.ts +107 -11
- package/dist/index.js +16 -2
- package/dist/stdio.d.ts +1 -1
- package/dist/stdio.js +2 -2
- package/package.json +3 -2
- package/skills/package-skill-catalog/SKILL.md +10 -8
- package/dist/chunk-N3SHKKWG.js +0 -363
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSkillServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3NNRQ5A4.js";
|
|
4
4
|
|
|
5
5
|
// src/stdio.ts
|
|
6
6
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
@@ -8,8 +8,14 @@ function resolveRoots(argv, cwd) {
|
|
|
8
8
|
const given = argv.filter((arg) => !arg.startsWith("-"));
|
|
9
9
|
return given.length > 0 ? given : [`${cwd}/node_modules`];
|
|
10
10
|
}
|
|
11
|
-
function serve(roots, scopes = []) {
|
|
12
|
-
const options =
|
|
11
|
+
function serve(roots, scopes = [], marketplaces = []) {
|
|
12
|
+
const options = {
|
|
13
|
+
roots,
|
|
14
|
+
...scopes.length > 0 ? { scopes } : {},
|
|
15
|
+
...marketplaces.length > 0 ? { marketplaces } : {},
|
|
16
|
+
onReject: ({ path, reason }) => process.stderr.write(`pmcp: skipped ${path}: ${reason}
|
|
17
|
+
`)
|
|
18
|
+
};
|
|
13
19
|
serveStdio(() => createSkillServer(options), {
|
|
14
20
|
// stdout is the protocol. A diagnostic written there corrupts the stream,
|
|
15
21
|
// so out-of-band errors go to stderr and nowhere else.
|
|
@@ -30,4 +36,4 @@ export {
|
|
|
30
36
|
serve,
|
|
31
37
|
main
|
|
32
38
|
};
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
39
|
+
//# sourceMappingURL=chunk-Y32X35YV.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
openDatabase
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2NOO5RSP.js";
|
|
5
5
|
import {
|
|
6
6
|
serve
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Y32X35YV.js";
|
|
8
8
|
import {
|
|
9
9
|
readCatalog
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3NNRQ5A4.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/command.ts
|
|
13
13
|
var ArgumentError = class extends Error {
|
|
@@ -302,16 +302,30 @@ var CATALOG_OPTIONS = [
|
|
|
302
302
|
describe: "Only packages whose names start with this. Repeatable.",
|
|
303
303
|
repeat: true,
|
|
304
304
|
placeholder: "<prefix>"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: "marketplace",
|
|
308
|
+
describe: "A plugin marketplace directory (holds .claude-plugin/marketplace.json). Repeatable.",
|
|
309
|
+
repeat: true,
|
|
310
|
+
placeholder: "<dir>"
|
|
305
311
|
}
|
|
306
312
|
];
|
|
307
313
|
function rootsFrom(context) {
|
|
308
314
|
const given = many(context.args, "root");
|
|
309
315
|
return given.length > 0 ? given : [`${context.cwd}/node_modules`];
|
|
310
316
|
}
|
|
311
|
-
function
|
|
317
|
+
function catalogOptionsFrom(context, onReject) {
|
|
312
318
|
const scopes = many(context.args, "scope");
|
|
313
|
-
const
|
|
314
|
-
return
|
|
319
|
+
const marketplaces = many(context.args, "marketplace");
|
|
320
|
+
return {
|
|
321
|
+
roots: rootsFrom(context),
|
|
322
|
+
...scopes.length > 0 ? { scopes } : {},
|
|
323
|
+
...marketplaces.length > 0 ? { marketplaces } : {},
|
|
324
|
+
...onReject ? { onReject } : {}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function catalogFrom(context, onReject) {
|
|
328
|
+
return readCatalog(catalogOptionsFrom(context, onReject));
|
|
315
329
|
}
|
|
316
330
|
|
|
317
331
|
// src/commands/reindex.ts
|
|
@@ -418,26 +432,39 @@ var indexCommand = {
|
|
|
418
432
|
// src/commands/list.ts
|
|
419
433
|
var listCommand = {
|
|
420
434
|
name: "list",
|
|
421
|
-
describe: "List the skills discovered in node_modules",
|
|
422
|
-
usage: "pmcp list [--root <dir>] [--scope <prefix>] [--json]",
|
|
435
|
+
describe: "List the skills discovered in node_modules and marketplaces",
|
|
436
|
+
usage: "pmcp list [--root <dir>] [--scope <prefix>] [--marketplace <dir>] [--json]",
|
|
423
437
|
options: [
|
|
424
438
|
...CATALOG_OPTIONS,
|
|
425
439
|
{ name: "json", describe: "Emit JSON rather than a table.", boolean: true }
|
|
426
440
|
],
|
|
427
441
|
run(context) {
|
|
428
|
-
const
|
|
442
|
+
const rejected = [];
|
|
443
|
+
const entries = catalogFrom(
|
|
444
|
+
context,
|
|
445
|
+
(rejection) => rejected.push(rejection)
|
|
446
|
+
);
|
|
429
447
|
if (context.args.flags.has("json")) {
|
|
430
|
-
context.ui.data(
|
|
431
|
-
|
|
432
|
-
|
|
448
|
+
context.ui.data(
|
|
449
|
+
`${JSON.stringify({ skills: entries, rejected }, null, 2)}
|
|
450
|
+
`
|
|
451
|
+
);
|
|
452
|
+
return entries.length > 0 && rejected.length === 0 ? 0 : 1;
|
|
433
453
|
}
|
|
454
|
+
for (const { path, reason } of rejected)
|
|
455
|
+
context.ui.error("skipped", `${path}: ${reason}`);
|
|
434
456
|
if (entries.length === 0) {
|
|
435
457
|
context.ui.error("no skills found", rootsFrom(context).join(" "));
|
|
436
458
|
return 1;
|
|
437
459
|
}
|
|
438
|
-
context.ui.table(
|
|
460
|
+
context.ui.table(
|
|
461
|
+
entries.map((entry2) => [
|
|
462
|
+
entry2.tier === void 0 ? entry2.name : `${entry2.name} [${entry2.tier}]`,
|
|
463
|
+
entry2.description
|
|
464
|
+
])
|
|
465
|
+
);
|
|
439
466
|
context.ui.success(`${entries.length} skills`);
|
|
440
|
-
return 0;
|
|
467
|
+
return rejected.length === 0 ? 0 : 1;
|
|
441
468
|
}
|
|
442
469
|
};
|
|
443
470
|
|
|
@@ -445,10 +472,14 @@ var listCommand = {
|
|
|
445
472
|
var serveCommand = {
|
|
446
473
|
name: "serve",
|
|
447
474
|
describe: "Run the MCP server on stdio (the default with no command)",
|
|
448
|
-
usage: "pmcp serve [--root <dir>] [--scope <prefix>]",
|
|
475
|
+
usage: "pmcp serve [--root <dir>] [--scope <prefix>] [--marketplace <dir>]",
|
|
449
476
|
options: [...CATALOG_OPTIONS],
|
|
450
477
|
run(context) {
|
|
451
|
-
serve(
|
|
478
|
+
serve(
|
|
479
|
+
rootsFrom(context),
|
|
480
|
+
many(context.args, "scope"),
|
|
481
|
+
many(context.args, "marketplace")
|
|
482
|
+
);
|
|
452
483
|
return 0;
|
|
453
484
|
}
|
|
454
485
|
};
|
|
@@ -2042,7 +2073,7 @@ function dispatch(argv, options = {}) {
|
|
|
2042
2073
|
}
|
|
2043
2074
|
return run(command, rest, { ui, env, cwd });
|
|
2044
2075
|
}
|
|
2045
|
-
var VERSION = "0.
|
|
2076
|
+
var VERSION = "0.2.0";
|
|
2046
2077
|
async function run(command, argv, context) {
|
|
2047
2078
|
try {
|
|
2048
2079
|
return await command.run({
|
package/dist/index.d.ts
CHANGED
|
@@ -77,12 +77,25 @@ interface SkillEntry {
|
|
|
77
77
|
readonly description: string;
|
|
78
78
|
/** Absolute path to the SKILL.md. `call` reads the body from here. */
|
|
79
79
|
readonly path: string;
|
|
80
|
+
/** open, free or paid. Set for marketplace skills, absent for packages. */
|
|
81
|
+
readonly tier?: string;
|
|
82
|
+
/** The frontmatter `metadata:` block, one level deep. */
|
|
83
|
+
readonly metadata?: Readonly<Record<string, string | readonly string[]>>;
|
|
84
|
+
/** Extra search terms. Ranked with the description, never used as triggers. */
|
|
85
|
+
readonly keywords?: readonly string[];
|
|
80
86
|
}
|
|
81
87
|
interface CatalogOptions {
|
|
82
88
|
/** Directories to walk. Each is a `node_modules` root, not a package root. */
|
|
83
89
|
readonly roots: readonly string[];
|
|
84
90
|
/** Package name prefixes to consider. Empty means every package. */
|
|
85
91
|
readonly scopes?: readonly string[];
|
|
92
|
+
/** Marketplace directories, each holding .claude-plugin/marketplace.json. */
|
|
93
|
+
readonly marketplaces?: readonly string[];
|
|
94
|
+
/** Told about every marketplace skill left out, and why. */
|
|
95
|
+
readonly onReject?: (rejection: {
|
|
96
|
+
path: string;
|
|
97
|
+
reason: string;
|
|
98
|
+
}) => void;
|
|
86
99
|
}
|
|
87
100
|
/**
|
|
88
101
|
* Directories a walk does not enter. Kept as short as the evidence allows: a
|
|
@@ -186,13 +199,65 @@ declare function cosine(a: Float32Array, b: Float32Array): number;
|
|
|
186
199
|
declare function find(options: FindOptions): Promise<FindResult>;
|
|
187
200
|
|
|
188
201
|
/**
|
|
189
|
-
*
|
|
202
|
+
* Skills laid out as an agent plugin marketplace: a directory holding
|
|
203
|
+
* `.claude-plugin/marketplace.json`, whose plugins keep skills at
|
|
204
|
+
* `skills/<skill>/SKILL.md`. No package.json is involved, which is why the
|
|
205
|
+
* node_modules walk never saw them.
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
type MetadataValue = string | readonly string[];
|
|
209
|
+
/** Why a skill was left out rather than served. */
|
|
210
|
+
interface Rejection {
|
|
211
|
+
readonly path: string;
|
|
212
|
+
readonly reason: string;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* The `metadata:` block of a frontmatter, one level deep: scalars and inline
|
|
216
|
+
* lists. Deeper nesting is skipped rather than half-read.
|
|
217
|
+
*/
|
|
218
|
+
declare function readMetadata(source: string): Record<string, MetadataValue>;
|
|
219
|
+
/** The raw frontmatter text between the fences, for skill_describe. */
|
|
220
|
+
declare function readFrontmatterText(source: string): string;
|
|
221
|
+
/**
|
|
222
|
+
* Every skill one marketplace lists. A skill whose own tier disagrees with the
|
|
223
|
+
* marketplace's is rejected: a mislabelled tier is how a private skill leaks.
|
|
224
|
+
*/
|
|
225
|
+
declare function readMarketplace(dir: string, onReject?: (rejection: Rejection) => void): SkillEntry[];
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The five tools, and nothing else.
|
|
190
229
|
*
|
|
191
230
|
* The point of the server is that a session's startup cost does not grow with
|
|
192
|
-
* the number of skills installed: the host lists
|
|
231
|
+
* the number of skills installed: the host lists five tools whatever the
|
|
193
232
|
* catalog holds, and a body is read only when one is asked for.
|
|
194
233
|
*/
|
|
195
234
|
|
|
235
|
+
/** Largest file skill_read returns. A skill needing more should split it. */
|
|
236
|
+
declare const READ_BUDGET_BYTES: number;
|
|
237
|
+
/** How many files skill_describe lists before saying the rest were cut. */
|
|
238
|
+
declare const DESCRIBE_FILE_LIMIT = 200;
|
|
239
|
+
declare const CATALOG_PAGE_SIZE = 8;
|
|
240
|
+
declare const CATALOG_PAGE_MAX = 20;
|
|
241
|
+
/** Equality filters over catalog fields. Unset keys match everything. */
|
|
242
|
+
interface SkillFilters {
|
|
243
|
+
readonly tier?: string;
|
|
244
|
+
readonly package?: string;
|
|
245
|
+
readonly level?: string;
|
|
246
|
+
readonly domain?: string;
|
|
247
|
+
readonly medium?: string;
|
|
248
|
+
}
|
|
249
|
+
type ReadResult = {
|
|
250
|
+
readonly ok: true;
|
|
251
|
+
readonly name: string;
|
|
252
|
+
readonly path: string;
|
|
253
|
+
readonly bytes: number;
|
|
254
|
+
readonly sha256: string;
|
|
255
|
+
readonly text: string;
|
|
256
|
+
} | {
|
|
257
|
+
readonly ok: false;
|
|
258
|
+
readonly error: string;
|
|
259
|
+
readonly detail: string;
|
|
260
|
+
};
|
|
196
261
|
interface SkillServerOptions extends CatalogOptions {
|
|
197
262
|
readonly embedder?: Embedder;
|
|
198
263
|
readonly cache?: IntentCache;
|
|
@@ -202,11 +267,15 @@ interface SkillServerOptions extends CatalogOptions {
|
|
|
202
267
|
}
|
|
203
268
|
interface CatalogResponse {
|
|
204
269
|
readonly count: number;
|
|
270
|
+
readonly page: number;
|
|
271
|
+
readonly totalPages: number;
|
|
272
|
+
readonly hasNext: boolean;
|
|
205
273
|
readonly packages: readonly {
|
|
206
274
|
readonly package: string;
|
|
207
275
|
readonly skills: readonly {
|
|
208
276
|
readonly name: string;
|
|
209
277
|
readonly description: string;
|
|
278
|
+
readonly tier?: string;
|
|
210
279
|
}[];
|
|
211
280
|
}[];
|
|
212
281
|
}
|
|
@@ -222,10 +291,37 @@ interface CallResponse {
|
|
|
222
291
|
* speak a protocol to get them.
|
|
223
292
|
*/
|
|
224
293
|
declare function createSkillTools(options: SkillServerOptions): {
|
|
225
|
-
/**
|
|
226
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Grouped, and without bodies. The cheap overview and the search's miss
|
|
296
|
+
* path. Paged by package so a large catalog never arrives in one answer.
|
|
297
|
+
*/
|
|
298
|
+
catalog(request?: {
|
|
299
|
+
page?: number;
|
|
300
|
+
pageSize?: number;
|
|
301
|
+
tier?: string;
|
|
302
|
+
}): CatalogResponse;
|
|
227
303
|
/** Ranked names. Returns; never loads a body. */
|
|
228
|
-
find(intent: string, limit?: number): Promise<FindResult>;
|
|
304
|
+
find(intent: string, limit?: number, filters?: SkillFilters): Promise<FindResult>;
|
|
305
|
+
/** Every property of one skill and the files it carries, without bodies. */
|
|
306
|
+
describe(name: string): {
|
|
307
|
+
name: string;
|
|
308
|
+
package: string;
|
|
309
|
+
description: string;
|
|
310
|
+
tier: string | undefined;
|
|
311
|
+
metadata: Readonly<Record<string, string | readonly string[]>>;
|
|
312
|
+
frontmatter: string;
|
|
313
|
+
files: {
|
|
314
|
+
path: string;
|
|
315
|
+
bytes: number;
|
|
316
|
+
sha256: string;
|
|
317
|
+
}[];
|
|
318
|
+
filesTruncated: boolean;
|
|
319
|
+
} | null;
|
|
320
|
+
/**
|
|
321
|
+
* One file inside a skill's directory. Paths that leave the directory,
|
|
322
|
+
* directly or through a link, are refused; nothing is ever executed.
|
|
323
|
+
*/
|
|
324
|
+
read(name: string, path?: string): ReadResult;
|
|
229
325
|
/** One body, at the moment it is needed. */
|
|
230
326
|
call(name: string): CallResponse | null;
|
|
231
327
|
/** Drops the memoised catalog, so the next call re-reads the tree. */
|
|
@@ -235,29 +331,29 @@ declare function createSkillTools(options: SkillServerOptions): {
|
|
|
235
331
|
type SkillTools = ReturnType<typeof createSkillTools>;
|
|
236
332
|
|
|
237
333
|
/**
|
|
238
|
-
* The
|
|
334
|
+
* The five tools, spoken over MCP.
|
|
239
335
|
*
|
|
240
336
|
* Thin on purpose: every decision is in `createSkillTools`, and this file only
|
|
241
337
|
* names the tools and shapes their arguments. A consumer that wants the same
|
|
242
|
-
*
|
|
243
|
-
*
|
|
338
|
+
* operations from a hook or a script uses the tools directly and never speaks
|
|
339
|
+
* a protocol.
|
|
244
340
|
*/
|
|
245
341
|
|
|
246
342
|
/** Reported to the host on connect. */
|
|
247
343
|
declare const SERVER_NAME = "pmcp";
|
|
248
344
|
/**
|
|
249
|
-
* Registers the
|
|
345
|
+
* Registers the five tools on a server.
|
|
250
346
|
*
|
|
251
347
|
* Exported separately from the stdio entry so a consumer already running an MCP
|
|
252
348
|
* server can add these to it rather than starting a second process.
|
|
253
349
|
*/
|
|
254
350
|
declare function registerSkillTools(server: McpServer, tools: SkillTools): McpServer;
|
|
255
351
|
/**
|
|
256
|
-
* A server with the
|
|
352
|
+
* A server with the five tools registered.
|
|
257
353
|
*
|
|
258
354
|
* The catalog is read on first use rather than here, so a host that connects
|
|
259
355
|
* and never asks pays nothing for the walk.
|
|
260
356
|
*/
|
|
261
357
|
declare function createSkillServer(options: SkillServerOptions): McpServer;
|
|
262
358
|
|
|
263
|
-
export { type CallResponse, type CatalogOptions, type CatalogResponse, DEFAULT_FIND_LIMIT, DEFAULT_INTENT_CACHE_LIMIT, type Embedder, type FindOptions, type FindResult, type IntentCache, type IntentCacheOptions, type IntentCacheStats, MAX_SKILL_DEPTH, type Match, type Ranking, SERVER_NAME, SKIPPED_DIRS, type SkillEntry, type SkillServerOptions, type SkillTools, cosine, createSkillServer, createSkillTools, displayPath, find, lexicalScore, normaliseIntent, openIntentCache, readBody, readCatalog, readFrontmatter, registerSkillTools, withoutBody };
|
|
359
|
+
export { CATALOG_PAGE_MAX, CATALOG_PAGE_SIZE, type CallResponse, type CatalogOptions, type CatalogResponse, DEFAULT_FIND_LIMIT, DEFAULT_INTENT_CACHE_LIMIT, DESCRIBE_FILE_LIMIT, type Embedder, type FindOptions, type FindResult, type IntentCache, type IntentCacheOptions, type IntentCacheStats, MAX_SKILL_DEPTH, type Match, type MetadataValue, READ_BUDGET_BYTES, type Ranking, type ReadResult, type Rejection, SERVER_NAME, SKIPPED_DIRS, type SkillEntry, type SkillFilters, type SkillServerOptions, type SkillTools, cosine, createSkillServer, createSkillTools, displayPath, find, lexicalScore, normaliseIntent, openIntentCache, readBody, readCatalog, readFrontmatter, readFrontmatterText, readMarketplace, readMetadata, registerSkillTools, withoutBody };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_INTENT_CACHE_LIMIT,
|
|
3
3
|
openIntentCache
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2NOO5RSP.js";
|
|
5
5
|
import {
|
|
6
|
+
CATALOG_PAGE_MAX,
|
|
7
|
+
CATALOG_PAGE_SIZE,
|
|
6
8
|
DEFAULT_FIND_LIMIT,
|
|
9
|
+
DESCRIBE_FILE_LIMIT,
|
|
7
10
|
MAX_SKILL_DEPTH,
|
|
11
|
+
READ_BUDGET_BYTES,
|
|
8
12
|
SERVER_NAME,
|
|
9
13
|
SKIPPED_DIRS,
|
|
10
14
|
cosine,
|
|
@@ -17,13 +21,20 @@ import {
|
|
|
17
21
|
readBody,
|
|
18
22
|
readCatalog,
|
|
19
23
|
readFrontmatter,
|
|
24
|
+
readFrontmatterText,
|
|
25
|
+
readMarketplace,
|
|
26
|
+
readMetadata,
|
|
20
27
|
registerSkillTools,
|
|
21
28
|
withoutBody
|
|
22
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3NNRQ5A4.js";
|
|
23
30
|
export {
|
|
31
|
+
CATALOG_PAGE_MAX,
|
|
32
|
+
CATALOG_PAGE_SIZE,
|
|
24
33
|
DEFAULT_FIND_LIMIT,
|
|
25
34
|
DEFAULT_INTENT_CACHE_LIMIT,
|
|
35
|
+
DESCRIBE_FILE_LIMIT,
|
|
26
36
|
MAX_SKILL_DEPTH,
|
|
37
|
+
READ_BUDGET_BYTES,
|
|
27
38
|
SERVER_NAME,
|
|
28
39
|
SKIPPED_DIRS,
|
|
29
40
|
cosine,
|
|
@@ -37,6 +48,9 @@ export {
|
|
|
37
48
|
readBody,
|
|
38
49
|
readCatalog,
|
|
39
50
|
readFrontmatter,
|
|
51
|
+
readFrontmatterText,
|
|
52
|
+
readMarketplace,
|
|
53
|
+
readMetadata,
|
|
40
54
|
registerSkillTools,
|
|
41
55
|
withoutBody
|
|
42
56
|
};
|
package/dist/stdio.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/** `node_modules` roots to walk, from argv or from the working directory. */
|
|
10
10
|
declare function resolveRoots(argv: readonly string[], cwd: string): string[];
|
|
11
|
-
declare function serve(roots: readonly string[], scopes?: readonly string[]): void;
|
|
11
|
+
declare function serve(roots: readonly string[], scopes?: readonly string[], marketplaces?: readonly string[]): void;
|
|
12
12
|
declare function main(argv?: readonly string[]): void;
|
|
13
13
|
|
|
14
14
|
export { main, resolveRoots, serve };
|
package/dist/stdio.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modootoday/pmcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"author": "modootoday",
|
|
6
6
|
"description": "An MCP server that finds the skills your installed packages already ship. Reads SKILL.md out of node_modules by shape rather than by path, so it sees the skills, .agent, .claude, .gemini and .codex conventions alike, and keeps session startup flat as the number of installed skills grows.",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
],
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsup",
|
|
60
|
-
"typecheck": "
|
|
60
|
+
"typecheck": "tsgo --noEmit --incremental --tsBuildInfoFile ./dist/.tsbuildinfo --singleThreaded && tsgo -p tsconfig.tests.json --noEmit --singleThreaded",
|
|
61
61
|
"test": "vitest run",
|
|
62
62
|
"clean": "rimraf dist",
|
|
63
63
|
"catalog:refresh": "node scripts/refresh-catalog.mjs",
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/node": "^22.15.21",
|
|
86
86
|
"@types/semver": "7.8.0",
|
|
87
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
87
88
|
"prettier": "^3.6.2",
|
|
88
89
|
"rimraf": "^6.0.1",
|
|
89
90
|
"tsup": "^8.5.1",
|
|
@@ -5,9 +5,9 @@ description: A project has grown past a hundred dependencies and nobody knows wh
|
|
|
5
5
|
|
|
6
6
|
# pmcp
|
|
7
7
|
|
|
8
|
-
An MCP server that reads `SKILL.md` files out of `node_modules` and
|
|
9
|
-
as
|
|
10
|
-
whole catalog.
|
|
8
|
+
An MCP server that reads `SKILL.md` files out of `node_modules` and plugin
|
|
9
|
+
marketplaces and serves them as five tools, so a session pays for the one skill
|
|
10
|
+
it opens rather than for the whole catalog.
|
|
11
11
|
|
|
12
12
|
## When to reach for it
|
|
13
13
|
|
|
@@ -108,11 +108,13 @@ discovery will and will not walk.
|
|
|
108
108
|
|
|
109
109
|
### Tools on the wire
|
|
110
110
|
|
|
111
|
-
| Tool
|
|
112
|
-
|
|
|
113
|
-
| `skill_catalog`
|
|
114
|
-
| `skill_find`
|
|
115
|
-
| `
|
|
111
|
+
| Tool | Argument | Returns |
|
|
112
|
+
| ---------------- | ------------------------------------------------- | ------------------------------------ |
|
|
113
|
+
| `skill_catalog` | optional `page`, `pageSize`, `tier` | each skill's name, description, tier |
|
|
114
|
+
| `skill_find` | `intent`, a sentence; optional `limit`, `filters` | ranked matches |
|
|
115
|
+
| `skill_describe` | `name` | metadata and files, no body |
|
|
116
|
+
| `skill_call` | `name` | that skill's body |
|
|
117
|
+
| `skill_read` | `name`, optional `path` | one file inside the skill, as text |
|
|
116
118
|
|
|
117
119
|
## Worked examples
|
|
118
120
|
|