Skip to content

Commit 0bc3e70

Browse files
committed
[FIX] tests
1 parent b64de9d commit 0bc3e70

5 files changed

Lines changed: 297 additions & 1 deletion

File tree

PRD.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010
- `SPEC.md` визначає технічні MUST/SHOULD контракти реалізації.
1111
- `TOOLSET.md` визначає публічний контракт tool names/params/responses/errors.
1212

13+
## 0.1 Поточний статус delivery (as of 2026-03-03)
14+
Підтверджений стан у workspace:
15+
- `make demo-all` проходить end-to-end у `demo`.
16+
- Інсталяційний pipeline (`install/publish/migrate`) проходить стабільно.
17+
- `php artisan emcp:test` (`initialize`, `tools/list`) -> PASS.
18+
- Runtime HTTP integration (`tests/Integration/RuntimeIntegrationHttpTest.php`) -> PASS.
19+
- Підтверджено API шлях читання даних з БД через MCP (`evo.content.search`, `evo.content.root_tree`, `evo.content.get`).
20+
- Автоматично генерується `demo/logs.md` з деталями токена, MCP запитів/відповідей і manual-check командами.
21+
22+
Залишок до RC-1 (core platform hardening):
23+
- live runtime integration job у GitHub Actions зі staging env/secrets;
24+
- live async checks для `sTask` (progress/result/retry/failover);
25+
- live stream/rate-limit операційні перевірки;
26+
- зафіксовані RC evidence артефакти (security sanity + performance baseline).
27+
1328
## 1. Контекст
1429
- Цільовий пакет: `eMCP` у `/Users/dmi3yy/PhpstormProjects/Extras/eMCP`.
1530
- Upstream MCP SDK: `/Users/dmi3yy/PhpstormProjects/Extras/LaravelMcp` (`laravel/mcp`).

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ make demo-all
237237
```
238238

239239
This target installs demo Evo, starts `php -S`, issues sApi JWT, runs `php artisan emcp:test`, then runs `composer run test` with HTTP runtime integration enabled.
240+
After run, detailed evidence is written to:
241+
- `demo/logs.md` (token/masked auth info, MCP request payloads, HTTP statuses, responses, manual verification commands)
242+
- `/tmp/emcp-demo-php-server.log` (php built-in server log)
240243

241244
If GitHub API auth is needed during install, pass token via ENV (same pattern as `evolution`):
242245

@@ -246,6 +249,25 @@ GITHUB_PAT=ghp_xxx make demo-all
246249

247250
Fallback ENV names are also supported: `GITHUB_TOKEN`, `GH_TOKEN`.
248251

252+
Manual content-read MCP examples (same calls used in `demo/logs.md`):
253+
254+
```bash
255+
# list tools
256+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
257+
-d '{"jsonrpc":"2.0","id":"tools-1","method":"tools/list","params":{}}' \
258+
'http://127.0.0.1:8787/api/v1/mcp/content'
259+
260+
# read content slice from DB
261+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
262+
-d '{"jsonrpc":"2.0","id":"search-1","method":"tools/call","params":{"name":"evo.content.search","arguments":{"limit":3,"offset":0}}}' \
263+
'http://127.0.0.1:8787/api/v1/mcp/content'
264+
265+
# read one document
266+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
267+
-d '{"jsonrpc":"2.0","id":"get-1","method":"tools/call","params":{"name":"evo.content.get","arguments":{"id":1}}}' \
268+
'http://127.0.0.1:8787/api/v1/mcp/content'
269+
```
270+
249271
Optional runtime integration check (against deployed environment):
250272

251273
```bash

README.uk.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ make demo-all
236236
```
237237

238238
Ця ціль встановлює demo Evo, запускає `php -S`, видає sApi JWT, виконує `php artisan emcp:test`, а потім `composer run test` з увімкненою HTTP runtime integration перевіркою.
239+
Після виконання детальні докази записуються у:
240+
- `demo/logs.md` (masked token, MCP payload-и, HTTP статуси, відповіді, manual verification команди)
241+
- `/tmp/emcp-demo-php-server.log` (лог PHP built-in server)
239242

240243
Якщо під час інсталяції потрібна GitHub авторизація API, передай токен через ENV (як у `evolution`):
241244

@@ -245,6 +248,25 @@ GITHUB_PAT=ghp_xxx make demo-all
245248

246249
Також підтримуються `GITHUB_TOKEN` і `GH_TOKEN`.
247250

251+
Ручні приклади MCP читання content (ті самі виклики, що пишуться у `demo/logs.md`):
252+
253+
```bash
254+
# список tools
255+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
256+
-d '{"jsonrpc":"2.0","id":"tools-1","method":"tools/list","params":{}}' \
257+
'http://127.0.0.1:8787/api/v1/mcp/content'
258+
259+
# читання content з БД
260+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
261+
-d '{"jsonrpc":"2.0","id":"search-1","method":"tools/call","params":{"name":"evo.content.search","arguments":{"limit":3,"offset":0}}}' \
262+
'http://127.0.0.1:8787/api/v1/mcp/content'
263+
264+
# читання одного документа
265+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
266+
-d '{"jsonrpc":"2.0","id":"get-1","method":"tools/call","params":{"name":"evo.content.get","arguments":{"id":1}}}' \
267+
'http://127.0.0.1:8787/api/v1/mcp/content'
268+
```
269+
248270
Опційна runtime integration перевірка (проти розгорнутого середовища):
249271

250272
```bash

