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
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

[![MCP Toplist](https://mcptoplist.com/badge/glama%2Fharness%2Fmcp-server.svg)](https://mcptoplist.com/server/glama%2Fharness%2Fmcp-server)

An MCP (Model Context Protocol) server that gives AI agents full access to the Harness.io platform through 11 consolidated tools and 228 resource types.
An MCP (Model Context Protocol) server that gives AI agents full access to the Harness.io platform through 11 consolidated tools and 239 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, 228 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.** 38 default toolsets spanning CI/CD, GitOps, Feature Flags, Cloud Cost Management, Security Testing, Chaos Engineering, Database DevOps, Internal Developer Portal, Software Supply Chain, Infrastructure as Code Management, Governance, Service Overrides, Knowledge Graph, and more. Opt-in Ansible coverage is available when you need inventory and playbook data.
- **11 tools, 239 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.** 39 default toolsets spanning CI/CD, GitOps, Feature Flags, Cloud Cost Management, Security Testing, Chaos Engineering, Database DevOps, Internal Developer Portal, Software Supply Chain, Infrastructure as Code Management, Release Management, Governance, Service Overrides, Knowledge Graph, and more. Opt-in Ansible coverage is available when you need inventory and playbook data.
- **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.
- **34 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.
- **Works everywhere.** Stdio transport for local clients (Claude Desktop, Cursor, Devin Desktop), HTTP transport for remote/shared deployments, Docker and Kubernetes ready.
Expand Down Expand Up @@ -1202,7 +1202,7 @@ Harness pipelines can be stored in three ways:

## Resource Types

228 resource types organized across 38 toolsets. Each resource type supports a subset of CRUD operations and optional execute actions.
239 resource types organized across 39 toolsets. Each resource type supports a subset of CRUD operations and optional execute actions.

### Platform

Expand Down Expand Up @@ -1791,7 +1791,7 @@ Security exemption execute workflow:

## Toolset Filtering

By default, 38 of 39 toolsets are enabled. One toolset is opt-in and excluded from the defaults:
By default, 39 of 40 toolsets are enabled. One toolset is opt-in and excluded from the defaults:

- **`ansible`** — Harness Ansible (inventories, playbooks, hosts, activity). Opt-in because it is project-scoped and adds concepts many users do not need.

Expand Down Expand Up @@ -1871,6 +1871,7 @@ Available toolset names:
| `ai-evals` | eval_dataset, eval_dataset_item, evaluation, eval_run, eval_run_item, eval_run_by_eval, eval_metric, eval_metric_set, eval_metric_set_entry, eval_suite, eval_suite_evaluation, eval_suite_run, eval_target, eval_annotation, eval_analytics, eval_git_settings, eval_registry_item, eval_git_registration, online_eval |
| `iacm` | iacm_workspace, iacm_variable_set, iacm_resource, iacm_module, iacm_workspace_costs, iacm_activity_resource_change |
| `ansible` *(opt-in)* | ansible_inventory, ansible_playbook, ansible_host, ansible_host_activity, ansible_activity |
| `release-management` | release_process, release_activity, release, release_execution_phase, release_execution_task, release_execution_activity, release_input, release_execution_phase_input, release_execution_phase_output, release_execution_activity_input, release_execution_activity_output |


## Architecture
Expand All @@ -1888,8 +1889,8 @@ Available toolset names:
|
+--------v---------+
| Registry | <-- Declarative resource definitions
| 38 Toolsets | (data files, not code)
| 228 Resource Types|
| 39 Toolsets | (data files, not code)
| 239 Resource Types|
+--------+---------+
|
+--------v---------+
Expand Down
18 changes: 18 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,24 @@ export function resolveProductBaseUrl(config: Config, product: "harness" | "fme"
return undefined;
}

/** Resolve Release Management (RMG) API root: `${HARNESS_BASE_URL}/gateway/rmg`. */
export function resolveRmgBaseUrl(config: Config): string {
return `${config.HARNESS_BASE_URL.replace(/\/$/, "")}/gateway/rmg`;
}

/**
* Resolve per-resource base URL overrides (FME, RMG). Returns undefined to use
* the default Harness client base URL.
*/
export function resolveResourceBaseUrl(
config: Config,
def: { product?: "harness" | "fme"; baseUrlOverride?: "fme" | "rmg" },
): string | undefined {
if (def.baseUrlOverride === "rmg") return resolveRmgBaseUrl(config);
if (def.baseUrlOverride === "fme" || def.product === "fme") return config.HARNESS_FME_BASE_URL;
return resolveProductBaseUrl(config, def.product ?? "harness");
}

export function loadConfig(): Config {
const result = ConfigSchema.safeParse(process.env);
if (!result.success) {
Expand Down
12 changes: 12 additions & 0 deletions src/registry/extractors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ export const pageExtract = (raw: unknown): { items: unknown[]; total: number } =
};
};

/**
* Spring Data page at the response root (no NG `{ data }` envelope):
* `{ content, totalElements }`. Used by Release Management (RMG) list APIs.
*/
export const springPageExtract = (raw: unknown): { items: unknown[]; total: number } => {
const r = raw as { content?: unknown[]; totalElements?: number };
return {
items: Array.isArray(r.content) ? r.content : [],
total: typeof r.totalElements === "number" ? r.totalElements : 0,
};
};

/** Extract `data` from NG API and wrap primitive values in an object for structuredContent compatibility. */
export const countExtract = (raw: unknown): { count: number; _error?: string } => {
const r = raw as { data?: unknown };
Expand Down
8 changes: 6 additions & 2 deletions src/registry/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import { type Config, resolveProductBaseUrl } from "../config.js";
import { type Config, resolveProductBaseUrl, resolveResourceBaseUrl } from "../config.js";
import type { HarnessClient } from "../client/harness-client.js";
import { HarnessApiError } from "../utils/errors.js";
import type { ResourceDefinition, ToolsetDefinition, ToolsetName, OperationName, EndpointSpec, FilterFieldSpec, ResourceScope } from "./types.js";
Expand Down Expand Up @@ -52,6 +52,7 @@ import { semanticLayerToolset } from "./toolsets/semantic-layer.js";
import { ansibleToolset } from "./toolsets/ansible.js";
import { incidentsToolset } from "./toolsets/incidents.js";
import { deploysToolset } from "./toolsets/deploys.js";
import { releaseManagementToolset } from "./toolsets/release-management.js";

const log = createLogger("registry");

Expand Down Expand Up @@ -167,6 +168,7 @@ const ALL_TOOLSETS: ToolsetDefinition[] = [
ansibleToolset,
incidentsToolset,
deploysToolset,
releaseManagementToolset,
];

/** All available toolset names — used by docs generation to discover opt-in toolsets. */
Expand Down Expand Up @@ -818,7 +820,9 @@ export class Registry {

// Make request — resolve base URL and auth from product backend
const product = resolvedRoute?.product ?? def.product ?? "harness";
const baseUrl = resolveProductBaseUrl(this.config, product);
const baseUrl = def.baseUrlOverride
? resolveResourceBaseUrl(this.config, def)
: resolveProductBaseUrl(this.config, product);
const productHeaders: Record<string, string> = { ...spec.headers, ...resolvedRoute?.headers };

const requestOpts = {
Expand Down
Loading
Loading