From 4a717714fffed639ea9121026a294ff1214d9163 Mon Sep 17 00:00:00 2001 From: "Dr. David A. Kunz" Date: Tue, 29 Jul 2025 10:19:06 +0200 Subject: [PATCH] chore: only expose one tool --- lib/setModel.js | 4 ++++ lib/tools.js | 42 +++++++++++++----------------------------- tests/tools.test.js | 18 ++++++++++++------ 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/lib/setModel.js b/lib/setModel.js index ab7b274..e2f51a4 100644 --- a/lib/setModel.js +++ b/lib/setModel.js @@ -40,6 +40,10 @@ async function compileModel(path) { Object.assign(def, info) } + for (const name in compiled.definitions) { + Object.defineProperty(compiled.definitions[name], 'name', { value: name, enumerable: true }) + } + const _entities_in = service => { const exposed = [], { entities } = service diff --git a/lib/tools.js b/lib/tools.js index ccd37d2..afcc25b 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -5,22 +5,22 @@ import { z } from 'zod' import setModel from './setModel.js' import fuzzyTopN from './fuzzyTopN.js' -const PROJECT_PATH = { - projectPath: z.string().describe('Root path of the project') -} - const tools = { search_cds_definitions: { title: 'Search for CDS definitions', description: 'Get details of CDS definitions, returns Core Schema Notation (CSN). Use this if you want to see elements, parameters, file locations, URL paths, etc., helpful when constructing queries or OData URLs or when modifying CDS models.', inputSchema: { - ...PROJECT_PATH, - name: z.string().optional().describe('Name of the definition (fuzzy search, no regex or special characters)'), - kind: z.string().optional().describe('Kind of the definition (service, entity, action, ...)'), - topN: z.number().default(1).describe('Number of results') + projectPath: z.string().describe('Root path of the project'), + name: z + .string() + .optional() + .describe('Name of the definition (fuzzy search (Levenshtein distance), no regex or special characters)'), + kind: z.string().optional().describe('Filter for kind of the definition (service, entity, action, ...)'), + topN: z.number().default(1).describe('Number of results'), + namesOnly: z.boolean().optional().describe('If true, only return the names of the definitions') }, - handler: async ({ projectPath, name, kind, topN }) => { + handler: async ({ projectPath, name, kind, topN, namesOnly }) => { await setModel(projectPath) const defNames = kind ? Object.entries(cds.model.definitions) @@ -29,26 +29,10 @@ const tools = { .map(([k]) => k) : Object.keys(cds.model.definitions) const scores = name ? fuzzyTopN(name, defNames, topN) : fuzzyTopN('', defNames, topN) - return scores.map(s => Object.assign({ name: s.item }, cds.model.definitions[s.item])) - } - }, - list_all_cds_definition_names: { - title: 'List all CDS definitions names', - description: - 'Get an overview of available CDS definitions, for details use `search_cds_definitions`. Helpful for initial exploration, e.g. to get all service names.', - inputSchema: { - ...PROJECT_PATH, - kind: z.string().optional().describe('Kind of the definition (service, entity, action, ...)') - }, - handler: async ({ projectPath, kind }) => { - await setModel(projectPath) - const defNames = kind - ? Object.entries(cds.model.definitions) - // eslint-disable-next-line no-unused-vars - .filter(([_k, v]) => v.kind === kind) - .map(([k]) => k) - : Object.keys(cds.model.definitions) - return defNames + if (namesOnly) { + return scores.map(s => s.item) + } + return scores.map(s => cds.model.definitions[s.item]) } } } diff --git a/tests/tools.test.js b/tests/tools.test.js index 0836a56..25c5946 100644 --- a/tests/tools.test.js +++ b/tests/tools.test.js @@ -40,21 +40,27 @@ test.describe('tools', () => { assert.equal(books[0].endpoints[0].path, 'odata/v4/admin/Books', 'Should contain endpoint path') }) - test('list_all_cds_definition_names: should list all entities', async () => { - const entities = await tools.list_all_cds_definition_names.handler({ + test('search_cds_definitions: should list all entities (namesOnly)', async () => { + const entities = await tools.search_cds_definitions.handler({ projectPath: sampleProjectPath, - kind: 'entity' + kind: 'entity', + topN: 100, + namesOnly: true }) assert(Array.isArray(entities), 'Entities should be an array') assert(entities.length > 0, 'Should find at least one entity') + assert(typeof entities[0] === 'string', 'Should return only names') }) - test('list_all_cds_definition_names: should list all services', async () => { - const services = await tools.list_all_cds_definition_names.handler({ + test('search_cds_definitions: should list all services (namesOnly)', async () => { + const services = await tools.search_cds_definitions.handler({ projectPath: sampleProjectPath, - kind: 'service' + kind: 'service', + topN: 100, + namesOnly: true }) assert(Array.isArray(services), 'Services should be an array') assert(services.length > 0, 'Should find at least one service') + assert(typeof services[0] === 'string', 'Should return only names') }) })