mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-20 02:33:15 +08:00
Netx tools: convert MCP inputSchema to the DSH value schema DSL
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>
This commit is contained in:
parent
2ef3a43c63
commit
277a61894d
12 changed files with 2852 additions and 117 deletions
51
test/mcp-schema.test.mjs
Normal file
51
test/mcp-schema.test.mjs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
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 }))
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue