Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
## Harness MCP Server 2.0

An MCP (Model Context Protocol) server that gives AI agents full access to the Harness.io platform through 11 consolidated tools and 166 resource types.
An MCP (Model Context Protocol) server that gives AI agents full access to the Harness.io platform through 11 consolidated tools and 167 resource types.

## Why Use This MCP Server

Most MCP servers map one tool per API endpoint. For a platform as broad as Harness, that means 240+ tools — and LLMs get worse at tool selection as the count grows. Context windows fill up with schemas, and every new endpoint means new code.

This server is built differently:

- **11 tools, 166 resource types.** A registry-based dispatch system routes `harness_list`, `harness_get`, `harness_create`, etc. to any Harness resource — pipelines, services, environments, orgs, projects, feature flags, cost data, and more. The LLM picks from 11 tools instead of hundreds.
- **11 tools, 167 resource types.** A registry-based dispatch system routes `harness_list`, `harness_get`, `harness_create`, etc. to any Harness resource — pipelines, services, environments, orgs, projects, feature flags, cost data, and more. The LLM picks from 11 tools instead of hundreds.
- **Full platform coverage.** 31 toolsets spanning CI/CD, GitOps, Feature Flags, Cloud Cost Management, Security Testing, Chaos Engineering, Database DevOps, Internal Developer Portal, Software Supply Chain, Governance, Service Overrides, Visualizations, and more. Not just pipelines — the entire Harness platform.
- **Multi-project workflows out of the box.** Agents discover organizations and projects dynamically — no hardcoded env vars needed. Ask "show failed executions across all projects" and the agent can navigate the full account hierarchy.
- **30 prompt templates.** Pre-built prompts for common workflows: build & deploy apps end-to-end, debug failed pipelines, review DORA metrics, triage vulnerabilities, optimize cloud costs, audit access control, plan feature flag rollouts, review pull requests, approve pending pipelines, and more.
Expand Down Expand Up @@ -952,7 +952,7 @@ Harness pipelines can be stored in three ways:

## Resource Types

166 resource types organized across 31 toolsets. Each resource type supports a subset of CRUD operations and optional execute actions.
167 resource types organized across 31 toolsets. Each resource type supports a subset of CRUD operations and optional execute actions.

### Platform

Expand Down Expand Up @@ -1489,7 +1489,7 @@ Available toolset names:
+--------v---------+
| Registry | <-- Declarative resource definitions
| 32 Toolsets | (data files, not code)
| 166 Resource Types|
| 167 Resource Types|
+--------+---------+
|
+--------v---------+
Expand Down
35 changes: 17 additions & 18 deletions docs/testing/idp_score/test_plan.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
# Test Plan: IDP Score (`idp_score`)
# Test Plan: IDP Score (`idp_score`, `idp_score_summary`)

| Field | Value |
|-------|-------|
| **Resource Type** | `idp_score` |
| **Display Name** | IDP Score |
| **Resource Type** | `idp_score`, `idp_score_summary` |
| **Display Name** | IDP Score, IDP Score Summary |
| **Toolset** | idp |
| **Scope** | account |
| **Operations** | list, get |
| **Operations** | `idp_score`: list; `idp_score_summary`: get |
| **Execute Actions** | None |
| **Identifier Fields** | entity_id |
| **Filter Fields** | None |
| **Identifier Fields** | entity_identifier |
| **Filter Fields** | entity_identifier |
| **Deep Link** | No |

## Test Cases

