harness-mcp
Harness MCP (Model Context Protocol) server integration for AI-powered CD operations, pipeline management, Git repositories, pull requests, code review comments, and bidirectional Jira synchronization
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
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
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-31
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!