Skip to content

Commit 20a513f

Browse files
feat: add localization and test coverage for ToolPipe MCP integration
- Create package.nls.json with localized strings for extension UI - Update package.json to use localization placeholders (%displayName%, %description%, etc.) - Add comprehensive test suite for inline reference snippet rendering - Tests cover: basic snippet rendering, backtick escaping, fence length calculation - Tests verify: code blocks with language IDs, empty snippets, multiple backtick sequences - All tests follow existing VS Code test patterns and conventions
1 parent 70d3c0a commit 20a513f

3 files changed

Lines changed: 178 additions & 9 deletions

File tree

extensions/toolpipe-mcp-server/package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "toolpipe-mcp-server",
3-
"displayName": "ToolPipe MCP Server",
4-
"description": "Integrates ToolPipe MCP Server - 120+ developer utilities via Model Context Protocol",
3+
"displayName": "%displayName%",
4+
"description": "%description%",
55
"version": "1.0.0",
66
"publisher": "vscode",
77
"license": "MIT",
@@ -36,17 +36,17 @@
3636
"mcpServerDefinitionProviders": [
3737
{
3838
"id": "toolpipe",
39-
"label": "ToolPipe MCP Server"
39+
"label": "%mcpServerDefinition.label%"
4040
}
4141
],
4242
"configuration": [
4343
{
44-
"title": "ToolPipe MCP Server",
44+
"title": "%configuration.title%",
4545
"properties": {
4646
"toolpipeMcpServer.enabled": {
4747
"type": "boolean",
4848
"default": true,
49-
"description": "Enable ToolPipe MCP Server integration"
49+
"description": "%configuration.enabled.description%"
5050
},
5151
"toolpipeMcpServer.mode": {
5252
"type": "string",
@@ -55,24 +55,24 @@
5555
"local"
5656
],
5757
"default": "remote",
58-
"description": "ToolPipe connection mode: 'remote' for cloud-hosted server, 'local' for npm-based server"
58+
"description": "%configuration.mode.description%"
5959
},
6060
"toolpipeMcpServer.remoteUrl": {
6161
"type": "string",
6262
"default": "",
63-
"description": "Remote URL for ToolPipe MCP Server (HTTPS endpoint). Provide your own server URL, for example: https://example.com/mcp"
63+
"description": "%configuration.remoteUrl.description%"
6464
},
6565
"toolpipeMcpServer.localCommand": {
6666
"type": "string",
6767
"default": "npx",
68-
"description": "Command to run local ToolPipe server (e.g., 'npx' or full path)"
68+
"description": "%configuration.localCommand.description%"
6969
},
7070
"toolpipeMcpServer.localArgs": {
7171
"type": "array",
7272
"default": [
7373
"@cosai-labs/toolpipe-mcp-server"
7474
],
75-
"description": "Arguments for local ToolPipe server command"
75+
"description": "%configuration.localArgs.description%"
7676
}
7777
}
7878
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"displayName": "ToolPipe MCP Server",
3+
"description": "Integrates ToolPipe MCP Server - 120+ developer utilities via Model Context Protocol",
4+
"configuration.title": "ToolPipe MCP Server",
5+
"configuration.enabled.description": "Enable ToolPipe MCP Server integration",
6+
"configuration.mode.description": "ToolPipe connection mode: 'remote' for cloud-hosted server, 'local' for npm-based server",
7+
"configuration.remoteUrl.description": "Remote URL for ToolPipe MCP Server (HTTPS endpoint). Provide your own server URL, for example: https://example.com/mcp",
8+
"configuration.localCommand.description": "Command to run local ToolPipe server (e.g., 'npx' or full path)",
9+
"configuration.localArgs.description": "Arguments for local ToolPipe server command",
10+
"mcpServerDefinition.label": "ToolPipe MCP Server"
11+
}

src/vs/workbench/contrib/chat/test/common/widget/annotations.test.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,162 @@ suite('Annotations', function () {
315315
});
316316