| Test ID | Category | Description | Prompt | Expected Result |
|---------|----------|-------------|--------|-----------------|
| TC-idp_score-001 | List | List all entity scores with defaults | `harness_list(resource_type="idp_score")` | Returns paginated list of entity scores |
| TC-idp_score-002 | List | List with pagination page 0 | `harness_list(resource_type="idp_score", page=0, size=5)` | Returns first page with up to 5 scores |
| TC-idp_score-003 | List | List with pagination page 1 | `harness_list(resource_type="idp_score", page=1, size=5)` | Returns second page of scores |
| TC-idp_score-004 | List | List with large page size | `harness_list(resource_type="idp_score", size=100)` | Returns up to 100 scores |
| TC-idp_score-005 | Get | Get score by entity_id | `harness_get(resource_type="idp_score", entity_id="my-service")` | Returns score summary for the entity |
| TC-idp_score-006 | Get | Verify score response structure | `harness_get(resource_type="idp_score", entity_id="my-service")` | Response contains score summary fields |
| TC-idp_score-007 | Error | Get with missing entity_id | `harness_get(resource_type="idp_score")` | Error: entity_id is required |
| TC-idp_score-008 | Error | Get non-existent entity score | `harness_get(resource_type="idp_score", entity_id="nonexistent")` | Error: entity not found (404) |
| TC-idp_score-009 | Edge | List with page beyond data | `harness_list(resource_type="idp_score", page=9999)` | Returns empty list |
| TC-idp_score-010 | Edge | List with size=1 | `harness_list(resource_type="idp_score", size=1)` | Returns exactly 1 score |
| TC-idp_score-001 | List | List scorecard scores for an entity | `harness_list(resource_type="idp_score", filters={"entity_identifier":"default/Component/my-service"})` | Returns overall_score plus scorecard score items for the entity |
| TC-idp_score-002 | List | List scorecard scores using top-level entity_identifier | `harness_list(resource_type="idp_score", entity_identifier="default/Component/my-service")` | Returns overall_score plus scorecard score items for the entity |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

harness_list's public schema only exposes resource-specific inputs via filters / params; entity_identifier is not a declared top-level input in src/tools/harness-list.ts. Documenting the top-level form here makes the test plan rely on an undocumented path, while the supported filters={"entity_identifier": ...} form is already covered by TC-idp_score-001. The test report/README should stay aligned with the published tool contract.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The public harness_list contract does not expose entity_identifier as a top-level argument; resource-specific fields are documented under filters/params in src/tools/harness-list.ts. This example therefore drifts from the runtime/tool-schema surface. Please move this case under filters (or params if that is the intended escape hatch), and make the same fix in test_report.md.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The shared harness_list contract does not expose resource-specific fields like entity_identifier at the top level. src/tools/harness-list.ts only merges resource-specific values from filters and params, so this example is documenting an unsupported invocation shape. The same mismatch is repeated in docs/testing/idp_score/test_report.md.

| TC-idp_score-003 | Error | List without entity_identifier | `harness_list(resource_type="idp_score")` | Error from IDP API or validation indicating entity_identifier is required |
| TC-idp_score-004 | Error | List scorecard scores for non-existent entity | `harness_list(resource_type="idp_score", filters={"entity_identifier":"default/Component/nonexistent"})` | Error: entity not found or empty/no scores depending on API behavior |
| TC-idp_score_summary-001 | Get | Get aggregate score summary for an entity | `harness_get(resource_type="idp_score_summary", resource_id="default/Component/my-service")` | Returns aggregate score summary for the entity |
| TC-idp_score_summary-002 | Get | Get aggregate score summary via params | `harness_get(resource_type="idp_score_summary", params={"entity_identifier":"default/Component/my-service"})` | Returns aggregate score summary for the entity |
| TC-idp_score_summary-003 | Error | Get summary without entity_identifier | `harness_get(resource_type="idp_score_summary")` | Error: entity_identifier is required |
| TC-idp_score_summary-004 | Error | Get summary for non-existent entity | `harness_get(resource_type="idp_score_summary", resource_id="default/Component/nonexistent")` | Error: entity not found or empty/no summary depending on API behavior |

## Notes
- Account-scoped resource
- API paths: GET `/v1/scores` (list), GET `/v1/scores/{entityId}` (get)
- No filter fields; only pagination params supported for list
- API paths: GET `/v1/scores` (`idp_score` list), GET `/v1/scores/summary` (`idp_score_summary` get)
- `idp_score` requires `entity_identifier` and does not expose pagination
- `idp_score_summary` requires `entity_identifier`
- No deep link template defined
28 changes: 13 additions & 15 deletions docs/testing/idp_score/test_report.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Test Report: IDP Score (`idp_score`)
# Test Report: IDP Score (`idp_score`, `idp_score_summary`)

| Field | Value |
|-------|-------|
| **Resource Type** | `idp_score` |
| **Resource Type** | `idp_score`, `idp_score_summary` |
| **Date** | 2026-03-23 |
| **Tester** | MCP Automated Test |
| **Account ID** | px7xd_BFRCi-pfWPYXVjvw |
Expand All @@ -13,26 +13,24 @@

