-
Notifications
You must be signed in to change notification settings - Fork 0
artifact: add MCP context bundle reference example #209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| { | ||
| "artifact_id": "mcp_context_bundle_ref_example_v1", | ||
| "bundle": { | ||
| "branch": "feat/mcp-context-bundle-ref-example", | ||
| "changed_files": [ | ||
| "artifacts/mcp_context_bundle_ref_example.json", | ||
| "scripts/generate_mcp_context_bundle_ref_example.py", | ||
| "tests/test_agent_artifact_bundle.py" | ||
| ], | ||
| "mcp_context_output_ref": "artifacts/mcp_context_layer_example.json", | ||
| "ok": true, | ||
| "result": "PASS", | ||
| "safe_pr_gate": { | ||
| "allow_dirty": false, | ||
| "allowed_prefixes": [], | ||
| "branch": "feat/mcp-context-bundle-ref-example", | ||
| "changed_paths": [ | ||
| "artifacts/mcp_context_bundle_ref_example.json", | ||
| "scripts/generate_mcp_context_bundle_ref_example.py", | ||
| "tests/test_agent_artifact_bundle.py" | ||
| ], | ||
| "ok": true, | ||
| "problems": [], | ||
| "result": "PASS", | ||
| "status_short": [] | ||
| }, | ||
| "validation_evidence": [ | ||
| { | ||
| "command": "python -m compileall -q scripts/agent_artifact_bundle.py scripts/generate_mcp_context_bundle_ref_example.py", | ||
| "result": "pass" | ||
| }, | ||
| { | ||
| "command": "pytest tests/test_agent_artifact_bundle.py -q", | ||
| "result": "pass" | ||
| }, | ||
| { | ||
| "command": "python scripts/validate_agent_artifact_bundle.py --bundle artifacts/mcp_context_bundle_ref_example.json", | ||
| "result": "pass" | ||
| } | ||
| ] | ||
| }, | ||
| "evaluation_mode": "deterministic", | ||
| "external_apis": "none", | ||
| "generated_by": "McpContextBundleRefExampleGenerator", | ||
| "llm_judges": "none", | ||
| "schema_version": "mcp_context_bundle_ref_example.v1", | ||
| "version": "1.0" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| #!/usr/bin/env python3 | ||
| """Generate a deterministic bundle example that references MCP context output.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| REPO_ROOT = Path(__file__).resolve().parents[1] | ||
| if str(REPO_ROOT) not in sys.path: | ||
| sys.path.insert(0, str(REPO_ROOT)) | ||
|
|
||
| from scripts.agent_artifact_bundle import build_agent_artifact_bundle | ||
| from scripts.safe_pr_gate import GateState | ||
|
|
||
| ARTIFACT_ID = "mcp_context_bundle_ref_example_v1" | ||
| MCP_CONTEXT_OUTPUT_REF = "artifacts/mcp_context_layer_example.json" | ||
| OUTPUT_PATH = REPO_ROOT / "artifacts" / "mcp_context_bundle_ref_example.json" | ||
|
|
||
| EXAMPLE_STATE = GateState( | ||
| branch="feat/mcp-context-bundle-ref-example", | ||
| status_short=(), | ||
| changed_paths=( | ||
| "artifacts/mcp_context_bundle_ref_example.json", | ||
| "scripts/generate_mcp_context_bundle_ref_example.py", | ||
| "tests/test_agent_artifact_bundle.py", | ||
| ), | ||
| ) | ||
| VALIDATION_COMMANDS = [ | ||
| "python -m compileall -q scripts/agent_artifact_bundle.py scripts/generate_mcp_context_bundle_ref_example.py", | ||
| "pytest tests/test_agent_artifact_bundle.py -q", | ||
| "python scripts/validate_agent_artifact_bundle.py --bundle artifacts/mcp_context_bundle_ref_example.json", | ||
| ] | ||
| VALIDATION_RESULTS = ["pass", "pass", "pass"] | ||
|
|
||
|
|
||
| def build_mcp_context_bundle_ref_example() -> dict[str, Any]: | ||
| return { | ||
| "artifact_id": ARTIFACT_ID, | ||
| "bundle": build_agent_artifact_bundle( | ||
| EXAMPLE_STATE, | ||
| allow_main=False, | ||
| validation_commands=VALIDATION_COMMANDS, | ||
| validation_results=VALIDATION_RESULTS, | ||
| mcp_context_output_ref=MCP_CONTEXT_OUTPUT_REF, | ||
| ), | ||
| "evaluation_mode": "deterministic", | ||
| "external_apis": "none", | ||
| "generated_by": "McpContextBundleRefExampleGenerator", | ||
| "llm_judges": "none", | ||
| "schema_version": "mcp_context_bundle_ref_example.v1", | ||
| "version": "1.0", | ||
| } | ||
|
|
||
|
|
||
| def generate_mcp_context_bundle_ref_example(output_path: Path = OUTPUT_PATH) -> Path: | ||
| artifact = build_mcp_context_bundle_ref_example() | ||
| output_path.parent.mkdir(parents=True, exist_ok=True) | ||
| output_path.write_text(json.dumps(artifact, indent=2, sort_keys=True) + "\n", encoding="utf-8") | ||
| return output_path | ||
|
|
||
|
|
||
| def main() -> int: | ||
| output_path = generate_mcp_context_bundle_ref_example() | ||
| print(output_path.relative_to(REPO_ROOT).as_posix()) | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| raise SystemExit(main()) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,9 +10,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ARTIFACT_ID, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_agent_artifact_bundle_example, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from scripts.generate_mcp_context_bundle_ref_example import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ARTIFACT_ID as MCP_REF_ARTIFACT_ID, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MCP_CONTEXT_OUTPUT_REF, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_mcp_context_bundle_ref_example, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from scripts.safe_pr_gate import GateState, evaluate_gate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ARTIFACT_PATH = Path("artifacts/agent_artifact_bundle_example.json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MCP_REF_ARTIFACT_PATH = Path("artifacts/mcp_context_bundle_ref_example.json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_build_agent_artifact_bundle_is_deterministic_and_includes_optional_metadata() -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -208,3 +214,42 @@ def test_agent_artifact_bundle_example_has_stable_schema_and_content() -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["mcp_context_output_ref"] == "artifacts/mcp_context_layer_example.json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["safe_pr_gate"]["ok"] is True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["safe_pr_gate"]["result"] == "PASS" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_mcp_context_bundle_ref_example_matches_generator_output(tmp_path: Path) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output_path = tmp_path / "mcp_context_bundle_ref_example.json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_mcp_context_bundle_ref_example(output_path) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert output_path.read_text(encoding="utf-8") == MCP_REF_ARTIFACT_PATH.read_text(encoding="utf-8") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_mcp_context_bundle_ref_example_references_mcp_output_without_dumping_payload() -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifact = json.loads(MCP_REF_ARTIFACT_PATH.read_text(encoding="utf-8")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert set(artifact) == { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "artifact_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bundle", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "evaluation_mode", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "external_apis", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "generated_by", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "llm_judges", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "schema_version", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "version", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert artifact["artifact_id"] == MCP_REF_ARTIFACT_ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert artifact["schema_version"] == "mcp_context_bundle_ref_example.v1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert artifact["evaluation_mode"] == "deterministic" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert artifact["external_apis"] == "none" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert artifact["llm_judges"] == "none" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bundle = artifact["bundle"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["branch"] == "feat/mcp-context-bundle-ref-example" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["mcp_context_output_ref"] == MCP_CONTEXT_OUTPUT_REF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["ok"] is True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["result"] == "PASS" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert bundle["safe_pr_gate"]["ok"] is True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifact_text = MCP_REF_ARTIFACT_PATH.read_text(encoding="utf-8") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert "prompt_context" not in artifact_text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert "replay_payload" not in artifact_text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert "dependency_chains" not in artifact_text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+245
to
+255
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current test uses brittle string-based checks to verify that certain fields are not present in the artifact. A more robust approach is to validate the set of keys in the
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When loading JSON files, the repository guidelines require handling
FileNotFoundErrorandJSONDecodeErrorby raising aRuntimeErrorthat includes the repo-relative path. Additionally, the decoded payload should be validated as the expected type (e.g., a dictionary) usingRuntimeErrorinstead of assertions.References