317317
});
318+
319+
suite('annotateSpecialMarkdownContent - inline references with snippets', () => {
320+
test('inline reference with snippet renders code block', () => {
321+
const result = annotateSpecialMarkdownContent([
322+
content('Check out '),
323+
{
324+
kind: 'inlineReference',
325+
inlineReference: URI.parse('file:///example.ts'),
326+
name: 'example.ts',
327+
snippet: 'export const greeting = "hello world";',
328+
languageId: 'typescript'
329+
},
330+
content(' for details'),
331+
]);
332+
333+
assert.strictEqual(result.length, 1);
334+
const md = result[0] as IChatMarkdownContent;
335+
// Should contain the file reference
336+
assert.ok(md.content.value.includes('[example.ts]'));
337+
// Should contain the code fence with language ID
338+
assert.ok(md.content.value.includes('```typescript'));
339+
// Should contain the snippet
340+
assert.ok(md.content.value.includes('export const greeting = "hello world";'));
341+
// Should contain closing fence
342+
assert.ok(md.content.value.includes('```'));
343+
});
344+
345+
test('snippet with backticks uses appropriate fence length', () => {
346+
const snippetWithBackticks = 'const code = `nested template literal`;';
347+
const result = annotateSpecialMarkdownContent([
348+
content('See '),
349+
{
350+
kind: 'inlineReference',
351+
inlineReference: URI.parse('file:///test.ts'),
352+
name: 'test.ts',
353+
snippet: snippetWithBackticks,
354+
languageId: 'typescript'
355+
},
356+
]);
357+
358+
assert.strictEqual(result.length, 1);
359+
const md = result[0] as IChatMarkdownContent;
360+
const value = md.content.value;
361+
// Should use 4 backticks (one more than the max run of 3 in the snippet)
362+
assert.ok(value.includes('````typescript'));
363+
assert.ok(value.includes(snippetWithBackticks));
364+
assert.ok(value.includes('````'));
365+
});
366+
367+
test('snippet with multiple backtick sequences uses longest length', () => {
368+
const snippetWithMultipleBackticks = 'const a = ``; const b = ```; const c = `;';
369+
const result = annotateSpecialMarkdownContent([
370+
content('Example: '),
371+
{
372+
kind: 'inlineReference',
373+
inlineReference: URI.parse('file:///multi.ts'),
374+
name: 'multi.ts',
375+
snippet: snippetWithMultipleBackticks,
376+
languageId: 'typescript'
377+
},
378+
]);
379+
380+
assert.strictEqual(result.length, 1);
381+
const md = result[0] as IChatMarkdownContent;
382+
const value = md.content.value;
383+
// Should use 4 backticks (one more than the max run of 3)
384+
assert.ok(value.includes('````typescript'));
385+
assert.ok(value.includes(snippetWithMultipleBackticks));
386+
assert.ok(value.includes('````'));
387+
});
388+
389+
test('snippet without backticks uses standard 3-backtick fence', () => {
390+
const cleanSnippet = 'function hello() {\n console.log("world");\n}';
391+
const result = annotateSpecialMarkdownContent([
392+
content('Function: '),
393+
{
394+
kind: 'inlineReference',
395+
inlineReference: URI.parse('file:///func.ts'),
396+
name: 'func.ts',
397+
snippet: cleanSnippet,
398+
languageId: 'typescript'
399+
},
400+
]);
401+
402+
assert.strictEqual(result.length, 1);
403+
const md = result[0] as IChatMarkdownContent;
404+
const value = md.content.value;
405+
// Should use standard 3-backtick fence
406+
assert.ok(value.includes('```typescript'));
407+
assert.ok(value.includes(cleanSnippet));
408+
// Count occurrences of closing fence
409+
const closeMatches = value.match(/^```$/gm);
410+
assert.ok(closeMatches && closeMatches.length >= 1, 'Should have at least one closing fence');
411+
});
412+
413+
test('snippet with code block markers renders with longer fence', () => {
414+
const snippetWithCodeBlock = 'const desc = "```javascript\ncode\n```";';
415+
const result = annotateSpecialMarkdownContent([
416+
content('Code: '),
417+
{
418+
kind: 'inlineReference',
419+
inlineReference: URI.parse('file:///code.ts'),
420+
name: 'code.ts',
421+
snippet: snippetWithCodeBlock,
422+
languageId: 'typescript'
423+
},
424+
]);
425+
426+
assert.strictEqual(result.length, 1);
427+
const md = result[0] as IChatMarkdownContent;
428+
const value = md.content.value;
429+
// Should use 4 backticks to escape the 3-backtick sequence inside
430+
assert.ok(value.includes('````typescript'));
431+
assert.ok(value.includes(snippetWithCodeBlock));
432+
assert.ok(value.includes('````'));
433+
});
434+
435+
test('snippet without language ID still renders with backtick escaping', () => {
436+
const snippetWithBackticks = 'const template = `Hello ${name}`;';
437+
const result = annotateSpecialMarkdownContent([
438+
content('Value: '),
439+
{
440+
kind: 'inlineReference',
441+
inlineReference: URI.parse('file:///value.js'),
442+
name: 'value.js',
443+
snippet: snippetWithBackticks
444+
// Note: no languageId provided
445+
},
446+
]);
447+
448+
assert.strictEqual(result.length, 1);
449+
const md = result[0] as IChatMarkdownContent;
450+
const value = md.content.value;
451+
// Should use 4 backticks even without explicit language
452+
assert.ok(value.includes('````'));
453+
assert.ok(value.includes(snippetWithBackticks));
454+
});
455+
456+
test('empty snippet still renders correctly', () => {
457+
const result = annotateSpecialMarkdownContent([
458+
content('Example: '),
459+
{
460+
kind: 'inlineReference',
461+
inlineReference: URI.parse('file:///empty.ts'),
462+
name: 'empty.ts',
463+
snippet: '',
464+
languageId: 'typescript'
465+
},
466+
]);
467+
468+
assert.strictEqual(result.length, 1);
469+
const md = result[0] as IChatMarkdownContent;
470+
const value = md.content.value;
471+
// Should still have fence markers for empty content
472+
assert.ok(value.includes('```typescript'));
473+
assert.ok(value.includes('```'));
474+
});
475+
});
318476
});

0 commit comments

Comments
 (0)