@emseepea/create-resources-and-prompts-server 0.0.2 → 0.0.4
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 +51 -10
- package/{dist → initializer-dist}/template/README.md +1 -1
- package/initializer-dist/template/eval/meaning.test.mjs +25 -0
- package/{dist → initializer-dist}/template/package.json +7 -6
- package/{dist/template/src/capabilities/prompt.brew-guide.ts → initializer-dist/template/src/capabilities/prompt.growing-guide.ts} +5 -5
- package/{dist → initializer-dist}/template/src/capabilities/resource.getting-started.ts +3 -3
- package/{dist/template/src/capabilities/resource.method-guide.ts → initializer-dist/template/src/capabilities/resource.planting-guide.ts} +5 -5
- package/{dist → initializer-dist}/template/src/server.ts +1 -1
- package/{dist → initializer-dist}/template/test/server.test.mjs +8 -8
- package/package.json +29 -14
- package/dist/template/eval/meaning.test.mjs +0 -25
- /package/{dist → initializer-dist}/LICENSE +0 -0
- /package/{dist → initializer-dist}/create.mjs +0 -0
- /package/{dist → initializer-dist}/template/tsconfig.json +0 -0
package/README.md
CHANGED
|
@@ -1,22 +1,63 @@
|
|
|
1
1
|
# `@emseepea/create-resources-and-prompts-server`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
The package builds its starter from the maintained
|
|
5
|
-
[resources and prompts example](https://github.com/emseepea/emseepea/tree/main/examples/resources-prompts).
|
|
3
|
+
This directory is both the maintained example and its public npm initializer.
|
|
6
4
|
|
|
7
|
-
##
|
|
5
|
+
## Use This Template
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
Use this template to publish readable resources, parameterized resource
|
|
8
|
+
addresses, reusable prompts, and prompt-field suggestions. Choose the
|
|
9
|
+
[tool server](../tool-server/README.md) when the model needs to call an
|
|
10
|
+
operation instead of reading material or rendering a prompt. [Compare all eight templates](https://emseepea.github.io/emseepea/examples/).
|
|
11
|
+
|
|
12
|
+
## Create a Project
|
|
11
13
|
|
|
12
14
|
```sh
|
|
13
|
-
npm init @emseepea/resources-and-prompts-server
|
|
15
|
+
npm init @emseepea/resources-and-prompts-server -- my-server
|
|
14
16
|
```
|
|
15
17
|
|
|
18
|
+
<!-- generated-project-readme -->
|
|
19
|
+
|
|
20
|
+
## Resources and Prompts Example
|
|
21
|
+
|
|
22
|
+
Choose this example when you want to give an assistant reusable reference
|
|
23
|
+
content and guided starting questions, without adding another tool.
|
|
24
|
+
|
|
25
|
+
It provides:
|
|
26
|
+
|
|
27
|
+
- a fixed resource at one known address
|
|
28
|
+
- a resource pattern for related content at predictable addresses
|
|
29
|
+
- a reusable prompt with one checked argument
|
|
30
|
+
- optional suggestions for the resource and prompt fields
|
|
31
|
+
|
|
32
|
+
## Run
|
|
33
|
+
|
|
34
|
+
From this directory:
|
|
35
|
+
|
|
16
36
|
```sh
|
|
17
|
-
cd my-server
|
|
18
37
|
npm install
|
|
19
|
-
npm
|
|
20
|
-
npm run lint
|
|
38
|
+
npm run build
|
|
21
39
|
npm start
|
|
22
40
|
```
|
|
41
|
+
|
|
42
|
+
The server listens on `http://127.0.0.1:3000/mcp` by default. Set `PORT` to
|
|
43
|
+
choose another port.
|
|
44
|
+
|
|
45
|
+
## Check This Example
|
|
46
|
+
|
|
47
|
+
[Ordinary tests](test/) live in `test/`.
|
|
48
|
+
The [AI understanding test](eval/meaning.test.mjs) lives separately in `eval/`.
|
|
49
|
+
The commands below run each suite independently.
|
|
50
|
+
|
|
51
|
+
Run its build and MCP resource and prompt checks:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
npm test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Check that Claude keeps sowing depth and plant spacing distinct:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npm run test:llm
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If Claude is not already signed in, run `claude auth login` first.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { semanticTest } from "@emseepea/testing/semantic";
|
|
3
|
+
|
|
4
|
+
semanticTest("Sowing depth and plant spacing remain separate concepts", {
|
|
5
|
+
server: new URL("../dist/server.js", import.meta.url),
|
|
6
|
+
question:
|
|
7
|
+
"If I sow pea seeds deeper, should I also space the plants farther apart? " +
|
|
8
|
+
"Explain the distinction for a home gardener.",
|
|
9
|
+
criticalFacts: [
|
|
10
|
+
"sowing depth",
|
|
11
|
+
"plant spacing"
|
|
12
|
+
],
|
|
13
|
+
criteria:
|
|
14
|
+
"The answer says sowing peas deeper does not mean spacing the plants farther " +
|
|
15
|
+
"apart. It explains that sowing depth is how deep a seed goes while plant " +
|
|
16
|
+
"spacing is the gap between plants, and it does not treat the measurements as " +
|
|
17
|
+
"interchangeable.",
|
|
18
|
+
requiredPaths: ["resources/read:guide://peas/getting-started","prompts/get:growing-guide"],
|
|
19
|
+
async exercise(client) {
|
|
20
|
+
const result1 = await client.readResource({"uri":"guide://peas/getting-started"});
|
|
21
|
+
assert.ok(result1);
|
|
22
|
+
const result2 = await client.getPrompt({"name":"growing-guide","arguments":{"topic":"sowing-depth"}});
|
|
23
|
+
assert.ok(result2);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emseepea-starter",
|
|
3
3
|
"version": "0.0.0",
|
|
4
|
-
"
|
|
4
|
+
"description": "Create an Em See Pea server with resources and prompts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -13,17 +13,18 @@
|
|
|
13
13
|
"test:llm:built": "emseepea-test eval",
|
|
14
14
|
"lint": "oxlint src test eval"
|
|
15
15
|
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@emseepea/server": "0.1.0",
|
|
18
|
-
"zod": "4.4.3"
|
|
19
|
-
},
|
|
20
16
|
"devDependencies": {
|
|
21
|
-
"@emseepea/testing": "0.2.
|
|
17
|
+
"@emseepea/testing": "0.2.2",
|
|
22
18
|
"@types/node": "24.13.3",
|
|
23
19
|
"typescript": "6.0.3",
|
|
24
20
|
"oxlint": "1.80.0"
|
|
25
21
|
},
|
|
26
22
|
"engines": {
|
|
27
23
|
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"private": true,
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@emseepea/server": "0.2.2",
|
|
28
|
+
"zod": "4.4.3"
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { definePrompt, type CapabilityModuleFactory } from "@emseepea/server";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
-
const topics = ["
|
|
4
|
+
const topics = ["sowing-depth", "plant-spacing", "trellis-support"];
|
|
5
5
|
|
|
6
6
|
export default (() => definePrompt({
|
|
7
|
-
name: "
|
|
8
|
-
title: "
|
|
9
|
-
description: "Create a prompt for a sample
|
|
7
|
+
name: "growing-guide",
|
|
8
|
+
title: "Pea growing guide",
|
|
9
|
+
description: "Create a prompt for a sample pea-growing topic.",
|
|
10
10
|
argsSchema: z.object({ topic: z.string().min(1) }),
|
|
11
11
|
complete: {
|
|
12
12
|
topic: (value) => topics.filter((topic) => topic.startsWith(value)),
|
|
@@ -17,7 +17,7 @@ export default (() => definePrompt({
|
|
|
17
17
|
role: "user",
|
|
18
18
|
content: {
|
|
19
19
|
type: "text",
|
|
20
|
-
text: `Explain ${topic} for a home
|
|
20
|
+
text: `Explain ${topic} for a home gardener. Distinguish any commonly confused concepts.`,
|
|
21
21
|
},
|
|
22
22
|
}],
|
|
23
23
|
}),
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { defineResource, type CapabilityModuleFactory } from "@emseepea/server";
|
|
2
2
|
|
|
3
|
-
const guideUri = "guide://
|
|
3
|
+
const guideUri = "guide://peas/getting-started";
|
|
4
4
|
|
|
5
5
|
export default (() => defineResource({
|
|
6
6
|
name: "getting-started",
|
|
7
7
|
uri: guideUri,
|
|
8
|
-
title: "
|
|
8
|
+
title: "Pea growing: getting started",
|
|
9
9
|
description: "A sample guide exposed as an MCP resource.",
|
|
10
10
|
mimeType: "text/markdown",
|
|
11
11
|
handler: () => ({
|
|
12
12
|
contents: [{
|
|
13
13
|
uri: guideUri,
|
|
14
14
|
mimeType: "text/markdown",
|
|
15
|
-
text: "#
|
|
15
|
+
text: "# Plant peas clearly\n\nSowing depth is how deep a seed goes; plant spacing is the gap between plants. They are separate choices, not interchangeable measurements.\n",
|
|
16
16
|
}],
|
|
17
17
|
}),
|
|
18
18
|
})) satisfies CapabilityModuleFactory;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { defineResourceTemplate, type CapabilityModuleFactory } from "@emseepea/server";
|
|
2
2
|
|
|
3
|
-
const methods = ["
|
|
3
|
+
const methods = ["container", "raised-bed", "row"];
|
|
4
4
|
|
|
5
5
|
export default (() => defineResourceTemplate({
|
|
6
|
-
name: "
|
|
7
|
-
uriTemplate: "guide://
|
|
8
|
-
title: "
|
|
9
|
-
description: "A sample guide selected by
|
|
6
|
+
name: "planting-guide",
|
|
7
|
+
uriTemplate: "guide://peas/planting/{method}",
|
|
8
|
+
title: "Pea planting guide",
|
|
9
|
+
description: "A sample guide selected by planting method.",
|
|
10
10
|
mimeType: "text/markdown",
|
|
11
11
|
complete: {
|
|
12
12
|
method: (value) => methods.filter((method) => method.startsWith(value)),
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@emseepea/server";
|
|
6
6
|
|
|
7
7
|
const running = await serveEmseepea(createEmseepea({
|
|
8
|
-
name: "emseepea-resources-prompts",
|
|
8
|
+
name: "emseepea-resources-and-prompts-server",
|
|
9
9
|
version: "0.0.0",
|
|
10
10
|
...await discoverCapabilities(new URL("./capabilities/", import.meta.url)),
|
|
11
11
|
}), { port: Number.parseInt(process.env.PORT ?? "3000", 10) });
|
|
@@ -8,16 +8,16 @@ test("lists and reads the advertised resource and prompt", async (t) => {
|
|
|
8
8
|
const client = await running.connect();
|
|
9
9
|
|
|
10
10
|
assert.deepEqual((await client.listResources()).resources.map(({ uri }) => uri), [
|
|
11
|
-
"guide://
|
|
11
|
+
"guide://peas/getting-started",
|
|
12
12
|
]);
|
|
13
|
-
const resource = await client.readResource({ uri: "guide://
|
|
14
|
-
assert.match(resource.contents[0].text, /
|
|
15
|
-
assert.match(resource.contents[0].text, /
|
|
13
|
+
const resource = await client.readResource({ uri: "guide://peas/getting-started" });
|
|
14
|
+
assert.match(resource.contents[0].text, /Sowing depth is how deep a seed goes/);
|
|
15
|
+
assert.match(resource.contents[0].text, /plant spacing is the gap between plants/);
|
|
16
16
|
|
|
17
|
-
assert.deepEqual((await client.listPrompts()).prompts.map(({ name }) => name), ["
|
|
17
|
+
assert.deepEqual((await client.listPrompts()).prompts.map(({ name }) => name), ["growing-guide"]);
|
|
18
18
|
const prompt = await client.getPrompt({
|
|
19
|
-
name: "
|
|
20
|
-
arguments: { topic: "
|
|
19
|
+
name: "growing-guide",
|
|
20
|
+
arguments: { topic: "sowing-depth" },
|
|
21
21
|
});
|
|
22
|
-
assert.match(prompt.messages[0].content.text, /Explain
|
|
22
|
+
assert.match(prompt.messages[0].content.text, /Explain sowing-depth/);
|
|
23
23
|
});
|
package/package.json
CHANGED
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emseepea/create-resources-and-prompts-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Create an Em See Pea server with resources and prompts.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/emseepea/emseepea.git",
|
|
9
|
-
"directory": "packages/create-resources-and-prompts-server"
|
|
10
|
-
},
|
|
11
|
-
"homepage": "https://emseepea.github.io/emseepea/examples/",
|
|
12
|
-
"bugs": "https://github.com/emseepea/emseepea/issues",
|
|
13
|
-
"publishConfig": { "access": "public", "provenance": true, "tag": "next" },
|
|
14
6
|
"type": "module",
|
|
15
|
-
"
|
|
16
|
-
"files": ["dist"],
|
|
7
|
+
"starterDependencies": ["@emseepea/server", "zod"],
|
|
17
8
|
"scripts": {
|
|
18
|
-
"build": "
|
|
19
|
-
"
|
|
9
|
+
"build": "npm run build:example && npm run build:initializer",
|
|
10
|
+
"build:example": "tsc -p tsconfig.json",
|
|
11
|
+
"build:initializer": "node ../../scripts/build-initializer.mjs",
|
|
12
|
+
"start": "node dist/server.js",
|
|
13
|
+
"test": "npm run build && npm run test:built",
|
|
14
|
+
"test:built": "node --test test/*.test.mjs",
|
|
15
|
+
"test:llm": "npm run build && npm run test:llm:built",
|
|
16
|
+
"test:llm:built": "emseepea-test eval",
|
|
17
|
+
"lint": "oxlint src test eval",
|
|
18
|
+
"prepack": "npm run build:initializer"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@emseepea/server": "0.2.2",
|
|
22
|
+
"zod": "4.4.3",
|
|
23
|
+
"@emseepea/testing": "0.2.2",
|
|
24
|
+
"@types/node": "24.13.3",
|
|
25
|
+
"typescript": "6.0.3",
|
|
26
|
+
"oxlint": "1.80.0"
|
|
20
27
|
},
|
|
21
|
-
"engines": {
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
31
|
+
"repository": { "type": "git", "url": "git+https://github.com/emseepea/emseepea.git", "directory": "examples/resources-and-prompts-server" },
|
|
32
|
+
"homepage": "https://emseepea.github.io/emseepea/examples/",
|
|
33
|
+
"bugs": "https://github.com/emseepea/emseepea/issues",
|
|
34
|
+
"publishConfig": { "access": "public", "provenance": true },
|
|
35
|
+
"bin": { "create-resources-and-prompts-server": "./initializer-dist/create.mjs" },
|
|
36
|
+
"files": ["initializer-dist"]
|
|
22
37
|
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { semanticTest } from "@emseepea/testing/semantic";
|
|
3
|
-
|
|
4
|
-
semanticTest("Strength and extraction remain separate concepts", {
|
|
5
|
-
server: new URL("../dist/server.js", import.meta.url),
|
|
6
|
-
question:
|
|
7
|
-
"Does making coffee stronger necessarily mean that extraction is higher? " +
|
|
8
|
-
"Explain the distinction for a home brewer.",
|
|
9
|
-
criticalFacts: [
|
|
10
|
-
"concentration",
|
|
11
|
-
"extraction"
|
|
12
|
-
],
|
|
13
|
-
criteria:
|
|
14
|
-
"The answer says stronger coffee does not necessarily mean higher extraction. " +
|
|
15
|
-
"It explains that strength is concentration while extraction is how much " +
|
|
16
|
-
"material left the grounds, and it does not describe the concepts as " +
|
|
17
|
-
"interchangeable.",
|
|
18
|
-
requiredPaths: ["resources/read:guide://coffee/getting-started","prompts/get:brew-guide"],
|
|
19
|
-
async exercise(client) {
|
|
20
|
-
const result1 = await client.readResource({"uri":"guide://coffee/getting-started"});
|
|
21
|
-
assert.ok(result1);
|
|
22
|
-
const result2 = await client.getPrompt({"name":"brew-guide","arguments":{"topic":"brew-ratio"}});
|
|
23
|
-
assert.ok(result2);
|
|
24
|
-
},
|
|
25
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|