Skip to content

Commit 6cbb76f

Browse files
wherka-amaWaldek Herka
andauthored
feat: update schema mcp remote servers (#102)
* feat(schema): add support for remote HTTP MCP servers - Add 'type' field (required) with enum ['stdio', 'http'] for MCP servers - Implement conditional validation using JSON Schema allOf with if/then: * stdio type requires 'command' field * http type requires 'url' field - Add 'url' property with URI format validation for HTTP endpoints - Update all MCP test fixtures to include type field - Add 3 new tests for stdio/http specific validation - Fix pre-existing issue: exclude e2e tests from unit test glob pattern (e2e tests use Playwright which conflicts with Mocha) - Fix npm audit vulnerabilities (lodash, diff) BREAKING CHANGE: Existing collections with MCP servers must add 'type: stdio' to their MCP server configurations. Closes #<issue-number> * fix(schema): remove merge conflict markers from collection.schema.json Critical fix: Removed unresolved merge conflict markers that were causing JSON parsing errors and schema validation failures. * fix(tests): remove 3 outdated tests that contradict backward compatibility These tests expected validation to fail when 'type' field is missing, but our schema intentionally allows this for backward compatibility - servers without 'type' default to stdio behavior and only require 'command' field. The schema design is correct; these tests were testing incorrect behavior. * fix: ensuring that the test-dist is properly cleaned when running local validation + restoring the e2e tests --------- Co-authored-by: Waldek Herka <waldek.herka@no.reply>
1 parent b389a34 commit 6cbb76f

File tree

5 files changed

+584
-119
lines changed

5 files changed

+584
-119
lines changed

.github/workflows/scripts/validate-locally.sh

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,21 @@ run_step() {
3838

3939
# 1. Clean previous builds
4040
run_step "Clean build artifacts" "npm run coverage:clean 2>/dev/null || true"
41-
42-
# 2. Install dependencies
41+
# 2. Clean test-dist
42+
run_step "Clean test-dist" "rm -rf test-dist"
43+
# 3. Install dependencies
4344
run_step "Install dependencies" "npm ci --fund=false"
44-
45-
# 3. Security audit
45+
# 4. Security audit
4646
run_step "Security audit (npm)" "npm audit --omit=dev --audit-level=moderate || echo 'Audit warnings found'"
47-
48-
# 4. Lint code
47+
# 5. Lint code
4948
run_step "ESLint validation" "npm run lint"
50-
51-
# 5. Type checking & compilation
49+
# 6. Type checking & compilation
5250
run_step "TypeScript compilation" "npm run compile"
53-
54-
# 6. Compile tests
51+
# 7. Compile tests
5552
run_step "Compile test suite" "npm run compile-tests"
56-
57-
# 7. Run unit tests
53+
# 8. Run unit tests
5854
run_step "Unit tests" "npm run test:unit"
59-
60-
# 8. Run integration tests (if display available)
55+
# 9. Run integration tests (if display available)
6156
if [ -n "$DISPLAY" ] || command -v xvfb-run &> /dev/null; then
6257
if command -v xvfb-run &> /dev/null; then
6358
run_step "Integration tests (xvfb)" "xvfb-run -a npm run test:integration"
@@ -68,10 +63,10 @@ else
6863
echo -e "${YELLOW}⚠ Skipping integration tests (no display available)${NC}"
6964
fi
7065

71-
# 9. Package VSIX (with production config)
66+
# 10. Package VSIX (with production config)
7267
run_step "Package VSIX (production mode)" "npm run package:full"
7368

74-
# 10. Validate VSIX contents
69+
# 11. Validate VSIX contents
7570
run_step "Validate VSIX package" "
7671
VSIX_FILE=\$(ls -t *.vsix 2>/dev/null | head -1)
7772
if [ -n \"\$VSIX_FILE\" ]; then
@@ -85,7 +80,7 @@ run_step "Validate VSIX package" "
8580
fi
8681
"
8782

88-
# 11. License compliance check (optional)
83+
# 12. License compliance check (optional)
8984
if command -v npx &> /dev/null; then
9085
run_step "License compliance check" "npx license-checker --summary 2>/dev/null || echo 'license-checker not available'"
9186
fi

schemas/collection.schema.json

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,17 @@
101101
"^[a-zA-Z0-9_-]+$": {
102102
"type": "object",
103103
"description": "MCP server configuration",
104-
"required": [
105-
"command"
106-
],
107104
"properties": {
105+
"type": {
106+
"type": "string",
107+
"description": "Transport type for the MCP server",
108+
"enum": ["stdio", "http", "sse"],
109+
"default": "stdio",
110+
"examples": ["stdio", "http", "sse"]
111+
},
108112
"command": {
109113
"type": "string",
110-
"description": "Command to start the MCP server",
114+
"description": "Command to start the MCP server (required for stdio type)",
111115
"examples": [
112116
"node",
113117
"python",
@@ -116,7 +120,7 @@
116120
},
117121
"args": {
118122
"type": "array",
119-
"description": "Arguments for the server command",
123+
"description": "Arguments for the server command (stdio only)",
120124
"items": {
121125
"type": "string"
122126
},
@@ -134,17 +138,99 @@
134138
},
135139
"env": {
136140
"type": "object",
137-
"description": "Environment variables for the server",
141+
"description": "Environment variables for the server (stdio only)",
138142
"additionalProperties": {
139143
"type": "string"
140144
}
141145
},
146+
"envFile": {
147+
"type": "string",
148+
"description": "Path to an environment file to load variables from (stdio only)",
149+
"examples": [
150+
"${workspaceFolder}/.env",
151+
"${bundlePath}/.env"
152+
]
153+
},
154+
"url": {
155+
"type": "string",
156+
"description": "URL for the remote MCP server (required for http/sse types). Supports HTTP/HTTPS URLs, Unix sockets (unix:///path), and Windows named pipes (pipe:///pipe/name)",
157+
"examples": [
158+
"http://localhost:3000/mcp",
159+
"https://api.example.com/mcp",
160+
"unix:///tmp/mcp.sock",
161+
"pipe:///pipe/mcp-server"
162+
]
163+
},
164+
"headers": {
165+
"type": "object",
166+
"description": "HTTP headers for authentication or configuration (http/sse only)",
167+
"additionalProperties": {
168+
"type": "string"
169+
},
170+
"examples": [
171+
{
172+
"Authorization": "Bearer ${input:api-token}"
173+
}
174+
]
175+
},
142176
"disabled": {
143177
"type": "boolean",
144178
"description": "Whether the server is disabled",
145179
"default": false
146180
}
147181
},
182+
"allOf": [
183+
{
184+
"if": {
185+
"properties": {
186+
"type": {
187+
"const": "stdio"
188+
}
189+
}
190+
},
191+
"then": {
192+
"required": ["command"]
193+
}
194+
},
195+
{
196+
"if": {
197+
"not": {
198+
"properties": {
199+
"type": {
200+
"const": "stdio"
201+
}
202+
}
203+
},
204+
"required": ["type"]
205+
},
206+
"then": {
207+
"required": ["url"]
208+
}
209+
},
210+
{
211+
"if": {
212+
"properties": {
213+
"type": {
214+
"enum": ["http", "sse"]
215+
}
216+
},
217+
"required": ["type"]
218+
},
219+
"then": {
220+
"required": ["url"]
221+
}
222+
},
223+
{
224+
"if": {
225+
"not": {
226+
"required": ["type"]
227+
}
228+
},
229+
"then": {
230+
"required": ["command"]
231+
}
232+
}
233+
],
148234
"additionalProperties": false
149235
}
150236
},

src/types/mcp.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,39 @@
22
* MCP (Model Context Protocol) Configuration Types
33
*/
44

5-
export interface McpServerConfig {
6-
type?: string; // e.g., "stdio" - optional, defaults to stdio
5+
/**
6+
* Base MCP server configuration
7+
*/
8+
export interface McpServerConfigBase {
9+
disabled?: boolean;
10+
description?: string;
11+
}
12+
13+
/**
14+
* Stdio MCP server configuration (local process)
15+
*/
16+
export interface McpStdioServerConfig extends McpServerConfigBase {
17+
type?: 'stdio'; // Optional, defaults to stdio for backward compatibility
718
command: string;
819
args?: string[];
920
env?: Record<string, string>;
10-
disabled?: boolean;
11-
description?: string;
21+
envFile?: string; // Path to environment file
1222
}
1323

24+
/**
25+
* Remote MCP server configuration (HTTP/SSE)
26+
*/
27+
export interface McpRemoteServerConfig extends McpServerConfigBase {
28+
type: 'http' | 'sse';
29+
url: string; // Supports http://, https://, unix://, pipe://
30+
headers?: Record<string, string>; // For authentication
31+
}
32+
33+
/**
34+
* Union type for all MCP server configurations
35+
*/
36+
export type McpServerConfig = McpStdioServerConfig | McpRemoteServerConfig;
37+
1438
export interface McpTaskDefinition {
1539
input?: string;
1640
output?: string;
@@ -26,13 +50,10 @@ export interface McpConfiguration {
2650
inputs?: any[]; // Legacy field, preserved for compatibility
2751
}
2852

29-
export interface McpServerDefinition {
30-
command: string;
31-
args?: string[];
32-
env?: Record<string, string>;
33-
disabled?: boolean;
34-
description?: string;
35-
}
53+
/**
54+
* Legacy type alias for backward compatibility
55+
*/
56+
export type McpServerDefinition = McpStdioServerConfig;
3657

3758
export type McpServersManifest = Record<string, McpServerDefinition>;
3859

test/services/McpServerManager.repositoryScope.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ suite('McpServerManager Repository Scope Test Suite', () => {
304304
assert.ok(config);
305305
const serverConfig = config.servers['prompt-registry:test-bundle:my-server'];
306306
assert.ok(serverConfig);
307-
assert.strictEqual(serverConfig.command, 'node', 'server should be overwritten');
307+
assert.ok(!serverConfig.type || serverConfig.type === 'stdio', 'should be stdio server');
308+
assert.strictEqual((serverConfig as any).command, 'node', 'server should be overwritten');
308309
});
309310

310311
test('should add .vscode/mcp.json to git exclude for local-only mode', async () => {

0 commit comments

Comments
 (0)