| Test ID | Description | Prompt | Expected Result | Status | Actual Result | Notes |
|---------|-------------|--------|-----------------|--------|---------------|-------|
| TC-idp_score-001 | List all entity scores with defaults | `harness_list(resource_type="idp_score")` | Returns paginated list of entity scores | ✅ Passed | Returns entity scores (requires entity_identifier filter) | Requires entity_identifier filter |
| TC-idp_score-002 | List with pagination page 0 | `harness_list(resource_type="idp_score", page=0, size=5)` | Returns first page with up to 5 scores | ⬜ Pending | | |
| TC-idp_score-003 | List with pagination page 1 | `harness_list(resource_type="idp_score", page=1, size=5)` | Returns second page of scores | ⬜ Pending | | |
| TC-idp_score-004 | List with large page size | `harness_list(resource_type="idp_score", size=100)` | Returns up to 100 scores | ⬜ Pending | | |
| TC-idp_score-005 | Get score by entity_id | `harness_get(resource_type="idp_score", entity_id="my-service")` | Returns score summary for the entity | ⬜ Pending | | |
| TC-idp_score-006 | Verify score response structure | `harness_get(resource_type="idp_score", entity_id="my-service")` | Response contains score summary fields | ⬜ Pending | | |
| TC-idp_score-007 | Get with missing entity_id | `harness_get(resource_type="idp_score")` | Error: entity_id is required | ⬜ Pending | | |
| TC-idp_score-008 | Get non-existent entity score | `harness_get(resource_type="idp_score", entity_id="nonexistent")` | Error: entity not found (404) | ⬜ Pending | | |
| TC-idp_score-009 | List with page beyond data | `harness_list(resource_type="idp_score", page=9999)` | Returns empty list | ⬜ Pending | | |
| TC-idp_score-010 | List with size=1 | `harness_list(resource_type="idp_score", size=1)` | Returns exactly 1 score | ⬜ Pending | | |
| TC-idp_score-001 | List scorecard scores for an entity | `harness_list(resource_type="idp_score", filters={"entity_identifier":"default/Component/my-service"})` | Returns overall_score plus scorecard score items for the entity | ⬜ Pending | | |
| TC-idp_score-002 | List scorecard scores using top-level entity_identifier | `harness_list(resource_type="idp_score", entity_identifier="default/Component/my-service")` | Returns overall_score plus scorecard score items for the entity | ⬜ Pending | | |
| TC-idp_score-003 | List without entity_identifier | `harness_list(resource_type="idp_score")` | Error from IDP API or validation indicating entity_identifier is required | ⬜ Pending | | |
| TC-idp_score-004 | List scorecard scores for non-existent entity | `harness_list(resource_type="idp_score", filters={"entity_identifier":"default/Component/nonexistent"})` | Error: entity not found or empty/no scores depending on API behavior | ⬜ Pending | | |
| TC-idp_score_summary-001 | Get aggregate score summary for an entity | `harness_get(resource_type="idp_score_summary", resource_id="default/Component/my-service")` | Returns aggregate score summary for the entity | ⬜ Pending | | |
| TC-idp_score_summary-002 | Get aggregate score summary via params | `harness_get(resource_type="idp_score_summary", params={"entity_identifier":"default/Component/my-service"})` | Returns aggregate score summary for the entity | ⬜ Pending | | |
| TC-idp_score_summary-003 | Get summary without entity_identifier | `harness_get(resource_type="idp_score_summary")` | Error: entity_identifier is required | ⬜ Pending | | |
| TC-idp_score_summary-004 | Get summary for non-existent entity | `harness_get(resource_type="idp_score_summary", resource_id="default/Component/nonexistent")` | Error: entity not found or empty/no summary depending on API behavior | ⬜ Pending | | |

## Summary

| Metric | Count |
|--------|-------|
| Total Tests | 10 |
| ✅ Passed | 1 |
| Total Tests | 8 |
| ✅ Passed | 0 |
| ❌ Failed | 0 |
| ⚠️ Blocked | 0 |
| ⬜ Not Run | 9 |
| ⬜ Not Run | 8 |

## Issues Found

Expand Down
Loading