SPEC.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,25 @@
55

66
Status markers:
77
- `SPEC Version`: `1.0-contract`
8-
- `Runtime Status`: `Gate C baseline implemented (full validation pending)`
8+
- `Runtime Status`: `Gate C baseline validated in demo runtime; RC-1 hardening pending`
99

1010
Normative hierarchy:
1111
- `SPEC.md` defines platform-wide MUST/SHOULD rules.
1212
- `TOOLSET.md` defines canonical public tool contract (`evo.content.*`, `evo.model.*`).
1313
- `DOCS*.md` are implementation and usage guides; if conflict occurs, `SPEC.md` + `TOOLSET.md` win.
1414

15+
Current validation snapshot (2026-03-03):
16+
- `make demo-all` PASS (install + smoke + runtime integration).
17+
- `php artisan emcp:test` PASS for `initialize` and `tools/list`.
18+
- Runtime HTTP integration PASS for `/api/v1/mcp/{server}`.
19+
- Verified content-read tool flow in runtime (`evo.content.search`, `evo.content.root_tree`, `evo.content.get`).
20+
- One-click verification writes `demo/logs.md` with request/response evidence.
21+
22+
Open RC-1 validation scope:
23+
- live CI runtime integration (external env/secrets) is not yet mandatory-on-push;
24+
- live async `sTask` e2e checks (queue lifecycle/progress/failover) are not yet enforced in CI;
25+
- live stream/rate-limit infra checks remain pending as RC evidence.
26+
1527
## 0. Джерела
1628
- `/Users/dmi3yy/PhpstormProjects/Extras/LaravelMcp` — upstream `laravel/mcp`.
1729
- `/Users/dmi3yy/PhpstormProjects/Extras/LaravelAi` — upstream SDK packaging patterns consumed via Evo thin wrappers.

scripts/demo_verify.sh

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SAPI_BASE_PATH=${SAPI_BASE_PATH:-api}
2020
SAPI_VERSION=${SAPI_VERSION:-v1}
2121
SERVER_LOG=${SERVER_LOG:-/tmp/emcp-demo-php-server.log}
2222
SERVER_PID=
23+
TMP_DIR=
2324

2425
if [ "${#SAPI_JWT_SECRET}" -lt 32 ]; then
2526
echo "[demo-verify] SAPI_JWT_SECRET is shorter than 32 chars; using SHA-256 normalized secret for compatibility."
@@ -42,6 +43,9 @@ case "${DEMO_CORE_DIR}" in
4243
*) DEMO_CORE_DIR_PATH="${REPO_ROOT}/${DEMO_CORE_DIR}" ;;
4344
esac
4445

