@emseepea/create-api-backed-server 0.0.8 → 0.0.10
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.
|
@@ -5,21 +5,25 @@ import { z } from "zod";
|
|
|
5
5
|
export interface BackendExampleContext { readonly client: JsonHttpClient }
|
|
6
6
|
|
|
7
7
|
const backendTaxon = z.object({
|
|
8
|
-
id: z.number().int().positive(),
|
|
9
|
-
name: z.string().min(1).max(200),
|
|
10
|
-
preferred_common_name: z.string().min(1).max(200).nullable().optional()
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
id: z.number().int().positive().describe("iNaturalist identifier for the taxon."),
|
|
9
|
+
name: z.string().min(1).max(200).describe("Scientific name of the taxon."),
|
|
10
|
+
preferred_common_name: z.string().min(1).max(200).nullable().optional()
|
|
11
|
+
.describe("Preferred common name when iNaturalist provides one."),
|
|
12
|
+
rank: z.string().min(1).max(40).describe("Taxonomic rank reported by iNaturalist."),
|
|
13
|
+
observations_count: z.number().int().nonnegative()
|
|
14
|
+
.describe("Recorded iNaturalist observations, not an estimate of the wild population."),
|
|
15
|
+
});
|
|
16
|
+
const inputSchema = z.object({
|
|
17
|
+
query: z.string().trim().min(2).max(80).describe("Pea name or other taxon search terms."),
|
|
13
18
|
});
|
|
14
|
-
const inputSchema = z.object({ query: z.string().trim().min(2).max(80) });
|
|
15
19
|
const backendPayload = z.object({
|
|
16
|
-
total_results: z.number().int().nonnegative(),
|
|
17
|
-
results: z.array(backendTaxon).max(5),
|
|
20
|
+
total_results: z.number().int().nonnegative().describe("Total matching taxa reported by iNaturalist."),
|
|
21
|
+
results: z.array(backendTaxon).max(5).describe("Up to five matching taxa."),
|
|
18
22
|
});
|
|
19
23
|
const outputSchema = backendPayload.extend({
|
|
20
|
-
query: z.string().max(80),
|
|
21
|
-
source: z.literal("iNaturalist"),
|
|
22
|
-
source_url: z.literal("https://www.inaturalist.org"),
|
|
24
|
+
query: z.string().max(80).describe("Trimmed search terms sent to iNaturalist."),
|
|
25
|
+
source: z.literal("iNaturalist").describe("Data provider for these results."),
|
|
26
|
+
source_url: z.literal("https://www.inaturalist.org").describe("Website of the data provider."),
|
|
23
27
|
});
|
|
24
28
|
const backendInputSchema = z.object({
|
|
25
29
|
pathname: z.literal("/v1/taxa"),
|
|
@@ -53,20 +57,6 @@ export default (({ client }) => defineMappedTool({
|
|
|
53
57
|
source: "iNaturalist" as const,
|
|
54
58
|
source_url: "https://www.inaturalist.org" as const,
|
|
55
59
|
};
|
|
56
|
-
|
|
57
|
-
record.preferred_common_name ?? "Common name not provided",
|
|
58
|
-
record.name,
|
|
59
|
-
`rank: ${record.rank}`,
|
|
60
|
-
`recorded observations: ${record.observations_count}`,
|
|
61
|
-
].join("; "));
|
|
62
|
-
return {
|
|
63
|
-
text: [
|
|
64
|
-
`iNaturalist returned ${data.results.length} of ${data.total_results} matching taxa for “${data.query}”.`,
|
|
65
|
-
"observations_count is the number of recorded observations, not a population estimate.",
|
|
66
|
-
...lines,
|
|
67
|
-
"Source: https://www.inaturalist.org",
|
|
68
|
-
].join("\n"),
|
|
69
|
-
data,
|
|
70
|
-
};
|
|
60
|
+
return { data };
|
|
71
61
|
},
|
|
72
62
|
})) satisfies CapabilityModuleFactory<BackendExampleContext>;
|
|
@@ -25,6 +25,19 @@ test("the API-backed example checks and passes through selected iNaturalist valu
|
|
|
25
25
|
try {
|
|
26
26
|
const listed = await client.listTools();
|
|
27
27
|
assert.deepEqual(listed.tools.map(({ name }) => name), ["search-pea-taxa"]);
|
|
28
|
+
const tool = listed.tools[0];
|
|
29
|
+
assert.equal(tool.inputSchema.properties.query.description, "Pea name or other taxon search terms.");
|
|
30
|
+
assert.equal(tool.outputSchema.properties.total_results.description, "Total matching taxa reported by iNaturalist.");
|
|
31
|
+
assert.equal(tool.outputSchema.properties.results.description, "Up to five matching taxa.");
|
|
32
|
+
const taxon = tool.outputSchema.properties.results.items.properties;
|
|
33
|
+
assert.equal(taxon.id.description, "iNaturalist identifier for the taxon.");
|
|
34
|
+
assert.equal(taxon.name.description, "Scientific name of the taxon.");
|
|
35
|
+
assert.equal(taxon.preferred_common_name.description, "Preferred common name when iNaturalist provides one.");
|
|
36
|
+
assert.equal(taxon.rank.description, "Taxonomic rank reported by iNaturalist.");
|
|
37
|
+
assert.equal(taxon.observations_count.description, "Recorded iNaturalist observations, not an estimate of the wild population.");
|
|
38
|
+
assert.equal(tool.outputSchema.properties.query.description, "Trimmed search terms sent to iNaturalist.");
|
|
39
|
+
assert.equal(tool.outputSchema.properties.source.description, "Data provider for these results.");
|
|
40
|
+
assert.equal(tool.outputSchema.properties.source_url.description, "Website of the data provider.");
|
|
28
41
|
|
|
29
42
|
const invalidInput = await client.callTool({
|
|
30
43
|
name: "search-pea-taxa",
|
|
@@ -44,7 +57,7 @@ test("the API-backed example checks and passes through selected iNaturalist valu
|
|
|
44
57
|
source: "iNaturalist",
|
|
45
58
|
source_url: "https://www.inaturalist.org",
|
|
46
59
|
});
|
|
47
|
-
assert.
|
|
60
|
+
assert.equal(result.content[0].text, JSON.stringify(result.structuredContent));
|
|
48
61
|
assert.equal(requests[0].pathname, "/v1/taxa");
|
|
49
62
|
assert.deepEqual(requests[0].searchParams, {
|
|
50
63
|
q: "pea",
|
|
@@ -78,6 +91,7 @@ test("the API-backed example checks and passes through selected iNaturalist valu
|
|
|
78
91
|
observations_count: 0,
|
|
79
92
|
});
|
|
80
93
|
assert.equal("private_note" in newProviderValue.structuredContent.results[0], false);
|
|
94
|
+
assert.equal(newProviderValue.content[0].text, JSON.stringify(newProviderValue.structuredContent));
|
|
81
95
|
|
|
82
96
|
response = { total_results: 1, results: [{ id: "bad provider row" }] };
|
|
83
97
|
const invalidProviderData = await client.callTool({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emseepea/create-api-backed-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "Create an Em See Pea server backed by a public web API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prepack": "npm run build:initializer"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@emseepea/server": "0.3.
|
|
21
|
+
"@emseepea/server": "0.3.3",
|
|
22
22
|
"zod": "4.4.3",
|
|
23
23
|
"@emseepea/testing": "0.3.0",
|
|
24
24
|
"@modelcontextprotocol/client": "2.0.0",
|