harness-mcp
SKILL.md
Harness MCP Skill
AI-powered CD operations, Git repository and pull request management via Harness MCP Server.
Prerequisites
Environment Variables
export HARNESS_API_KEY="your-api-key"
export HARNESS_DEFAULT_ORG_ID="your-org-id"
export HARNESS_DEFAULT_PROJECT_ID="your-project-id"
export HARNESS_BASE_URL="https://app.harness.io"
export HARNESS_ACCOUNT_ID="your-account-id"
API Token Generation
- Navigate to Account Settings > API Keys in Harness UI
- Click + API Key
- Set permissions (minimum: pipeline execution, connector management)
- Store securely
MCP Server Configuration
Claude Code
{
"mcpServers": {
"harness": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-harness"],
"env": {
"HARNESS_API_KEY": "${HARNESS_API_KEY}",
"HARNESS_DEFAULT_ORG_ID": "${HARNESS_DEFAULT_ORG_ID}",
"HARNESS_DEFAULT_PROJECT_ID": "${HARNESS_DEFAULT_PROJECT_ID}",
"HARNESS_BASE_URL": "${HARNESS_BASE_URL}"
}
}
}
}
Docker
docker run -e HARNESS_API_KEY=$HARNESS_API_KEY \
-e HARNESS_DEFAULT_ORG_ID=$HARNESS_DEFAULT_ORG_ID \
-e HARNESS_DEFAULT_PROJECT_ID=$HARNESS_DEFAULT_PROJECT_ID \
harness/mcp-server:latest
Available MCP Tools
| Category | Tool | Purpose |
|---|---|---|
| Connectors | harness_get_connector, harness_list_connectors, harness_get_connector_catalogue |
Manage connectors |
| Pipelines | harness_list_pipelines, harness_get_pipeline, harness_trigger_pipeline |
Pipeline operations |
| Executions | harness_get_execution, harness_list_executions, harness_get_execution_url |
Track executions |
| Dashboards | harness_list_dashboards, harness_get_dashboard |
Dashboard data |
| Repos | harness_get_repository, harness_list_repositories |
Repository management |
| Pull Requests | harness_get_pull_request, harness_list_pull_requests, harness_create_pull_request, harness_get_pull_request_checks, harness_get_pull_request_activities |
PR operations |
Git & Pull Request Workflows
List Repositories
repos = harness_list_repositories(
org_id="${HARNESS_ORG_ID}",
project_id="${HARNESS_PROJECT_ID}"
)
Create Pull Request
pr = harness_create_pull_request(
repo_id="my-application",
title="PROJ-123: Feature title",
source_branch="feature/PROJ-123",
target_branch="main",
description="## Summary\nImplements feature.\n## Jira\n[PROJ-123](https://company.atlassian.net/browse/PROJ-123)"
)
Get PR Activities (Comments, Reviews)
activities = harness_get_pull_request_activities(repo_id="my-app", pr_number=42)
for activity in activities:
if activity.type == "comment":
print(f"Comment by {activity.author} at {activity.file_path}:{activity.line_number}")
elif activity.type == "review":
print(f"Review by {activity.author}: {activity.state}")
Sync PR Comments to Jira
activities = harness_get_pull_request_activities(repo_id="my-app", pr_number=42)
review_summary = []
for activity in activities:
if activity.type == "review":
review_summary.append(f"- **{activity.author}**: {activity.state}")
jira_add_comment(issue_key="PROJ-123",
body=f"## PR Review\n**PR:** [#{42}]({pr.url})\n**Status:** {pr.state}\n\n" + "\n".join(review_summary))
PR-to-Jira Status Mapping
pr_sync:
enabled: true
jira_key_patterns:
- title: "^([A-Z]+-\\d+)"
- branch: "feature/([A-Z]+-\\d+)"
transitions:
pr_created: { transition: "In Review", comment: "PR created: {pr_url}" }
pr_approved: { transition: "Approved", comment: "PR approved by {approver}" }
pr_merged: { transition: "Done", comment: "PR merged to {target_branch}" }
fields:
pr_url: "customfield_10200"
pr_status: "customfield_10201"
reviewers: "customfield_10202"
Jira Connector Setup
Create Connector
connector:
name: jira-connector
identifier: jira_connector
type: Jira
spec:
jiraUrl: https://your-company.atlassian.net
auth:
type: UsernamePassword
spec:
username: your.email@company.com
passwordRef: jira_api_token
delegateSelectors:
- delegate-name
Required Scopes: read:jira-user, read:jira-work, write:jira-work
Jira Create Step in Pipeline
- step:
name: Create Jira Issue
type: JiraCreate
spec:
connectorRef: jira_connector
projectKey: PROJ
issueType: Task
fields:
- name: Summary
value: "Deployment: <+pipeline.name> - <+pipeline.sequenceId>"
- name: Priority
value: Medium
Jira Update Step
- step:
name: Update Jira Issue
type: JiraUpdate
spec:
connectorRef: jira_connector
issueKey: <+pipeline.variables.jiraIssueKey>
fields:
- name: Status
value: Done
transitionTo:
transitionName: Done
status: Done
Jira Approval Step
- step:
name: Jira Approval
type: JiraApproval
spec:
connectorRef: jira_connector
issueKey: <+pipeline.variables.jiraIssueKey>
approvalCriteria:
matchAnyCondition: true
conditions:
- key: Status
operator: equals
value: Approved
Integration with Jira Orchestrator
Configuration
harness:
account:
account_id: "${HARNESS_ACCOUNT_ID}"
org_id: "${HARNESS_ORG_ID}"
project_id: "${HARNESS_PROJECT_ID}"
api:
base_url: "https://app.harness.io"
api_key: "${HARNESS_API_KEY}"
mcp:
enabled: true
tools:
- harness_get_connector
- harness_list_pipelines
- harness_get_execution
jira_connector_ref: "jira_connector"
sync:
auto_create_issues: true
auto_transition: true
environments:
dev: "In Development"
staging: "In QA"
prod: "Released"
MCP Tool Usage
connector = harness_get_connector(connector_id="jira_connector", org_id="default", project_id="my_project")
executions = harness_list_executions(pipeline_id="deploy_pipeline", limit=10)
execution = harness_get_execution(execution_id="abc123", org_id="default", project_id="my_project")
REST API for PR Operations
Base URL
HARNESS_CODE_API="${HARNESS_BASE_URL}/code/api/v1"
Authentication
curl -H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
"${HARNESS_CODE_API}/repos/{repo-ref}/pullreq/{pr-number}/comments"
Key Endpoints
| Operation | Method | Endpoint |
|---|---|---|
| Create Comment | POST | /v1/repos/{repo}/pullreq/{pr}/comments |
| Create Code Comment | POST | /v1/repos/{repo}/pullreq/{pr}/comments (with path, line_start, line_end) |
| Submit Review | POST | /v1/repos/{repo}/pullreq/{pr}/reviews |
| Add Reviewer | POST | /v1/repos/{repo}/pullreq/{pr}/reviewers |
| Merge PR | POST | /v1/repos/{repo}/pullreq/{pr}/merge |
Create General Comment
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/comments" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"text": "Great work!"}'
Create Code Comment
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/comments" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"text": "Consider adding null check",
"path": "src/auth.ts",
"line_start": 42,
"line_end": 45,
"line_start_new": true,
"line_end_new": true
}'
Submit Review
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/reviews" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"commit_sha": "abc123", "decision": "approved"}'
Decision Values: approved, changereq, reviewed
Merge PR
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/merge" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"method": "squash",
"source_sha": "abc123",
"title": "feat: Add auth",
"delete_source_branch": true
}'
Merge Methods: merge, squash, rebase, fast-forward
Bash Helper Functions
export HARNESS_CODE_API="${HARNESS_BASE_URL:-https://app.harness.io}/code/api/v1"
harness_pr_comment() {
local repo="$1" pr="$2" text="$3"
curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/comments" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"text\": \"${text}\"}"
}
harness_pr_approve() {
local repo="$1" pr="$2" commit_sha="$3"
curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/reviews" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"commit_sha\": \"${commit_sha}\", \"decision\": \"approved\"}"
}
harness_pr_merge() {
local repo="$1" pr="$2" method="${3:-squash}" source_sha="$4" title="$5"
curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/merge" \
-H "x-api-key: ${HARNESS_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"method\": \"${method}\", \"source_sha\": \"${source_sha}\", \"title\": \"${title}\", \"delete_source_branch\": true}"
}
Python Client
import requests, os
from typing import Optional, Literal
class HarnessCodeAPI:
def __init__(self, api_key: str = None, base_url: str = None):
self.api_key = api_key or os.environ.get("HARNESS_API_KEY")
self.base_url = base_url or os.environ.get("HARNESS_BASE_URL", "https://app.harness.io")
self.api_url = f"{self.base_url}/code/api/v1"
self.headers = {"x-api-key": self.api_key, "Content-Type": "application/json"}
def create_comment(self, repo: str, pr_number: int, text: str, path: Optional[str] = None,
line_start: Optional[int] = None, line_end: Optional[int] = None,
parent_id: Optional[int] = None) -> dict:
url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/comments"
data = {"text": text}
if parent_id:
data["parent_id"] = parent_id
elif path and line_start:
data.update({"path": path, "line_start": line_start, "line_end": line_end or line_start,
"line_start_new": True, "line_end_new": True})
return requests.post(url, headers=self.headers, json=data).json()
def submit_review(self, repo: str, pr_number: int, commit_sha: str,
decision: Literal["approved", "changereq", "reviewed"]) -> dict:
url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/reviews"
data = {"commit_sha": commit_sha, "decision": decision}
return requests.post(url, headers=self.headers, json=data).json()
def approve(self, repo: str, pr_number: int, commit_sha: str) -> dict:
return self.submit_review(repo, pr_number, commit_sha, "approved")
def merge(self, repo: str, pr_number: int, source_sha: str,
method: Literal["merge", "squash", "rebase", "fast-forward"] = "squash",
title: Optional[str] = None, delete_source_branch: bool = True,
dry_run: bool = False) -> dict:
url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/merge"
data = {"method": method, "source_sha": source_sha, "delete_source_branch": delete_source_branch, "dry_run": dry_run}
if title:
data["title"] = title
return requests.post(url, headers=self.headers, json=data).json()
Multi-Repository Workspace Support
Configuration
harness:
workspace:
repositories:
- identifier: frontend-app
path: ./frontend
jira_project: FRONT
- identifier: backend-api
path: ./backend
jira_project: BACK
auto_create_repos: true
default_branch: main
review:
cross_repo_review: true
jira:
sync_enabled: true
aggregate_prs: true
Python API
from lib.harness_code_api import HarnessCodeAPI
client = HarnessCodeAPI()
repos = client.setup_workspace_repos([
{"identifier": "frontend", "path": "./frontend"},
{"identifier": "backend", "path": "./backend"}
])
prs = client.get_workspace_prs(repo_identifiers=["frontend", "backend"], state="open", jira_key="PROJ-123")
Repository Creation
Python
repo = client.create_repository(
identifier="my-service",
description="User management service",
default_branch="main",
is_public=False,
readme=True,
license="MIT"
)
REST API
| Operation | Method | Endpoint |
|---|---|---|
| List Repos | GET | /v1/repos |
| Get Repo | GET | /v1/repos/{repo} |
| Create Repo | POST | /v1/repos |
| Update Repo | PATCH | /v1/repos/{repo} |
| Delete Repo | DELETE | /v1/repos/{repo} |
Confluence Documentation Integration
Auto-Documentation
from lib.confluence_doc_linker import ConfluenceDocLinker
linker = ConfluenceDocLinker()
docs = linker.ensure_issue_docs("PROJ-123")
linker.link_readme_to_confluence(readme_path="./README.md", jira_key="PROJ-123")
Configuration
documentation:
confluence:
base_url: "${CONFLUENCE_BASE_URL}"
space_key: "ENG"
auto_create:
enabled: true
on_work_start: true
readme:
auto_update: true
Troubleshooting
| Issue | Solution |
|---|---|
| Invalid API Key | Regenerate in Harness UI |
| Network timeout | Check delegate connectivity |
| Permission denied | Verify API key permissions |
| Jira unreachable | Check firewall/proxy |
Debug Logging
export HARNESS_LOG_LEVEL=debug
export MCP_DEBUG=true
Best Practices
- Use Harness Secrets for credentials
- Select delegates with direct Jira network access
- Configure error handling with retries
- Enable logging for all operations
- Scope API tokens to minimum permissions
Related Resources
Weekly Installs
5
Repository
lobbi-docs/claudeGitHub Stars
9
First Seen
Feb 27, 2026
Security Audits
Installed on
opencode5
gemini-cli5
codebuddy5
github-copilot5
codex5
kimi-cli5