46+
LOGS_MD=${LOGS_MD:-${DEMO_DIR_PATH}/logs.md}
47+
TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/emcp-demo-verify.XXXXXX")
48+
4549
cleanup() {
4650
status=$?
4751

@@ -50,6 +54,10 @@ cleanup() {
5054
wait "${SERVER_PID}" 2>/dev/null || true
5155
fi
5256

57+
if [ -n "${TMP_DIR}" ] && [ -d "${TMP_DIR}" ]; then
58+
rm -rf "${TMP_DIR}" >/dev/null 2>&1 || true
59+
fi
60+
5361
if [ "${status}" -ne 0 ] && [ -f "${SERVER_LOG}" ]; then
5462
echo "[demo-verify] FAILED (exit ${status}). php -S log tail:" >&2
5563
tail -n 120 "${SERVER_LOG}" >&2 || true
@@ -170,13 +178,230 @@ echo $signingInput . "." . $base64Url($signature);
170178
')
171179
fi
172180

181+
token_masked=$(printf '%s' "${token}" | php -r '
182+
$token = trim((string)stream_get_contents(STDIN));
183+
if ($token === "") {
184+
echo "";
185+
exit(0);
186+
}
187+
$len = strlen($token);
188+
if ($len <= 24) {
189+
echo $token;
190+
exit(0);
191+
}
192+
echo substr($token, 0, 16) . "..." . substr($token, -8);
193+
')
194+
195+
mcp_url="${DEMO_BASE_URL}${api_prefix}/mcp/${EMCP_SERVER_HANDLE}"
196+
session_id=""
197+
198+
initialize_payload='{"jsonrpc":"2.0","id":"init-doc","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"emcp-demo-verify","version":"1.0.0"}}}'
199+
tools_list_payload='{"jsonrpc":"2.0","id":"tools-doc","method":"tools/list","params":{}}'
200+
content_search_payload='{"jsonrpc":"2.0","id":"search-doc","method":"tools/call","params":{"name":"evo.content.search","arguments":{"limit":3,"offset":0}}}'
201+
content_root_tree_payload='{"jsonrpc":"2.0","id":"root-doc","method":"tools/call","params":{"name":"evo.content.root_tree","arguments":{"limit":3,"offset":0,"depth":2}}}'
202+
content_get_payload='{"jsonrpc":"2.0","id":"get-doc","method":"tools/call","params":{"name":"evo.content.get","arguments":{"id":1}}}'
203+
204+
init_headers_file="${TMP_DIR}/init.headers"
205+
init_raw=$(curl -sS -D "${init_headers_file}" \
206+
-H 'Content-Type: application/json' \
207+
-H "Authorization: Bearer ${token}" \
208+
-d "${initialize_payload}" \
209+
-w "\n__HTTP_CODE__:%{http_code}" \
210+
"${mcp_url}" || true)
211+
init_http_code=$(printf '%s' "${init_raw}" | sed -n 's/^__HTTP_CODE__://p' | tail -n 1)
212+
init_response=$(printf '%s' "${init_raw}" | sed '/^__HTTP_CODE__:/d')
213+
session_id=$(awk 'BEGIN{IGNORECASE=1} /^MCP-Session-Id:/{gsub("\r","",$2); print $2}' "${init_headers_file}" | tail -n 1)
214+
215+
mcp_post_with_optional_session() {
216+
payload="$1"
217+
headers_file="$2"
218+
if [ -n "${session_id}" ]; then
219+
curl -sS -D "${headers_file}" \
220+
-H 'Content-Type: application/json' \
221+
-H "Authorization: Bearer ${token}" \
222+
-H "MCP-Session-Id: ${session_id}" \
223+
-d "${payload}" \
224+
-w "\n__HTTP_CODE__:%{http_code}" \
225+
"${mcp_url}" || true
226+
return
227+
fi
228+
229+
curl -sS -D "${headers_file}" \
230+
-H 'Content-Type: application/json' \
231+
-H "Authorization: Bearer ${token}" \
232+
-d "${payload}" \
233+
-w "\n__HTTP_CODE__:%{http_code}" \
234+
"${mcp_url}" || true
235+
}
236+
237+
tools_headers_file="${TMP_DIR}/tools.headers"
238+
tools_raw=$(mcp_post_with_optional_session "${tools_list_payload}" "${tools_headers_file}")
239+
tools_http_code=$(printf '%s' "${tools_raw}" | sed -n 's/^__HTTP_CODE__://p' | tail -n 1)
240+
tools_response=$(printf '%s' "${tools_raw}" | sed '/^__HTTP_CODE__:/d')
241+
242+
search_headers_file="${TMP_DIR}/search.headers"
243+
search_raw=$(mcp_post_with_optional_session "${content_search_payload}" "${search_headers_file}")
244+
search_http_code=$(printf '%s' "${search_raw}" | sed -n 's/^__HTTP_CODE__://p' | tail -n 1)
245+
search_response=$(printf '%s' "${search_raw}" | sed '/^__HTTP_CODE__:/d')
246+
247+
root_headers_file="${TMP_DIR}/root.headers"
248+
root_raw=$(mcp_post_with_optional_session "${content_root_tree_payload}" "${root_headers_file}")
249+
root_http_code=$(printf '%s' "${root_raw}" | sed -n 's/^__HTTP_CODE__://p' | tail -n 1)
250+
root_response=$(printf '%s' "${root_raw}" | sed '/^__HTTP_CODE__:/d')
251+
252+
get_headers_file="${TMP_DIR}/get.headers"
253+
get_raw=$(mcp_post_with_optional_session "${content_get_payload}" "${get_headers_file}")
254+
get_http_code=$(printf '%s' "${get_raw}" | sed -n 's/^__HTTP_CODE__://p' | tail -n 1)
255+
get_response=$(printf '%s' "${get_raw}" | sed '/^__HTTP_CODE__:/d')
256+
173257
echo "[demo-verify] Step 4/4: running full test suite with runtime HTTP integration"
258+
259+
set +e
174260
EMCP_INTEGRATION_ENABLED=1 \
175261
EMCP_BASE_URL="${DEMO_BASE_URL}" \
176262
EMCP_API_PATH="${api_prefix}/mcp/{server}" \
177263
EMCP_API_TOKEN="${token}" \
178264
EMCP_SERVER_HANDLE="${EMCP_SERVER_HANDLE}" \
179265
EMCP_DISPATCH_CHECK="${EMCP_DISPATCH_CHECK}" \
180266
composer run test
267+
test_exit=$?
268+
set -e
269+
270+
test_status="PASS"
271+
if [ "${test_exit}" -ne 0 ]; then
272+
test_status="FAIL"
273+
fi
274+
275+
run_utc_ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
276+
277+
cat > "${LOGS_MD}" <<EOF
278+
# eMCP Demo Verify Log
279+
280+
Generated at (UTC): \`${run_utc_ts}\`
281+
Result: **${test_status}** (exit code: \`${test_exit}\`)
282+
283+
## Environment
284+
285+
- Base URL: \`${DEMO_BASE_URL}\`
286+
- API prefix: \`${api_prefix}\`
287+
- MCP endpoint: \`${mcp_url}\`
288+
- Server handle: \`${EMCP_SERVER_HANDLE}\`
289+
- Token endpoint: \`${DEMO_BASE_URL}${api_prefix}/token\`
290+
- Token (masked): \`${token_masked}\`
291+
- MCP Session ID: \`${session_id:-n/a}\`
292+
- php -S log file: \`${SERVER_LOG}\`
293+
294+
## Smoke Check
295+
296+
\`php artisan emcp:test\`: passed (initialize/tools:list OK)
297+
298+
## HTTP / MCP Probe Requests
299+
300+
### 1) initialize
301+
302+
Request:
303+
\`\`\`json
304+
${initialize_payload}
305+
\`\`\`
306+
307+
HTTP: \`${init_http_code}\`
308+
309+
Response:
310+
\`\`\`json
311+
${init_response}
312+
\`\`\`
313+
314+
### 2) tools/list
315+
316+
Request:
317+
\`\`\`json
318+
${tools_list_payload}
319+
\`\`\`
320+
321+
HTTP: \`${tools_http_code}\`
322+
323+
Response:
324+
\`\`\`json
325+
${tools_response}
326+
\`\`\`
327+
328+
### 3) site content via evo.content.search
329+
330+
Request:
331+
\`\`\`json
332+
${content_search_payload}
333+
\`\`\`
334+
335+
HTTP: \`${search_http_code}\`
336+
337+
Response:
338+
\`\`\`json
339+
${search_response}
340+
\`\`\`
341+
342+
### 4) site content via evo.content.root_tree
343+
344+
Request:
345+
\`\`\`json
346+
${content_root_tree_payload}
347+
\`\`\`
348+
349+
HTTP: \`${root_http_code}\`
350+
351+
Response:
352+
\`\`\`json
353+
${root_response}
354+
\`\`\`
355+
356+
### 5) site content via evo.content.get (id=1)
357+
358+
Request:
359+
\`\`\`json
360+
${content_get_payload}
361+
\`\`\`
362+
363+
HTTP: \`${get_http_code}\`
364+
365+
Response:
366+
\`\`\`json
367+
${get_response}
368+
\`\`\`
369+
370+
## How To Verify Manually
371+
372+
1. Get token:
373+
\`\`\`bash
374+
curl -sS -H 'Content-Type: application/json' \\
375+
-d '{"username":"${DEMO_ADMIN_USERNAME}","password":"${DEMO_ADMIN_PASSWORD}"}' \\
376+
'${DEMO_BASE_URL}${api_prefix}/token'
377+
\`\`\`
378+
379+
2. Initialize MCP:
380+
\`\`\`bash
381+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \\
382+
-d '${initialize_payload}' \\
383+
'${mcp_url}'
384+
\`\`\`
385+
386+
3. Read site content (search):
387+
\`\`\`bash
388+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \\
389+
-d '${content_search_payload}' \\
390+
'${mcp_url}'
391+
\`\`\`
392+
393+
4. Read one document (id=1):
394+
\`\`\`bash
395+
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \\
396+
-d '${content_get_payload}' \\
397+
'${mcp_url}'
398+
\`\`\`
399+
EOF
400+
401+
echo "[demo-verify] Wrote detailed run log: ${LOGS_MD}"
402+
403+
if [ "${test_exit}" -ne 0 ]; then
404+
exit "${test_exit}"
405+
fi
181406

182407
echo "[demo-verify] PASS: demo is running and MCP checks are green."

0 commit comments

Comments
 (0)