33 lines
2.2 KiB
JavaScript
33 lines
2.2 KiB
JavaScript
// Controlled real SDK server: stdio child or imported HTTP server factory. No external calls.
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
|
import { appendFile } from 'node:fs/promises'
|
|
export function fixtureServer(label, events, secret = '') {
|
|
const server = new Server({ name: 'ycode-controlled-' + label, version: '1.0.0' }, { capabilities: { tools: {} } })
|
|
const tool = name => ({ name, description: name === 'secret' ? 'Fixture secret masking' : 'Controlled ' + label + ' ' + name, inputSchema: { type: 'object', properties: { text: { type: 'string' } } } })
|
|
server.setRequestHandler(ListToolsRequestSchema, async request => {
|
|
await events({ type: 'list', cursor: request.params?.cursor || null })
|
|
return request.params?.cursor ? { tools: [tool('wait'), tool('secret'), tool('failure')] } : { tools: [tool('echo')], nextCursor: 'second' }
|
|
})
|
|
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
await events({ type: 'call', name: request.params.name })
|
|
if (request.params.name === 'wait') {
|
|
await new Promise((resolve, reject) => {
|
|
const timer = setTimeout(resolve, 10000)
|
|
extra.signal.addEventListener('abort', () => { clearTimeout(timer); void events({ type: 'cancel' }); reject(Error('Cancelled fixture')) }, { once: true })
|
|
})
|
|
}
|
|
if (request.params.name === 'failure') throw Error('Controlled failure ' + secret)
|
|
return { content: [{ type: 'text', text: request.params.name === 'secret' ? secret : label + ':' + (request.params.arguments?.text || '') }], isError: false }
|
|
})
|
|
return server
|
|
}
|
|
if (process.argv[2] === 'stdio') {
|
|
const events = event => appendFile(process.argv[3], JSON.stringify(event) + '\n')
|
|
const server = fixtureServer('stdio', events, process.env.FIXTURE_SECRET || '')
|
|
// The host must discard server stderr, including credential-bearing diagnostics.
|
|
process.stderr.write('fixture stderr ' + (process.env.FIXTURE_SECRET || '') + '\n')
|
|
await server.connect(new StdioServerTransport())
|
|
}
|