@emseepea/create-tool-server 0.0.3 → 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 +13 -4
- package/initializer-dist/template/README.md +3 -3
- package/initializer-dist/template/eval/meaning.test.mjs +12 -13
- package/initializer-dist/template/package.json +2 -2
- package/initializer-dist/template/src/capabilities/tool.get-pea-variety.ts +44 -0
- package/initializer-dist/template/src/server.ts +2 -2
- package/initializer-dist/template/test/server.test.mjs +9 -10
- package/package.json +5 -5
- package/initializer-dist/template/src/capabilities/tool.get-bean-details.ts +0 -47
package/README.md
CHANGED
|
@@ -2,8 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
This directory is both the maintained example and its public npm initializer.
|
|
4
4
|
|
|
5
|
+
## Use This Template
|
|
6
|
+
|
|
7
|
+
Use this template for the smallest server with one public, read-only tool and
|
|
8
|
+
no external service, sign-in, web page, progress stream, or shared storage.
|
|
9
|
+
Choose the [API-backed server](../api-backed-server/README.md) when the tool
|
|
10
|
+
must call a public web service. [Compare all eight templates](https://emseepea.github.io/emseepea/examples/).
|
|
11
|
+
|
|
12
|
+
## Create a Project
|
|
13
|
+
|
|
5
14
|
```sh
|
|
6
|
-
npm init @emseepea/tool-server
|
|
15
|
+
npm init @emseepea/tool-server -- my-server
|
|
7
16
|
```
|
|
8
17
|
|
|
9
18
|
<!-- generated-project-readme -->
|
|
@@ -13,8 +22,8 @@ npm init @emseepea/tool-server@next -- my-server
|
|
|
13
22
|
Choose this example when you want the smallest working server with one public,
|
|
14
23
|
read-only tool and no web page.
|
|
15
24
|
|
|
16
|
-
The `get-
|
|
17
|
-
See Pea checks the
|
|
25
|
+
The `get-pea-variety` tool returns useful details about one sample pea variety. Em
|
|
26
|
+
See Pea checks the input and result before returning them through the public
|
|
18
27
|
`@emseepea/server` API.
|
|
19
28
|
|
|
20
29
|
## What This Example Includes
|
|
@@ -52,7 +61,7 @@ Run its build and MCP checks:
|
|
|
52
61
|
npm test
|
|
53
62
|
```
|
|
54
63
|
|
|
55
|
-
Check that Claude chooses the
|
|
64
|
+
Check that Claude chooses the variety tool and understands its result:
|
|
56
65
|
|
|
57
66
|
```sh
|
|
58
67
|
npm run test:llm
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Choose this example when you want the smallest working server with one public,
|
|
4
4
|
read-only tool and no web page.
|
|
5
5
|
|
|
6
|
-
The `get-
|
|
7
|
-
See Pea checks the
|
|
6
|
+
The `get-pea-variety` tool returns useful details about one sample pea variety. Em
|
|
7
|
+
See Pea checks the input and result before returning them through the public
|
|
8
8
|
`@emseepea/server` API.
|
|
9
9
|
|
|
10
10
|
## What This Example Includes
|
|
@@ -42,7 +42,7 @@ Run its build and MCP checks:
|
|
|
42
42
|
npm test
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Check that Claude chooses the
|
|
45
|
+
Check that Claude chooses the variety tool and understands its result:
|
|
46
46
|
|
|
47
47
|
```sh
|
|
48
48
|
npm run test:llm
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { toolSelectionTest } from "@emseepea/testing/semantic";
|
|
2
2
|
|
|
3
|
-
toolSelectionTest("
|
|
3
|
+
toolSelectionTest("Pea variety details keep each concept distinct", {
|
|
4
4
|
server: new URL("../dist/server.js", import.meta.url),
|
|
5
5
|
question:
|
|
6
|
-
"For Highland
|
|
7
|
-
"
|
|
6
|
+
"For Highland Snap, give me its pea type, growth habit, days to maturity, and " +
|
|
7
|
+
"traits. Keep those concepts distinct.",
|
|
8
8
|
criticalFacts: [
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"cocoa"
|
|
9
|
+
"snap",
|
|
10
|
+
"climbing",
|
|
11
|
+
"70",
|
|
12
|
+
"edible pods",
|
|
13
|
+
"needs support"
|
|
15
14
|
],
|
|
16
15
|
criteria:
|
|
17
|
-
"The answer says Highland
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
expectedTools: ["get-
|
|
16
|
+
"The answer says Highland Snap is a snap pea with a climbing growth habit, " +
|
|
17
|
+
"matures in 70 days, has edible pods, and needs support. It does not confuse " +
|
|
18
|
+
"pea type, growth habit, maturity time, or traits.",
|
|
19
|
+
expectedTools: ["get-pea-variety"],
|
|
21
20
|
});
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"lint": "oxlint src test eval"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@emseepea/testing": "0.2.
|
|
17
|
+
"@emseepea/testing": "0.2.2",
|
|
18
18
|
"@types/node": "24.13.3",
|
|
19
19
|
"typescript": "6.0.3",
|
|
20
20
|
"oxlint": "1.80.0"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"private": true,
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@emseepea/server": "0.2.
|
|
27
|
+
"@emseepea/server": "0.2.2",
|
|
28
28
|
"zod": "4.4.3"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineTool, type CapabilityModuleFactory } from "@emseepea/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
const varietyNames = ["Harbour Gem", "Highland Snap"] as const;
|
|
5
|
+
const peaVarietySchema = z.object({
|
|
6
|
+
name: z.enum(varietyNames),
|
|
7
|
+
peaType: z.enum(["shelling", "snap"]),
|
|
8
|
+
growthHabit: z.enum(["bush", "climbing"]),
|
|
9
|
+
daysToMaturity: z.number().int().positive(),
|
|
10
|
+
traits: z.array(z.string()),
|
|
11
|
+
});
|
|
12
|
+
const varieties: Record<(typeof varietyNames)[number], z.input<typeof peaVarietySchema>> = {
|
|
13
|
+
"Harbour Gem": {
|
|
14
|
+
name: "Harbour Gem",
|
|
15
|
+
peaType: "shelling",
|
|
16
|
+
growthHabit: "bush",
|
|
17
|
+
daysToMaturity: 62,
|
|
18
|
+
traits: ["compact", "sweet peas"],
|
|
19
|
+
},
|
|
20
|
+
"Highland Snap": {
|
|
21
|
+
name: "Highland Snap",
|
|
22
|
+
peaType: "snap",
|
|
23
|
+
growthHabit: "climbing",
|
|
24
|
+
daysToMaturity: 70,
|
|
25
|
+
traits: ["edible pods", "needs support"],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default (() => defineTool({
|
|
30
|
+
name: "get-pea-variety",
|
|
31
|
+
access: "public",
|
|
32
|
+
title: "Pea Variety Details",
|
|
33
|
+
description: "Get the type, growth habit, maturity time, and traits of a sample pea variety.",
|
|
34
|
+
inputSchema: z.object({ name: z.enum(varietyNames) }),
|
|
35
|
+
outputSchema: peaVarietySchema,
|
|
36
|
+
handler: ({ name }) => {
|
|
37
|
+
const data = varieties[name];
|
|
38
|
+
return {
|
|
39
|
+
text: `${data.name} is a ${data.peaType} pea with a ${data.growthHabit} habit. ` +
|
|
40
|
+
`It matures in ${data.daysToMaturity} days and is known for ${data.traits.join(" and ")}.`,
|
|
41
|
+
data,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
})) satisfies CapabilityModuleFactory;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createEmseepea, discoverCapabilities, serveEmseepea } from "@emseepea/server";
|
|
2
2
|
|
|
3
3
|
const handler = createEmseepea({
|
|
4
|
-
name: "emseepea-
|
|
4
|
+
name: "emseepea-tool-server",
|
|
5
5
|
version: "0.0.0",
|
|
6
|
-
instructions: "Use get-
|
|
6
|
+
instructions: "Use get-pea-variety for information about a sample pea variety.",
|
|
7
7
|
...await discoverCapabilities(new URL("./capabilities/", import.meta.url)),
|
|
8
8
|
});
|
|
9
9
|
|
|
@@ -3,24 +3,23 @@ import test from "node:test";
|
|
|
3
3
|
|
|
4
4
|
import { startMcpServer } from "@emseepea/testing";
|
|
5
5
|
|
|
6
|
-
test("advertises and returns understandable
|
|
6
|
+
test("advertises and returns understandable pea variety details", async (t) => {
|
|
7
7
|
const running = await startMcpServer(t, new URL("../dist/server.js", import.meta.url));
|
|
8
8
|
const client = await running.connect();
|
|
9
9
|
|
|
10
10
|
const listed = await client.listTools();
|
|
11
|
-
assert.deepEqual(listed.tools.map(({ name }) => name), ["get-
|
|
11
|
+
assert.deepEqual(listed.tools.map(({ name }) => name), ["get-pea-variety"]);
|
|
12
12
|
|
|
13
13
|
const result = await client.callTool({
|
|
14
|
-
name: "get-
|
|
15
|
-
arguments: { name: "Highland
|
|
14
|
+
name: "get-pea-variety",
|
|
15
|
+
arguments: { name: "Highland Snap" },
|
|
16
16
|
});
|
|
17
17
|
assert.equal(result.isError, false);
|
|
18
18
|
assert.deepEqual(result.structuredContent, {
|
|
19
|
-
name: "Highland
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
tastingNotes: ["berry", "cocoa"],
|
|
19
|
+
name: "Highland Snap",
|
|
20
|
+
peaType: "snap",
|
|
21
|
+
growthHabit: "climbing",
|
|
22
|
+
daysToMaturity: 70,
|
|
23
|
+
traits: ["edible pods", "needs support"],
|
|
25
24
|
});
|
|
26
25
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emseepea/create-tool-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Create an Em See Pea server with one public tool.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"prepack": "npm run build:initializer"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@emseepea/server": "0.2.
|
|
21
|
+
"@emseepea/server": "0.2.2",
|
|
22
22
|
"zod": "4.4.3",
|
|
23
|
-
"@emseepea/testing": "0.2.
|
|
23
|
+
"@emseepea/testing": "0.2.2",
|
|
24
24
|
"@types/node": "24.13.3",
|
|
25
25
|
"typescript": "6.0.3",
|
|
26
26
|
"oxlint": "1.80.0"
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=22"
|
|
30
30
|
},
|
|
31
|
-
"repository": { "type": "git", "url": "git+https://github.com/emseepea/emseepea.git", "directory": "examples/
|
|
31
|
+
"repository": { "type": "git", "url": "git+https://github.com/emseepea/emseepea.git", "directory": "examples/tool-server" },
|
|
32
32
|
"homepage": "https://emseepea.github.io/emseepea/examples/",
|
|
33
33
|
"bugs": "https://github.com/emseepea/emseepea/issues",
|
|
34
|
-
"publishConfig": { "access": "public", "provenance": true
|
|
34
|
+
"publishConfig": { "access": "public", "provenance": true },
|
|
35
35
|
"bin": { "create-tool-server": "./initializer-dist/create.mjs" },
|
|
36
36
|
"files": ["initializer-dist"]
|
|
37
37
|
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { defineTool, type CapabilityModuleFactory } from "@emseepea/server";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
|
|
4
|
-
const beanNames = ["Harbour Dawn", "Highland Bloom"] as const;
|
|
5
|
-
const beanDetailsSchema = z.object({
|
|
6
|
-
name: z.enum(beanNames),
|
|
7
|
-
origin: z.string(),
|
|
8
|
-
variety: z.string(),
|
|
9
|
-
process: z.string(),
|
|
10
|
-
roast: z.enum(["light", "medium", "dark"]),
|
|
11
|
-
tastingNotes: z.array(z.string()),
|
|
12
|
-
});
|
|
13
|
-
const beans: Record<(typeof beanNames)[number], z.input<typeof beanDetailsSchema>> = {
|
|
14
|
-
"Harbour Dawn": {
|
|
15
|
-
name: "Harbour Dawn",
|
|
16
|
-
origin: "Sample Coast",
|
|
17
|
-
variety: "Caturra",
|
|
18
|
-
process: "washed",
|
|
19
|
-
roast: "light",
|
|
20
|
-
tastingNotes: ["citrus", "honey"],
|
|
21
|
-
},
|
|
22
|
-
"Highland Bloom": {
|
|
23
|
-
name: "Highland Bloom",
|
|
24
|
-
origin: "Sample Highlands",
|
|
25
|
-
variety: "Bourbon",
|
|
26
|
-
process: "natural",
|
|
27
|
-
roast: "medium",
|
|
28
|
-
tastingNotes: ["berry", "cocoa"],
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export default (() => defineTool({
|
|
33
|
-
name: "get-bean-details",
|
|
34
|
-
access: "public",
|
|
35
|
-
title: "Coffee Bean Details",
|
|
36
|
-
description: "Get origin, processing, roast, and tasting details for a sample coffee bean.",
|
|
37
|
-
inputSchema: z.object({ name: z.enum(beanNames) }),
|
|
38
|
-
outputSchema: beanDetailsSchema,
|
|
39
|
-
handler: ({ name }) => {
|
|
40
|
-
const data = beans[name];
|
|
41
|
-
return {
|
|
42
|
-
text: `${data.name} is a ${data.roast} ${data.process} ${data.variety} from ` +
|
|
43
|
-
`${data.origin}, with notes of ${data.tastingNotes.join(" and ")}.`,
|
|
44
|
-
data,
|
|
45
|
-
};
|
|
46
|
-
},
|
|
47
|
-
})) satisfies CapabilityModuleFactory;
|