@modootoday/pmcp 0.1.4 → 0.3.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 CHANGED
@@ -1,8 +1,11 @@
1
1
  # pmcp
2
2
 
3
3
  Find and use package skills without loading every document into your agent's context.
4
- `pmcp` reads installed `SKILL.md` files and exposes three MCP tools: `skill_catalog`,
5
- `skill_find`, and `skill_call`.
4
+ `pmcp` reads `SKILL.md` files from installed packages, from monorepo workspaces
5
+ (`--workspace <dir>`: the root and every member its `workspaces` globs name, nested
6
+ workspace roots included), from single package directories (`--package <dir>`), and
7
+ from plugin marketplaces (`--marketplace <dir>`), and exposes five MCP tools: `skill_catalog`, `skill_find`,
8
+ `skill_describe`, `skill_call`, and `skill_read`.
6
9
 
7
10
  ## Install
8
11
 
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The skills the installed packages brought with them.
3
+ *
4
+ * Derived from `node_modules` at read time rather than from a list somebody
5
+ * maintains: installing a package is how its skill arrives and uninstalling it
6
+ * is how the skill leaves, so the catalog is always true of the project.
7
+ */
8
+ interface SkillEntry {
9
+ /** `<package>/<slug>`. Unique, and stable while the package is installed. */
10
+ readonly name: string;
11
+ readonly package: string;
12
+ readonly slug: string;
13
+ /** Frontmatter description. The only text `find` ranks against. */
14
+ readonly description: string;
15
+ /** Absolute path to the SKILL.md. `call` reads the body from here. */
16
+ readonly path: string;
17
+ /** open, free or paid. Set for marketplace skills, absent for packages. */
18
+ readonly tier?: string;
19
+ /** The frontmatter `metadata:` block, one level deep. */
20
+ readonly metadata?: Readonly<Record<string, string | readonly string[]>>;
21
+ /** Extra search terms. Ranked with the description, never used as triggers. */
22
+ readonly keywords?: readonly string[];
23
+ }
24
+ interface CatalogOptions {
25
+ /** Directories to walk. Each is a `node_modules` root, not a package root. */
26
+ readonly roots: readonly string[];
27
+ /** Package name prefixes to consider. Empty means every package. */
28
+ readonly scopes?: readonly string[];
29
+ /** Marketplace directories, each holding .claude-plugin/marketplace.json. */
30
+ readonly marketplaces?: readonly string[];
31
+ /** Package directories read directly, for a package no node_modules links. */
32
+ readonly packages?: readonly string[];
33
+ /** Workspace roots: the root and every member its workspaces globs name. */
34
+ readonly workspaces?: readonly string[];
35
+ /** Told about every marketplace skill left out, and why. */
36
+ readonly onReject?: (rejection: {
37
+ path: string;
38
+ reason: string;
39
+ }) => void;
40
+ }
41
+ /**
42
+ * Directories a walk does not enter. Kept as short as the evidence allows: a
43
+ * name here is a package whose skill will never be found, and the cost of one
44
+ * extra readdir is far below the cost of missing a skill. Measured 20260906 --
45
+ * `lib` was on this list and hid playwright's `lib/skill/SKILL.md`, which is
46
+ * the most widely installed skill in the real world.
47
+ */
48
+ declare const SKIPPED_DIRS: ReadonlySet<string>;
49
+ /**
50
+ * How deep below a package root a SKILL.md is looked for. Three reaches every
51
+ * convention in use (skills, .agent/skills, .claude/skills, .gemini/skills,
52
+ * .codex/skills); four was measured to find nothing more.
53
+ */
54
+ declare const MAX_SKILL_DEPTH = 3;
55
+ /**
56
+ * Reads `name` and `description` out of YAML frontmatter without a parser.
57
+ *
58
+ * A parser is a dependency this server does not otherwise need, and the two
59
+ * fields it wants are flat scalars on their own line. Anything more nested is
60
+ * not read, which is the honest limit rather than a partial YAML.
61
+ */
62
+ declare function readFrontmatter(source: string): Record<string, string>;
63
+ /**
64
+ * The body after the frontmatter, or the whole file when there is none.
65
+ *
66
+ * The slice starts at the newline terminating the closing `---`, and a blank
67
+ * line after it is separator rather than content, so both are dropped.
68
+ */
69
+ declare function readBody(source: string): string;
70
+ /**
71
+ * Every skill reachable from the given roots, sorted by name.
72
+ *
73
+ * A package with no skills directory contributes nothing and costs one
74
+ * `existsSync` per convention. A skill with no description is skipped rather
75
+ * than listed:
76
+ * `find` ranks descriptions, so one without a description can only ever be
77
+ * found by already knowing its name, and listing it would spend a session's
78
+ * tokens on an entry that cannot answer.
79
+ */
80
+ declare function readCatalog(options: CatalogOptions): SkillEntry[];
81
+ /** A catalog entry without its body, which is what `catalog` returns. */
82
+ declare function withoutBody({ path, ...rest }: SkillEntry): Omit<SkillEntry, "path">;
83
+ /** Path relative to a root, for a message a reader can act on. */
84
+ declare function displayPath(root: string, entry: SkillEntry): string;
85
+
86
+ export { type CatalogOptions as C, MAX_SKILL_DEPTH as M, type SkillEntry as S, SKIPPED_DIRS as a, readCatalog as b, readFrontmatter as c, displayPath as d, readBody as r, withoutBody as w };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normaliseIntent
3
- } from "./chunk-N3SHKKWG.js";
3
+ } from "./chunk-SPWHSHOC.js";
4
4
 
