@modootoday/pmcp 0.7.1 → 0.8.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 +40 -9
- package/dist/{catalog-5v7jrGwP.d.ts → catalog-CS0j6-0U.d.ts} +11 -11
- package/dist/{chunk-IJPOJ6PG.js → chunk-LUBYOET7.js} +6 -3
- package/dist/{chunk-GNJSZCRH.js → chunk-M6LBYJDS.js} +37 -2
- package/dist/{chunk-KP3TQ3QY.js → chunk-OPDVUHTK.js} +2 -2
- package/dist/{chunk-VBLAH6J2.js → chunk-WSTCBVXW.js} +2 -2
- package/dist/{chunk-C46YCY2I.js → chunk-ZDV75HZN.js} +823 -389
- package/dist/cli.js +50 -11
- package/dist/http.d.ts +10 -2
- package/dist/http.js +5 -4
- package/dist/index.d.ts +119 -44
- package/dist/index.js +51 -6
- package/dist/server-CLyCpwZb.d.ts +352 -0
- package/dist/stdio.d.ts +7 -3
- package/dist/stdio.js +2 -2
- package/package.json +1 -1
- package/dist/server-B9GDPRoE.d.ts +0 -217
package/README.md
CHANGED
|
@@ -4,8 +4,9 @@ Find and use package skills without loading every document into your agent's con
|
|
|
4
4
|
`pmcp` reads `SKILL.md` files from installed packages, from monorepo workspaces
|
|
5
5
|
(`--workspace <dir>`: the root and every member its `workspaces` globs name, nested
|
|
6
6
|
workspace roots included), from single package directories (`--package <dir>`), and
|
|
7
|
-
from plugin marketplaces (`--marketplace <dir>`), and exposes
|
|
8
|
-
`skill_describe`, `skill_call`, and `
|
|
7
|
+
from plugin marketplaces (`--marketplace <dir>`), and exposes six MCP tools: `skill_catalog`, `skill_find`,
|
|
8
|
+
`skill_describe`, `skill_call`, `skill_read` and `skill_bundle`, plus every skill file as a
|
|
9
|
+
`skill://` resource and, on request, one prompt per skill.
|
|
9
10
|
|
|
10
11
|
## Install
|
|
11
12
|
|
|
@@ -121,7 +122,28 @@ Skills are discovered by filename, including `skills/`, `.agents/skills/`,
|
|
|
121
122
|
within the discovery depth. A skill needs a frontmatter `description` for search.
|
|
122
123
|
|
|
123
124
|
`skill_find` accepts a problem description and returns matching skills.
|
|
124
|
-
`skill_call` opens the selected document
|
|
125
|
+
`skill_call` opens the selected document and lists the reference, script and asset
|
|
126
|
+
files it carries, as text and as resource links. Local MCP reading requires no login.
|
|
127
|
+
|
|
128
|
+
Files keep their type, as the Agent Skills layout (`references/`, `scripts/`, `assets/`)
|
|
129
|
+
expects: `skill_read` returns text as text, images and audio as image and audio content,
|
|
130
|
+
and other binary files as an embedded resource with its media type; a file whose extension
|
|
131
|
+
names text but whose bytes are not UTF-8 goes out as a blob, so its sha256 stays exact.
|
|
132
|
+
Scripts are returned, never run: running them is the host's job, from a local copy of the
|
|
133
|
+
skill. `skill_bundle` lists every file of a skill as resource links that `resources/read`
|
|
134
|
+
returns, so a host can write the skill into a local skills directory without the bytes
|
|
135
|
+
passing through the model.
|
|
136
|
+
|
|
137
|
+
`skill_catalog`, `skill_find`, `skill_describe` and `skill_bundle` declare an
|
|
138
|
+
`outputSchema` and return `structuredContent` alongside the same JSON as text.
|
|
139
|
+
Frontmatter is read as YAML (folded and block descriptions, a BOM and CRLF are fine), and
|
|
140
|
+
`metadata` is read for every skill. Loading is lenient, as the client guide asks; what
|
|
141
|
+
breaks the specification is reported, and `pmcp validate [<skill-dir>...]` checks given
|
|
142
|
+
directories or every skill the catalog reaches (name rules and length, description and
|
|
143
|
+
compatibility length, field types, name matching the directory, duplicate names).
|
|
144
|
+
|
|
145
|
+
`pmcp serve --prompts` also offers one prompt per skill, for hosts that turn prompts into
|
|
146
|
+
commands; the prompt's text is the skill body and its file list, with an optional `task`.
|
|
125
147
|
|
|
126
148
|
Marketplace plugins also carry commands, agents, hooks and MCP servers.
|
|
127
149
|
Commands are listed as skills. The others are listed under their own kind and
|
|
@@ -132,15 +154,24 @@ are left out of `skill_catalog` and `skill_find` unless `kind` asks for them
|
|
|
132
154
|
## MCP Skills extension
|
|
133
155
|
|
|
134
156
|
The server also declares `io.modelcontextprotocol/skills` (SEP-2640): it
|
|
135
|
-
answers `skills/list` and `skills/get
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
157
|
+
answers `skills/list` and `skills/get` (both with `ttlMs` and `cacheScope`), with
|
|
158
|
+
a sha256 digest and size per file. A skill qualifies when its frontmatter passes the
|
|
159
|
+
Agent Skills specification and its `name` matches its directory, and it stays within
|
|
160
|
+
512 files and 16 MiB; the rest remain reachable through the tools.
|
|
161
|
+
|
|
162
|
+
Every file of every skill the caller may see is a `skill://pmcp/<package>/<name>/<file>`
|
|
163
|
+
resource: `resources/list` lists each skill's `SKILL.md`, `resources/read` returns any file
|
|
164
|
+
(text, or a blob with its media type), and the template completes skill names and paths.
|
|
165
|
+
List-change notifications and subscriptions are not offered: they need a session, and the
|
|
166
|
+
HTTP handler is stateless.
|
|
140
167
|
|
|
141
168
|
## Hosting over HTTP
|
|
142
169
|
|
|
143
|
-
`@modootoday/pmcp/http` serves the same
|
|
170
|
+
`@modootoday/pmcp/http` serves the same tools and resources over streamable HTTP for a hosted
|
|
171
|
+
catalog. Tools, resources, the Skills extension and prompts all read the same per-caller,
|
|
172
|
+
tier-filtered catalog, so a file of a skill a caller cannot list cannot be read either. The
|
|
173
|
+
extension's `cacheScope` is `private` there by default (`cacheScope` overrides it), and
|
|
174
|
+
`prompts: true` turns prompts on.
|
|
144
175
|
The host owns identity: `authorize(request)` returns the caller or `undefined` (answered 401),
|
|
145
176
|
and `tiersFor(caller)` decides which tiers that caller sees (default `open` and `free`; skills
|
|
146
177
|
without a tier count as `open`). The catalog is read once; call `reload()` after deploying new
|
|
@@ -48,6 +48,14 @@ interface CatalogOptions {
|
|
|
48
48
|
path: string;
|
|
49
49
|
reason: string;
|
|
50
50
|
}) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Told about a skill that is served but breaks the Agent Skills specification,
|
|
53
|
+
* or that lost a name collision. Loading stays lenient, as the client guide asks.
|
|
54
|
+
*/
|
|
55
|
+
readonly onWarning?: (warning: {
|
|
56
|
+
path: string;
|
|
57
|
+
reason: string;
|
|
58
|
+
}) => void;
|
|
51
59
|
}
|
|
52
60
|
/**
|
|
53
61
|
* Directories a walk does not enter. Kept as short as the evidence allows: a
|
|
@@ -64,19 +72,11 @@ declare const SKIPPED_DIRS: ReadonlySet<string>;
|
|
|
64
72
|
*/
|
|
65
73
|
declare const MAX_SKILL_DEPTH = 3;
|
|
66
74
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* A parser is a dependency this server does not otherwise need, and the two
|
|
70
|
-
* fields it wants are flat scalars on their own line. Anything more nested is
|
|
71
|
-
* not read, which is the honest limit rather than a partial YAML.
|
|
75
|
+
* Top-level scalar fields of a SKILL.md frontmatter, parsed as YAML, so a folded
|
|
76
|
+
* `description: >-` arrives as its text rather than as the indicator.
|
|
72
77
|
*/
|
|
73
78
|
declare function readFrontmatter(source: string): Record<string, string>;
|
|
74
|
-
/**
|
|
75
|
-
* The body after the frontmatter, or the whole file when there is none.
|
|
76
|
-
*
|
|
77
|
-
* The slice starts at the newline terminating the closing `---`, and a blank
|
|
78
|
-
* line after it is separator rather than content, so both are dropped.
|
|
79
|
-
*/
|
|
79
|
+
/** The body after the frontmatter, or the whole file when there is none. */
|
|
80
80
|
declare function readBody(source: string): string;
|
|
81
81
|
/**
|
|
82
82
|
* Every skill reachable from the given roots, sorted by name.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSkillServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZDV75HZN.js";
|
|
4
4
|
|
|
5
5
|
// src/stdio.ts
|
|
6
6
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
@@ -8,10 +8,13 @@ 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(catalog) {
|
|
11
|
+
function serve(catalog, serving = {}) {
|
|
12
12
|
const options = {
|
|
13
13
|
...catalog,
|
|
14
|
+
...serving,
|
|
14
15
|
onReject: ({ path, reason }) => process.stderr.write(`pmcp: skipped ${path}: ${reason}
|
|
16
|
+
`),
|
|
17
|
+
onWarning: ({ path, reason }) => process.stderr.write(`pmcp: warning ${path}: ${reason}
|
|
15
18
|
`)
|
|
16
19
|
};
|
|
17
20
|
serveStdio(() => createSkillServer(options), {
|
|
@@ -35,4 +38,4 @@ export {
|
|
|
35
38
|
serve,
|
|
36
39
|
main
|
|
37
40
|
};
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
41
|
+
//# sourceMappingURL=chunk-LUBYOET7.js.map
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
frontmatterObject,
|
|
3
|
+
readCatalog,
|
|
4
|
+
specProblems
|
|
5
|
+
} from "./chunk-ZDV75HZN.js";
|
|
6
|
+
|
|
1
7
|
// src/config.ts
|
|
2
8
|
import { existsSync, readFileSync } from "fs";
|
|
3
9
|
import { dirname, join, resolve } from "path";
|
|
@@ -1086,6 +1092,33 @@ function readSpec(config) {
|
|
|
1086
1092
|
return { root: config.dir, tools, skills, agents, packageRules, mcp };
|
|
1087
1093
|
}
|
|
1088
1094
|
|
|
1095
|
+
// src/validate.ts
|
|
1096
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, statSync } from "fs";
|
|
1097
|
+
import { basename, join as join6, resolve as resolve2 } from "path";
|
|
1098
|
+
function validateSkillDir(dir) {
|
|
1099
|
+
const root = resolve2(dir);
|
|
1100
|
+
const skillMd = basename(root) === "SKILL.md" ? root : join6(root, "SKILL.md");
|
|
1101
|
+
if (!existsSync6(skillMd) || !statSync(skillMd).isFile()) {
|
|
1102
|
+
return [{ path: root, reason: "no SKILL.md", level: "error" }];
|
|
1103
|
+
}
|
|
1104
|
+
const front = frontmatterObject(readFileSync5(skillMd, "utf8"));
|
|
1105
|
+
const directory = basename(skillMd === root ? join6(root, "..") : root);
|
|
1106
|
+
return specProblems(front, directory).map((reason) => ({
|
|
1107
|
+
path: skillMd,
|
|
1108
|
+
reason,
|
|
1109
|
+
level: "error"
|
|
1110
|
+
}));
|
|
1111
|
+
}
|
|
1112
|
+
function validateCatalog(options) {
|
|
1113
|
+
const findings = [];
|
|
1114
|
+
readCatalog({
|
|
1115
|
+
...options,
|
|
1116
|
+
onReject: (r) => findings.push({ ...r, level: "error" }),
|
|
1117
|
+
onWarning: (w) => findings.push({ ...w, level: "warning" })
|
|
1118
|
+
});
|
|
1119
|
+
return findings;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1089
1122
|
export {
|
|
1090
1123
|
CONFIG_FILE,
|
|
1091
1124
|
ConfigError,
|
|
@@ -1102,6 +1135,8 @@ export {
|
|
|
1102
1135
|
spawnRunner,
|
|
1103
1136
|
doctor,
|
|
1104
1137
|
TOOLS,
|
|
1105
|
-
readSpec
|
|
1138
|
+
readSpec,
|
|
1139
|
+
validateSkillDir,
|
|
1140
|
+
validateCatalog
|
|
1106
1141
|
};
|
|
1107
|
-
//# sourceMappingURL=chunk-
|
|
1142
|
+
//# sourceMappingURL=chunk-M6LBYJDS.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
normaliseIntent
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZDV75HZN.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-
|
|
134
|
+
//# sourceMappingURL=chunk-OPDVUHTK.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openDatabase
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OPDVUHTK.js";
|
|
4
4
|
|
|
5
5
|
// src/embed.ts
|
|
6
6
|
var DEFAULT_MODEL_ID = "Xenova/multilingual-e5-small";
|
|
@@ -157,4 +157,4 @@ export {
|
|
|
157
157
|
encodeEntries,
|
|
158
158
|
openEntryVectors
|
|
159
159
|
};
|
|
160
|
-
//# sourceMappingURL=chunk-
|
|
160
|
+
//# sourceMappingURL=chunk-WSTCBVXW.js.map
|