Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/vs/workbench/contrib/mcp/common/mcpTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,14 +609,18 @@ export const mcpServerIcon = registerIcon('mcp-server', Codicon.mcp, localize('m
export namespace McpResourceURI {
export const scheme = 'mcp-resource';

// Random placeholder for empty authorities, otherwise they're represente as
// `scheme//path/here` in the URI which would get normalized to `scheme/path/here`.
const emptyAuthorityPlaceholder = 'dylo78gyp'; // chosen by a fair dice roll. Guaranteed to be random.

export function fromServer(def: McpDefinitionReference, resourceURI: URI | string): URI {
if (typeof resourceURI === 'string') {
resourceURI = URI.parse(resourceURI);
}
return resourceURI.with({
scheme,
authority: encodeHex(VSBuffer.fromString(def.id)),
path: ['', resourceURI.scheme, resourceURI.authority].join('/') + resourceURI.path,
path: ['', resourceURI.scheme, resourceURI.authority || emptyAuthorityPlaceholder].join('/') + resourceURI.path,
});
}

Expand All @@ -636,8 +640,8 @@ export namespace McpResourceURI {
definitionId: decodeHex(uri.authority).toString(),
resourceURI: uri.with({
scheme: serverScheme,
authority,
path: '/' + path.join('/'),
authority: authority.toLowerCase() === emptyAuthorityPlaceholder ? '' : authority,
path: path.length ? ('/' + path.join('/')) : '',
}),
};
}
Expand Down
27 changes: 27 additions & 0 deletions src/vs/workbench/contrib/mcp/test/common/mcpTypes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { McpResourceURI } from '../../common/mcpTypes.js';
import * as assert from 'assert';

suite('MCP Types', () => {
ensureNoDisposablesAreLeakedInTestSuite();

test('McpResourceURI - round trips', () => {
const roundTrip = (uri: string) => {
const from = McpResourceURI.fromServer({ label: '', id: 'my-id' }, uri);
const to = McpResourceURI.toServer(from);
assert.strictEqual(to.definitionId, 'my-id');
assert.strictEqual(to.resourceURI.toString(true), uri, `expected to round trip ${uri}`);
};

roundTrip('file:///path/to/file.txt');
roundTrip('custom-scheme://my-path/to/resource.txt');
roundTrip('custom-scheme://my-path');
roundTrip('custom-scheme://my-path/');
roundTrip('custom-scheme://my-path/?with=query&params=here');
});
});
Loading