@emseepea/create-api-backed-server 0.0.7 → 0.0.9

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.
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "private": true,
27
27
  "dependencies": {
28
- "@emseepea/server": "0.3.0",
28
+ "@emseepea/server": "0.3.2",
29
29
  "zod": "4.4.3"
30
30
  }
31
31
  }
@@ -4,29 +4,28 @@ import { z } from "zod";
4
4
 
5
5
  export interface BackendExampleContext { readonly client: JsonHttpClient }
6
6
 
7
- const taxon = 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
- rank: z.string().min(1).max(40),
12
- observations_count: z.number().int().nonnegative(),
13
- });
14
7
  const backendTaxon = z.object({
15
- id: z.number().int().positive(),
16
- name: z.string().min(1).max(200),
17
- preferred_common_name: z.string().min(1).max(200).nullable().optional(),
18
- rank: z.string().min(1).max(40),
19
- observations_count: z.number().int().nonnegative(),
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."),
18
+ });
19
+ const backendPayload = z.object({
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."),
20
22
  });
21
- const searchInput = z.object({ query: z.string().trim().min(2).max(80) });
22
- const searchReport = z.object({
23
- query: z.string().max(80),
24
- total_results: z.number().int().nonnegative(),
25
- results: z.array(taxon).max(5),
26
- source: z.literal("iNaturalist"),
27
- source_url: z.literal("https://www.inaturalist.org"),
23
+ const outputSchema = backendPayload.extend({
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."),
28
27
  });
29
- const backendCommand = z.object({
28
+ const backendInputSchema = z.object({
30
29
  pathname: z.literal("/v1/taxa"),
31
30
  searchParams: z.object({
32
31
  q: z.string().min(2).max(80),
@@ -34,20 +33,16 @@ const backendCommand = z.object({
34
33
  per_page: z.literal("5"),
35
34
  }),
36
35
  });
37
- const backendPayload = z.object({
38
- total_results: z.number().int().nonnegative(),
39
- results: z.array(backendTaxon).max(5),
40
- });
41
- const backendResult = z.object({ request: backendCommand, payload: backendPayload });
36
+ const backendOutputSchema = z.object({ request: backendInputSchema, payload: backendPayload });
42
37
 
43
38
  export default (({ client }) => defineMappedTool({
44
39
  name: "search-pea-taxa",
45
40
  access: "public",
46
41
  description: "Search iNaturalist's public taxon catalogue for pea species.",
47
- inputSchema: searchInput,
48
- outputSchema: searchReport,
49
- backendInputSchema: backendCommand,
50
- backendOutputSchema: backendResult,
42
+ inputSchema,
43
+ outputSchema,
44
+ backendInputSchema,
45
+ backendOutputSchema,
51
46
  mapInput: ({ query }) => ({
52
47
  pathname: "/v1/taxa" as const,
53
48
  searchParams: { q: query, rank: "species" as const, per_page: "5" as const },
@@ -57,15 +52,8 @@ export default (({ client }) => defineMappedTool({
57
52
  },
58
53
  mapOutput: ({ request, payload }) => {
59
54
  const data = {
55
+ ...payload,
60
56
  query: request.searchParams.q,
61
- total_results: payload.total_results,
62
- results: payload.results.map((record) => ({
63
- id: record.id,
64
- name: record.name,
65
- preferred_common_name: record.preferred_common_name,
66
- rank: record.rank,
67
- observations_count: record.observations_count,
68
- })),
69
57
  source: "iNaturalist" as const,
70
58
  source_url: "https://www.inaturalist.org" as const,
71
59
  };
@@ -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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emseepea/create-api-backed-server",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
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.0",
21
+ "@emseepea/server": "0.3.2",
22
22
  "zod": "4.4.3",
23
23
  "@emseepea/testing": "0.3.0",
24
24
  "@modelcontextprotocol/client": "2.0.0",