5
5
  // src/cache.ts
6
6
  async function openDatabase(path) {
@@ -131,4 +131,4 @@ export {
131
131
  DEFAULT_INTENT_CACHE_LIMIT,
132
132
  openIntentCache
133
133
  };
134
- //# sourceMappingURL=chunk-SLTUWTII.js.map
134
+ //# sourceMappingURL=chunk-MBAXK4IZ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createSkillServer
3
- } from "./chunk-N3SHKKWG.js";
3
+ } from "./chunk-SPWHSHOC.js";
4
4
 
5
5
  // src/stdio.ts
6
6
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
@@ -8,8 +8,12 @@ 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 = scopes.length > 0 ? { roots, scopes } : { roots };
11
+ function serve(catalog) {
12
+ const options = {
13
+ ...catalog,
14
+ onReject: ({ path, reason }) => process.stderr.write(`pmcp: skipped ${path}: ${reason}
15
+ `)
16
+ };
13
17
  serveStdio(() => createSkillServer(options), {
14
18
  // stdout is the protocol. A diagnostic written there corrupts the stream,
15
19
  // so out-of-band errors go to stderr and nowhere else.
@@ -19,10 +23,11 @@ function serve(roots, scopes = []) {
19
23
  }
20
24
  function main(argv = process.argv.slice(2)) {
21
25
  const scopeArg = argv.find((arg) => arg.startsWith("--scope="));
22
- serve(
23
- resolveRoots(argv, process.cwd()),
24
- scopeArg ? scopeArg.slice("--scope=".length).split(",") : []
25
- );
26
+ const scopes = scopeArg ? scopeArg.slice("--scope=".length).split(",") : [];
27
+ serve({
28
+ roots: resolveRoots(argv, process.cwd()),
29
+ ...scopes.length > 0 ? { scopes } : {}
30
+ });
26
31
  }
27
32
 
28
33
  export {
@@ -30,4 +35,4 @@ export {
30
35
  serve,
31
36
  main
32
37
  };
33
- //# sourceMappingURL=chunk-AJNIMNCV.js.map
38
+ //# sourceMappingURL=chunk-QJS3NYLT.js.map