Skip to content

Commit f7bc687

Browse files
Add client-side SEP-1034 elicitation defaults conformance test (#19)
* feat: add client-side SEP-1034 conformance test for elicitation defaults Adds a conformance test that validates client SDKs properly apply default values for omitted fields in elicitation responses per SEP-1034. The test spins up a server that sends elicitation requests with defaults, and validates that the client returns content with those defaults applied. * feat: use elicitInput() for SEP-1034 default validation Updates client-side test to validate server-side default application using elicitInput() helper, which applies defaults via validation layer. This aligns with the TypeScript SDK's SEP-1034 implementation approach. The test now validates: - Server uses elicitInput() with schemas containing defaults - Client returns empty/partial content - Server automatically applies defaults during validation - Defaults are correctly merged for all primitive types * refactor: use server.request() instead of elicitInput() for client-side defaults test Ensures conformance test validates true client-side default application rather than server-side validation behavior. * feat: add applyDefaults capability flag for opt-in default application Enables conformance test to opt into client-side elicitation defaults by setting the applyDefaults capability flag.
1 parent fa7a0bc commit f7bc687

File tree

3 files changed

+640
-1
lines changed

3 files changed

+640
-1
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Test client for SEP-1034 client-side elicitation defaults
5+
* This client intentionally returns empty/partial content in elicitation responses
6+
* to verify that the SDK applies defaults for omitted fields.
7+
*/
8+
9+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
10+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
11+
import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
12+
13+
async function main(): Promise<void> {
14+
const serverUrl = process.argv[2];
15+
16+
if (!serverUrl) {
17+
console.error('Usage: elicitation-defaults-test <server-url>');
18+
process.exit(1);
19+
}
20+
21+
console.log(`Connecting to MCP server at: ${serverUrl}`);
22+
23+
try {
24+
const client = new Client(
25+
{
26+
name: 'elicitation-defaults-test-client',
27+
version: '1.0.0'
28+
},
29+
{
30+
capabilities: {
31+
elicitation: {
32+
applyDefaults: true
33+
}
34+
}
35+
}
36+
);
37+
38+
// Register elicitation handler that returns empty content
39+
// The SDK should fill in defaults for all omitted fields
40+
client.setRequestHandler(ElicitRequestSchema, async (request) => {
41+
console.log(
42+
'📋 Received elicitation request:',
43+
JSON.stringify(request.params, null, 2)
44+
);
45+
console.log(
46+
'✅ Accepting with empty content - SDK should apply defaults'
47+
);
48+
49+
// Return empty content - SDK should merge in defaults
50+
return {
51+
action: 'accept' as const,
52+
content: {}
53+
};
54+
});
55+
56+
const transport = new StreamableHTTPClientTransport(new URL(serverUrl));
57+
58+
await client.connect(transport);
59+
console.log('✅ Successfully connected to MCP server');
60+
61+
// List available tools
62+
const tools = await client.listTools();
63+
console.log(
64+
'📦 Available tools:',
65+
tools.tools.map((t) => t.name)
66+
);
67+
68+
// Call the test tool which will trigger elicitation
69+
const testTool = tools.tools.find(
70+
(t) => t.name === 'test_client_elicitation_defaults'
71+
);
72+
if (!testTool) {
73+
console.error('❌ Test tool not found: test_client_elicitation_defaults');
74+
process.exit(1);
75+
}
76+
77+
console.log('🔧 Calling test_client_elicitation_defaults tool...');
78+
const result = await client.callTool({
79+
name: 'test_client_elicitation_defaults',
80+
arguments: {}
81+
});
82+
83+
console.log('📄 Tool result:', JSON.stringify(result, null, 2));
84+
85+
await transport.close();
86+
console.log('✅ Connection closed successfully');
87+
88+
process.exit(0);
89+
} catch (error) {
90+
console.error('❌ Error:', error);
91+
process.exit(1);
92+
}
93+
}
94+
95+
main().catch((error) => {
96+
console.error('Unhandled error:', error);
97+
process.exit(1);
98+
});

0 commit comments

Comments
 (0)