fix(server): return Invalid Params for malformed resource URIs (#2451)
This commit is contained in:
parent
e2aeac2085
commit
7e697354de
3 changed files with 88 additions and 1 deletions
5
.changeset/malformed-resource-uri-invalid-params.md
Normal file
5
.changeset/malformed-resource-uri-invalid-params.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
---
|
||||
|
||||
Return JSON-RPC Invalid Params with the original URI and an `invalid_uri` reason when `resources/read` receives a syntactically malformed URI.
|
||||
|
|
@ -476,7 +476,15 @@ export class McpServer {
|
|||
});
|
||||
|
||||
this.server.setRequestHandler('resources/read', async (request, ctx) => {
|
||||
const uri = new URL(request.params.uri);
|
||||
let uri: URL;
|
||||
try {
|
||||
uri = new URL(request.params.uri);
|
||||
} catch {
|
||||
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Resource URI ${request.params.uri} is invalid`, {
|
||||
uri: request.params.uri,
|
||||
reason: 'invalid_uri'
|
||||
});
|
||||
}
|
||||
|
||||
// First check for exact resource match
|
||||
const resource = this._registeredResources[uri.toString()];
|
||||
|
|
|
|||
|
|
@ -2743,6 +2743,80 @@ describe('Zod v4', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should echo the exact requested URI for nonexistent resources', async () => {
|
||||
const mcpServer = new McpServer({
|
||||
name: 'test server',
|
||||
version: '1.0'
|
||||
});
|
||||
const client = new Client({
|
||||
name: 'test client',
|
||||
version: '1.0'
|
||||
});
|
||||
const requestedUri = 'HTTP://example.com:80/docs/../missing file.txt';
|
||||
mcpServer.registerResource('test', 'test://resource', {}, async () => ({
|
||||
contents: [
|
||||
{
|
||||
uri: 'test://resource',
|
||||
text: 'Test content'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
|
||||
await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]);
|
||||
|
||||
await expect(
|
||||
client.request({
|
||||
method: 'resources/read',
|
||||
params: {
|
||||
uri: requestedUri
|
||||
}
|
||||
})
|
||||
).rejects.toMatchObject({
|
||||
code: ProtocolErrorCode.InvalidParams,
|
||||
message: expect.stringContaining('not found'),
|
||||
data: { uri: requestedUri }
|
||||
});
|
||||
});
|
||||
|
||||
test('should return invalid params for syntactically invalid resource URIs', async () => {
|
||||
const mcpServer = new McpServer({
|
||||
name: 'test server',
|
||||
version: '1.0'
|
||||
});
|
||||
const client = new Client({
|
||||
name: 'test client',
|
||||
version: '1.0'
|
||||
});
|
||||
const requestedUri = 'not a valid URI';
|
||||
mcpServer.registerResource('test', 'test://resource', {}, async () => ({
|
||||
contents: [
|
||||
{
|
||||
uri: 'test://resource',
|
||||
text: 'Test content'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
|
||||
await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]);
|
||||
|
||||
await expect(
|
||||
client.request({
|
||||
method: 'resources/read',
|
||||
params: {
|
||||
uri: requestedUri
|
||||
}
|
||||
})
|
||||
).rejects.toMatchObject({
|
||||
code: ProtocolErrorCode.InvalidParams,
|
||||
message: expect.stringContaining('invalid'),
|
||||
data: { uri: requestedUri, reason: 'invalid_uri' }
|
||||
});
|
||||
});
|
||||
|
||||
/***
|
||||
* Test: ProtocolError for Disabled Resource
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue