Skip to content

Feat/mcp eval phases - #102

Open
operetz-rh wants to merge 12 commits into
mcp-evaluation-pipelinefrom
feat/mcp-eval-phases
Open

operetz-rh wants to merge 12 commits into
mcp-evaluation-pipelinefrom
feat/mcp-eval-phases

Conversation

@operetz-rh

Copy link
Copy Markdown

Summary

Adds MCP-server evaluation Phase 1 (static / build-time) and Phase 2 (deterministic conformance) per the ADR (Approach 4), scoped to those two phases only — Phase 3 (behavioral) and pipeline orchestration are out of scope here. Targeted at the mcp-evaluation-pipeline branch so all MCP pipeline pieces land together before the combined PR to main.

Changes

  • Phase 1 static scanners + gates (abevalflow/mcp/phase1, scripts/mcp): secrets (gitleaks), no-user-code (semgrep, offline ruleset for Python/JS/TS/Go/Java), and license (licensee). Weighted 0–1 scoring with block / warn / disabled modes; a missing scan fails in block mode.
  • Phase 2 deterministic conformance (abevalflow/mcp/phase2, scripts/mcp): black-box probe of a running server over Streamable HTTP (JSON-RPC 2.0), 10 checks, three-state model (pass / fail / not_evaluated — unreachable or undecidable never fails). No LLM. Two checks are consumed from existing Compass facts rather than re-probed.
  • Tekton tasks under pipeline/tasks/konflux/: mcp-phase1-static and mcp-phase2-conformance, following this branch's convention (name == filename, app.kubernetes.io labels).
  • Tests: unit + integration tests for both phases.
  • Coverage: the no-user-code scan surfaces a coverage block so a zero-finding pass shows what was actually scanned.

Test plan

Related

APPENG-6254

operetz-rh and others added 6 commits September 30, 2026 13:39
- Move mcp-phase{1,2} tasks to pipeline/tasks/konflux/, rename to
  mcp-phase1-static / mcp-phase2-conformance, and adopt the app.kubernetes.io
  labels used on the deploy-pipeline branch (name == filename, no namespace).
- Trim redundant/duplicated comments in the Phase 1/2 scanners and gates;
  keep only the WHY notes. No logic change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@operetz-rh operetz-rh self-assigned this Oct 1, 2026

@IlonaShishov IlonaShishov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @operetz-rh!
Please consider my suggestions bellow

Comment thread pipeline/tasks/konflux/mcp-phase1-static.yaml Outdated
Comment thread pipeline/tasks/konflux/mcp-phase1-static.yaml Outdated
Comment thread pipeline/tasks/konflux/mcp-phase1-static.yaml Outdated
Comment thread pipeline/tasks/konflux/mcp-phase2-conformance.yaml Outdated
@IlonaShishov

Copy link
Copy Markdown

Another review item:
The split between scripts/mcp/ and abevalflow/mcp/ has a reasonable intent (execution/I/O vs pure evaluation logic) but it's not self-documenting and one must really understand the code for this to make sense. Within scripts/mcp/ there are scanners, probes, evaluators, and utilities and they are all mixed with inconsistent naming - you can't tell which files are Tekton entry points vs internal helpers. Please make the separation clearer through naming and file structure.

operetz-rh and others added 2 commits October 6, 2026 14:29
…arer layout

- Add containers/mcp-eval/Containerfile baking scanners (gitleaks, semgrep,
  licensee) + deps; both Phase 1/2 tasks use it and drop the runtime git clone,
  tool installs, and pipeline-repo-url/revision params
- Trim unused Tekton results (per-gate passes, not-evaluated-count); keep
  phase1/phase2-passed + report-path
- Rename mcp_client.py -> _mcp_client.py and document entry points vs helpers
- compass_fetch: degrade missing/malformed facts to not_evaluated instead of
  aborting Phase 2; pin image Python deps

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@IlonaShishov IlonaShishov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the Refactor, please see a few more minor comments.
We are almost there!

Comment thread pipeline/tasks/konflux/mcp-phase1-static.yaml Outdated
Comment thread pipeline/tasks/konflux/mcp-phase2-conformance.yaml
Comment thread containers/mcp-eval/Containerfile Outdated
operetz-rh and others added 3 commits October 11, 2026 19:17
…per, scanner hardening

Phase 2 probe / client:
- Parse all SSE data frames and select the one whose id matches the request
  (with a string-id fallback), so an interleaved notification no longer
  masquerades as the response.
- Paginate tools/list via nextCursor (list_all_tools, with cursor dedup) so
  schema/annotation checks see tools beyond page one.
- Guard a non-object JSON-RPC "error" (e.g. a bare string) instead of crashing.
- Tighten _schema_is_object: require the declared type to permit "object"
  (array types like ["object","null"] are accepted) and reject malformed
  object keywords, while still accepting a typeless node with object keywords.

Phase 1 scanners:
- license_scan: licensee exits non-zero when it finds no license; evaluate its
  JSON output as a license-missing finding instead of a tool error. A non-zero
  exit with empty/unparseable output is still treated as a genuine tool error.
- no_user_code_scan: disable inline nosem suppression (--disable-nosem) and the
  phone-home version check (--disable-version-check); flag a committed
  .semgrepignore as a high-severity finding (semgrep honors it, so its presence
  fails a blocking gate).

Tekton tasks / image:
- Extract the duplicated gate step into scripts/mcp/run_gate.sh (baked in the
  image) and call it from both phases; a missing/invalid summary now fails
  loudly rather than writing an empty Tekton result.
- Drop the SEMGREP_ENABLE_VERSION_CHECK env var from the phase 1 task (now a
  scanner flag) and pin the licensee gem version in the Containerfile.

Docs/tests:
- Correct the Phase 1/2 implementation note in abevalflow/mcp docstring.
- Add unit tests for SSE id-matching, pagination, schema shape (incl. array
  types), non-object errors, licensee non-zero exits, and .semgrepignore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make entry-points-vs-helpers legible by filename, per PR review. Convention:
run_* = Tekton-invoked entry point (python -m scripts.mcp.<name> or run_gate.sh),
_* = imported helper. No bare names.

Renamed (git-tracked moves):
  secrets_scan.py       -> run_secrets_scan.py
  no_user_code_scan.py  -> run_no_user_code_scan.py
  license_scan.py       -> run_license_scan.py
  phase2_probe.py       -> run_phase2_probe.py
  compass_fetch.py      -> run_compass_fetch.py

Updated the python -m paths in both Konflux task YAMLs, aliased the new names
in the phase 1/2 test imports (usage sites unchanged), and fixed docstring/
comment path references in abevalflow/mcp. Added scripts/mcp/README.md
documenting the convention with an entry-point -> phase -> emits table and the
helper list. Behavior unchanged.

Verify: ruff check + format clean; 47 passed, 2 skipped; live mock and
openshift-mcp-server runs identical to prior baseline (P1 FAIL 0.75;
P2 mock PASS 1.00, openshift FAIL 0.88 catching error-unknown-method).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants