mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-20 07:40:46 +08:00
defineTool rejected netx tools whose parameters carry standard JSON
Schema constraints ("parameters.page.minimum is not supported by the
value schema DSL"), and the old pass-through dropped the top-level
required list.
- mcp-schema.ts: fold minimum/maxItems/pattern/... into the description,
mark required per property, map anyOf/oneOf/type arrays (minus null)
to oneOf, default additionalProperties to true.
- Test compiles all 39 real /mcp tool schemas through defineTool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2 KiB
JavaScript
51 lines
2 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
import { parametersFromInputSchema } from '../src/netx/mcp-schema.ts'
|
|
|
|
const tools = JSON.parse(readFileSync(new URL('./fixtures-netx-mcp-tools.json', import.meta.url), 'utf8'))
|
|
|
|
function define(name, inputSchema) {
|
|
return defineTool({
|
|
name: `netx__${name}`,
|
|
description: name,
|
|
parameters: parametersFromInputSchema(inputSchema),
|
|
output: { schema: { type: 'object', additionalProperties: true }, render: () => [] },
|
|
async execute() {
|
|
return {}
|
|
},
|
|
})
|
|
}
|
|
|
|
test('every real netx /mcp tool schema compiles in the DSH value schema DSL', () => {
|
|
assert.ok(tools.length >= 39)
|
|
for (const tool of tools) {
|
|
assert.doesNotThrow(() => define(tool.name, tool.inputSchema), tool.name)
|
|
}
|
|
})
|
|
|
|
test('required, constraints and nullable unions survive conversion', () => {
|
|
const params = parametersFromInputSchema({
|
|
type: 'object',
|
|
required: ['ne_id'],
|
|
properties: {
|
|
ne_id: { type: 'string', description: 'NE id' },
|
|
page: { type: 'integer', minimum: 1, maximum: 50, default: 1 },
|
|
ids: { type: 'array', items: { type: 'string' }, maxItems: 20 },
|
|
filter: { type: 'object', required: ['k'], properties: { k: { type: 'string' } } },
|
|
maybe: { anyOf: [{ type: 'string' }, { type: 'null' }] },
|
|
either: { type: ['string', 'integer'] },
|
|
},
|
|
})
|
|
assert.equal(params.ne_id.required, true)
|
|
assert.equal(params.page.required, undefined)
|
|
assert.equal(params.page.minimum, undefined)
|
|
assert.match(params.page.description, /minimum=1, maximum=50/)
|
|
assert.match(params.ids.description, /maxItems=20/)
|
|
assert.equal(params.filter.additionalProperties, true)
|
|
assert.equal(params.filter.properties.k.required, true)
|
|
assert.equal(params.maybe.type, 'string')
|
|
assert.equal(params.either.oneOf.length, 2)
|
|
assert.doesNotThrow(() => define('sample', { type: 'object', properties: params }))
|
|
})
|