Skip to content

Commit 02ef2bf

Browse files
authored
Add MCP lifecycle tests on Enterprise given a base path (#871)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 15c7cc2 commit 02ef2bf

11 files changed

Lines changed: 709 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ jobs:
7575
path: enterprise/e2e/html
7676
edition: ${{ matrix.edition.name }}
7777
if: matrix.edition.name == 'enterprise'
78+
- name: E2E (enterprise-path)
79+
uses: ./.github/actions/e2e
80+
with:
81+
path: enterprise/e2e/path
82+
edition: ${{ matrix.edition.name }}
83+
if: matrix.edition.name == 'enterprise'
7884

7985
# Public instance
8086
- run: docker build . --file public/Dockerfile --progress plain

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ docker: docker-build
7676
$(MAKE) -C test/e2e/chaos EDITION=$(EDITION)
7777
ifeq ($(ENTERPRISE),ON)
7878
$(MAKE) -C enterprise/e2e/html EDITION=$(EDITION)
79+
$(MAKE) -C enterprise/e2e/path EDITION=$(EDITION)
7980
endif
8081

8182
.PHONY: docker-benchmark

enterprise/e2e/path/Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM one
2+
COPY one.json .
3+
RUN sourcemeta one.json --profile
4+
RUN set -e && test -d "$SOURCEMETA_ONE_WORKDIR" && \
5+
test -z "$(ls -A "$SOURCEMETA_ONE_WORKDIR")"
6+
RUN rm -rf "$SOURCEMETA_ONE_WORKDIR"

enterprise/e2e/path/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../../test/e2e/common.mk

enterprise/e2e/path/compose.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
services:
2+
sandbox:
3+
build:
4+
context: .
5+
dockerfile: Dockerfile
6+
args:
7+
SOURCEMETA_ONE_SANDBOX_EDITION: ${EDITION}
8+
environment:
9+
- SOURCEMETA_ONE_PORT=8001
10+
ports:
11+
- "${PORT}:8001"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
OPTIONS {{base}}/v1/catalog/self/v1/mcp
2+
HTTP 204
3+
[Asserts]
4+
bytes count == 0
5+
header "Access-Control-Allow-Origin" == "http://localhost:8000"
6+
header "Access-Control-Allow-Methods" == "POST, OPTIONS"
7+
header "Access-Control-Allow-Headers" == "Content-Type, MCP-Protocol-Version"
8+
header "Access-Control-Max-Age" == "3600"
9+
10+
OPTIONS {{base}}/v1/catalog/self/v1/mcp
11+
Origin: http://localhost:8000
12+
HTTP 204
13+
[Asserts]
14+
bytes count == 0
15+
header "Access-Control-Allow-Origin" == "http://localhost:8000"
16+
header "Access-Control-Allow-Methods" == "POST, OPTIONS"
17+
header "Access-Control-Allow-Headers" == "Content-Type, MCP-Protocol-Version"
18+
header "Access-Control-Max-Age" == "3600"
19+
20+
OPTIONS {{base}}/v1/catalog/self/v1/mcp
21+
Origin: https://evil.example
22+
HTTP 403
23+
Content-Type: application/json
24+
Access-Control-Allow-Origin: http://localhost:8000
25+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
26+
[Captures]
27+
last_response: body
28+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
29+
[Asserts]
30+
jsonpath "$.jsonrpc" == "2.0"
31+
jsonpath "$.id" not exists
32+
jsonpath "$.error.code" == 2
33+
jsonpath "$.error.message" == "Forbidden origin"
34+
35+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
36+
```
37+
{{last_response}}
38+
```
39+
HTTP 200
40+
[Asserts]
41+
jsonpath "$.valid" == true
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
POST {{base}}/v1/catalog/self/v1/mcp
2+
Content-Type: application/json
3+
```
4+
{
5+
"jsonrpc": "2.0",
6+
"id": 1,
7+
"method": "initialize",
8+
"params": {
9+
"protocolVersion": "2025-11-25",
10+
"capabilities": {},
11+
"clientInfo": { "name": "hurl", "version": "1.0.0" }
12+
}
13+
}
14+
```
15+
HTTP 200
16+
Content-Type: application/json
17+
Access-Control-Allow-Origin: http://localhost:8000
18+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
19+
[Captures]
20+
last_response: body
21+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
22+
[Asserts]
23+
jsonpath "$.jsonrpc" == "2.0"
24+
jsonpath "$.id" == 1
25+
jsonpath "$.result.protocolVersion" == "2025-11-25"
26+
jsonpath "$.result.capabilities" isObject
27+
jsonpath "$.result.capabilities" isEmpty
28+
jsonpath "$.result.serverInfo.name" == "sourcemeta-one-enterprise"
29+
jsonpath "$.result.serverInfo.title" == "Sourcemeta One Enterprise"
30+
jsonpath "$.result.serverInfo.version" matches "^.+$"
31+
32+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
33+
```
34+
{{last_response}}
35+
```
36+
HTTP 200
37+
[Asserts]
38+
jsonpath "$.valid" == true
39+
40+
POST {{base}}/v1/catalog/self/v1/mcp
41+
Content-Type: application/json
42+
```
43+
{ "jsonrpc": "2.0", "id": "abc", "method": "ping" }
44+
```
45+
HTTP 200
46+
Content-Type: application/json
47+
Access-Control-Allow-Origin: http://localhost:8000
48+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
49+
[Captures]
50+
last_response: body
51+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
52+
[Asserts]
53+
jsonpath "$.jsonrpc" == "2.0"
54+
jsonpath "$.id" == "abc"
55+
jsonpath "$.result" isObject
56+
jsonpath "$.result" isEmpty
57+
58+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
59+
```
60+
{{last_response}}
61+
```
62+
HTTP 200
63+
[Asserts]
64+
jsonpath "$.valid" == true
65+
66+
POST {{base}}/v1/catalog/self/v1/mcp
67+
Content-Type: application/json
68+
```
69+
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
70+
```
71+
HTTP 202
72+
Access-Control-Allow-Origin: http://localhost:8000
73+
[Asserts]
74+
bytes count == 0
75+
header "Link" not exists
76+
77+
POST {{base}}/v1/catalog/self/v1/mcp
78+
Content-Type: application/json
79+
```
80+
{
81+
"jsonrpc": "2.0",
82+
"method": "notifications/cancelled",
83+
"params": { "requestId": 99, "reason": "test" }
84+
}
85+
```
86+
HTTP 202
87+
Access-Control-Allow-Origin: http://localhost:8000
88+
[Asserts]
89+
bytes count == 0
90+
header "Link" not exists
91+
92+
POST {{base}}/v1/catalog/self/v1/mcp
93+
Content-Type: application/json
94+
```
95+
{
96+
"jsonrpc": "2.0",
97+
"method": "notifications/cancelled",
98+
"params": { "requestId": "never-issued" }
99+
}
100+
```
101+
HTTP 202
102+
Access-Control-Allow-Origin: http://localhost:8000
103+
[Asserts]
104+
bytes count == 0
105+
header "Link" not exists
106+
107+
POST {{base}}/v1/catalog/self/v1/mcp
108+
Content-Type: application/json
109+
```
110+
{ "jsonrpc": "2.0", "id": 5, "method": "tools/list" }
111+
```
112+
HTTP 200
113+
Content-Type: application/json
114+
Access-Control-Allow-Origin: http://localhost:8000
115+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
116+
[Captures]
117+
last_response: body
118+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
119+
[Asserts]
120+
jsonpath "$.jsonrpc" == "2.0"
121+
jsonpath "$.id" == 5
122+
jsonpath "$.error.code" == -32601
123+
jsonpath "$.error.message" == "Method not found"
124+
125+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
126+
```
127+
{{last_response}}
128+
```
129+
HTTP 200
130+
[Asserts]
131+
jsonpath "$.valid" == true
132+
133+
POST {{base}}/v1/catalog/self/v1/mcp
134+
Content-Type: application/json
135+
```
136+
{ "jsonrpc": "2.0", "id": 7, "method": "notifications/initialized" }
137+
```
138+
HTTP 200
139+
Content-Type: application/json
140+
Access-Control-Allow-Origin: http://localhost:8000
141+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
142+
[Captures]
143+
last_response: body
144+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
145+
[Asserts]
146+
jsonpath "$.jsonrpc" == "2.0"
147+
jsonpath "$.id" == 7
148+
jsonpath "$.error.code" == -32601
149+
jsonpath "$.error.message" == "Method not found"
150+
151+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
152+
```
153+
{{last_response}}
154+
```
155+
HTTP 200
156+
[Asserts]
157+
jsonpath "$.valid" == true
158+
159+
# The MCP route is mounted under /v1/catalog. Requests without the base path
160+
# must not match.
161+
162+
GET {{base}}/self/v1/mcp
163+
HTTP 404
164+
Content-Type: application/problem+json
165+
Access-Control-Allow-Origin: *
166+
[Asserts]
167+
jsonpath "$.status" == 404
168+
jsonpath "$.title" == "sourcemeta:one/not-found"
169+
170+
POST {{base}}/self/v1/mcp
171+
Content-Type: application/json
172+
```
173+
{ "jsonrpc": "2.0", "id": 1, "method": "ping" }
174+
```
175+
HTTP 404
176+
177+
OPTIONS {{base}}/self/v1/mcp
178+
HTTP 404
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
POST {{base}}/v1/catalog/self/v1/mcp
2+
Origin: http://localhost:8000
3+
Content-Type: application/json
4+
```
5+
{ "jsonrpc": "2.0", "id": 1, "method": "ping" }
6+
```
7+
HTTP 200
8+
Content-Type: application/json
9+
Access-Control-Allow-Origin: http://localhost:8000
10+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
11+
[Captures]
12+
last_response: body
13+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
14+
[Asserts]
15+
jsonpath "$.jsonrpc" == "2.0"
16+
jsonpath "$.id" == 1
17+
jsonpath "$.result" isObject
18+
jsonpath "$.result" isEmpty
19+
20+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
21+
```
22+
{{last_response}}
23+
```
24+
HTTP 200
25+
[Asserts]
26+
jsonpath "$.valid" == true
27+
28+
POST {{base}}/v1/catalog/self/v1/mcp
29+
Origin: https://evil.example
30+
Content-Type: application/json
31+
```
32+
{ "jsonrpc": "2.0", "id": 1, "method": "ping" }
33+
```
34+
HTTP 403
35+
Content-Type: application/json
36+
Access-Control-Allow-Origin: http://localhost:8000
37+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
38+
[Captures]
39+
last_response: body
40+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
41+
[Asserts]
42+
jsonpath "$.jsonrpc" == "2.0"
43+
jsonpath "$.id" not exists
44+
jsonpath "$.error.code" == 2
45+
jsonpath "$.error.message" == "Forbidden origin"
46+
47+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
48+
```
49+
{{last_response}}
50+
```
51+
HTTP 200
52+
[Asserts]
53+
jsonpath "$.valid" == true
54+
55+
POST {{base}}/v1/catalog/self/v1/mcp
56+
Origin: http://localhost:1234
57+
Content-Type: application/json
58+
```
59+
{ "jsonrpc": "2.0", "id": 1, "method": "ping" }
60+
```
61+
HTTP 403
62+
Content-Type: application/json
63+
Access-Control-Allow-Origin: http://localhost:8000
64+
Link: </v1/catalog/self/v1/schemas/mcp/response>; rel="describedby"
65+
[Captures]
66+
last_response: body
67+
schema_path: header "Link" regex "</v1/catalog([^>]+)>"
68+
[Asserts]
69+
jsonpath "$.jsonrpc" == "2.0"
70+
jsonpath "$.id" not exists
71+
jsonpath "$.error.code" == 2
72+
jsonpath "$.error.message" == "Forbidden origin"
73+
74+
POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
75+
```
76+
{{last_response}}
77+
```
78+
HTTP 200
79+
[Asserts]
80+
jsonpath "$.valid" == true

0 commit comments

Comments
 (0)