Skip to content

Commit a5e971f

Browse files
authored
Mrtr tests updates (#3)
* remove duplicates in index, rename test cases to be consistent * add negative tests * refactor into everything-server and update negative tests * fix conformance tests
1 parent a041f5c commit a5e971f

9 files changed

Lines changed: 918 additions & 1049 deletions

File tree

examples/servers/typescript/everything-server.ts

Lines changed: 590 additions & 2 deletions
Large diffs are not rendered by default.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* SEP-2322 MRTR Broken Server — Negative Test Case
5+
*
6+
* Deliberately violates several SEP-2322 MUST requirements:
7+
* 1. Omits `resultType` field from InputRequiredResult responses
8+
* 2. Returns InputRequiredResult on `tools/list` (unsupported method)
9+
* 3. Accepts tampered requestState without integrity verification
10+
*
11+
* The conformance scenarios should emit FAILURE against this server.
12+
*/
13+
14+
import express from 'express';
15+
import { randomUUID } from 'crypto';
16+
17+
const PORT = parseInt(process.env.PORT || '3011', 10);
18+
19+
// --- JSON-RPC dispatch ---
20+
21+
type Handler = (params: Record<string, unknown>) => unknown;
22+
23+
const handlers: Record<string, Handler> = {};
24+
25+
handlers['server/discover'] = () => ({
26+
supportedVersions: ['DRAFT-2026-v1'],
27+
capabilities: {
28+
tools: {},
29+
prompts: {},
30+
elicitation: {}
31+
},
32+
serverInfo: { name: 'sep-2322-mrtr-broken-server', version: '1.0.0' }
33+
});
34+
35+
// BUG 2: Returns InputRequiredResult on tools/list (unsupported method)
36+
handlers['tools/list'] = () => ({
37+
resultType: 'input_required',
38+
inputRequests: {
39+
bogus: {
40+
method: 'elicitation/create',
41+
params: {
42+
message: 'This should not happen on tools/list',
43+
requestedSchema: { type: 'object', properties: {} }
44+
}
45+
}
46+
},
47+
tools: [
48+
{
49+
name: 'test_input_required_result_elicitation',
50+
description: 'Test tool for elicitation',
51+
inputSchema: { type: 'object' as const, properties: {} }
52+
},
53+
{
54+
name: 'test_input_required_result_tampered_state',
55+
description: 'Test tool for tampered state',
56+
inputSchema: { type: 'object' as const, properties: {} }
57+
}
58+
]
59+
});
60+
61+
handlers['prompts/list'] = () => ({
62+
prompts: []
63+
});
64+
65+
handlers['tools/call'] = (params) => {
66+
const toolName = params.name as string;
67+
const inputResponses = params.inputResponses as
68+
| Record<string, unknown>
69+
| undefined;
70+
71+
switch (toolName) {
72+
case 'test_input_required_result_elicitation': {
73+
if (inputResponses?.['user_name']) {
74+
return {
75+
content: [{ type: 'text', text: 'Hello!' }]
76+
};
77+
}
78+
// BUG 1: Omits `resultType` field — spec says MUST include it
79+
return {
80+
// resultType: 'input_required', <-- deliberately omitted
81+
inputRequests: {
82+
user_name: {
83+
method: 'elicitation/create',
84+
params: {
85+
message: 'What is your name?',
86+
requestedSchema: {
87+
type: 'object',
88+
properties: { name: { type: 'string' } },
89+
required: ['name']
90+
}
91+
}
92+
}
93+
}
94+
};
95+
}
96+
97+
case 'test_input_required_result_tampered_state': {
98+
if (inputResponses) {
99+
// BUG 3: Accepts ANY requestState without verification
100+
// A compliant server MUST reject tampered state
101+
return {
102+
content: [{ type: 'text', text: 'Accepted (no integrity check)' }]
103+
};
104+
}
105+
return {
106+
resultType: 'input_required',
107+
inputRequests: {
108+
confirm: {
109+
method: 'elicitation/create',
110+
params: {
111+
message: 'Confirm?',
112+
requestedSchema: {
113+
type: 'object',
114+
properties: { ok: { type: 'boolean' } },
115+
required: ['ok']
116+
}
117+
}
118+
}
119+
},
120+
requestState: 'unprotected-state-' + randomUUID()
121+
};
122+
}
123+
124+
default:
125+
throw { code: -32602, message: `Unknown tool: ${toolName}` };
126+
}
127+
};
128+
129+
// --- Express app ---
130+
131+
const app = express();
132+
app.use(express.json());
133+
134+
app.post('/mcp', (req, res) => {
135+
const body = req.body as {
136+
jsonrpc: string;
137+
id: number;
138+
method: string;
139+
params?: Record<string, unknown>;
140+
};
141+
142+
const handler = handlers[body.method];
143+
if (!handler) {
144+
res.json({
145+
jsonrpc: '2.0',
146+
id: body.id,
147+
error: { code: -32601, message: `Method not found: ${body.method}` }
148+
});
149+
return;
150+
}
151+
152+
try {
153+
const result = handler(body.params || {});
154+
res.json({ jsonrpc: '2.0', id: body.id, result });
155+
} catch (err: unknown) {
156+
const error = err as { code?: number; message?: string };
157+
res.json({
158+
jsonrpc: '2.0',
159+
id: body.id,
160+
error: {
161+
code: error.code || -32603,
162+
message: error.message || 'Internal error'
163+
}
164+
});
165+
}
166+
});
167+
168+
app.listen(PORT, () => {
169+
console.log(
170+
`sep-2322-mrtr-broken-server running on http://localhost:${PORT}/mcp`
171+
);
172+
});

0 commit comments

Comments
 (0)