@octopusdeploy/mcp-server 1.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +237 -46
- package/dist/helpers/activeToolsetConfig.d.ts +4 -0
- package/dist/helpers/activeToolsetConfig.d.ts.map +1 -0
- package/dist/helpers/activeToolsetConfig.js +18 -0
- package/dist/helpers/activeToolsetConfig.js.map +1 -0
- package/dist/helpers/errorHandling.d.ts +38 -0
- package/dist/helpers/errorHandling.d.ts.map +1 -0
- package/dist/helpers/errorHandling.js +75 -0
- package/dist/helpers/errorHandling.js.map +1 -0
- package/dist/helpers/getClientConfigurationFromEnvironment.d.ts +2 -0
- package/dist/helpers/getClientConfigurationFromEnvironment.d.ts.map +1 -1
- package/dist/helpers/getClientConfigurationFromEnvironment.js +21 -5
- package/dist/helpers/getClientConfigurationFromEnvironment.js.map +1 -1
- package/dist/helpers/grepLines.d.ts +38 -0
- package/dist/helpers/grepLines.d.ts.map +1 -0
- package/dist/helpers/grepLines.js +65 -0
- package/dist/helpers/grepLines.js.map +1 -0
- package/dist/helpers/methodTier.d.ts +15 -0
- package/dist/helpers/methodTier.d.ts.map +1 -0
- package/dist/helpers/methodTier.js +25 -0
- package/dist/helpers/methodTier.js.map +1 -0
- package/dist/helpers/pathAllowlist.d.ts +27 -0
- package/dist/helpers/pathAllowlist.d.ts.map +1 -0
- package/dist/helpers/pathAllowlist.js +177 -0
- package/dist/helpers/pathAllowlist.js.map +1 -0
- package/dist/helpers/pathGlob.d.ts +15 -0
- package/dist/helpers/pathGlob.d.ts.map +1 -0
- package/dist/helpers/pathGlob.js +47 -0
- package/dist/helpers/pathGlob.js.map +1 -0
- package/dist/helpers/requireConfirmation.d.ts +119 -0
- package/dist/helpers/requireConfirmation.d.ts.map +1 -0
- package/dist/helpers/requireConfirmation.js +148 -0
- package/dist/helpers/requireConfirmation.js.map +1 -0
- package/dist/helpers/sensitivePathDenylist.d.ts +32 -0
- package/dist/helpers/sensitivePathDenylist.d.ts.map +1 -0
- package/dist/helpers/sensitivePathDenylist.js +49 -0
- package/dist/helpers/sensitivePathDenylist.js.map +1 -0
- package/dist/helpers/spaceResolver.d.ts +4 -0
- package/dist/helpers/spaceResolver.d.ts.map +1 -0
- package/dist/helpers/spaceResolver.js +18 -0
- package/dist/helpers/spaceResolver.js.map +1 -0
- package/dist/helpers/stripLinks.d.ts +15 -0
- package/dist/helpers/stripLinks.d.ts.map +1 -0
- package/dist/helpers/stripLinks.js +19 -0
- package/dist/helpers/stripLinks.js.map +1 -0
- package/dist/helpers/urlParser.d.ts +16 -0
- package/dist/helpers/urlParser.d.ts.map +1 -0
- package/dist/helpers/urlParser.js +83 -0
- package/dist/helpers/urlParser.js.map +1 -0
- package/dist/helpers/userCache.d.ts +14 -0
- package/dist/helpers/userCache.d.ts.map +1 -0
- package/dist/helpers/userCache.js +16 -0
- package/dist/helpers/userCache.js.map +1 -0
- package/dist/helpers/validateExecutePath.d.ts +29 -0
- package/dist/helpers/validateExecutePath.d.ts.map +1 -0
- package/dist/helpers/validateExecutePath.js +62 -0
- package/dist/helpers/validateExecutePath.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -15
- package/dist/index.js.map +1 -1
- package/dist/resources/catalog/capabilities.d.ts +36 -0
- package/dist/resources/catalog/capabilities.d.ts.map +1 -0
- package/dist/resources/catalog/capabilities.js +90 -0
- package/dist/resources/catalog/capabilities.js.map +1 -0
- package/dist/resources/catalog/llmsTxt.d.ts +8 -0
- package/dist/resources/catalog/llmsTxt.d.ts.map +1 -0
- package/dist/resources/catalog/llmsTxt.js +44 -0
- package/dist/resources/catalog/llmsTxt.js.map +1 -0
- package/dist/resources/dispatch.d.ts +30 -0
- package/dist/resources/dispatch.d.ts.map +1 -0
- package/dist/resources/dispatch.js +81 -0
- package/dist/resources/dispatch.js.map +1 -0
- package/dist/resources/featureToggle.d.ts +2 -0
- package/dist/resources/featureToggle.d.ts.map +1 -0
- package/dist/resources/featureToggle.js +34 -0
- package/dist/resources/featureToggle.js.map +1 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +44 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/interruption.d.ts +2 -0
- package/dist/resources/interruption.d.ts.map +1 -0
- package/dist/resources/interruption.js +34 -0
- package/dist/resources/interruption.js.map +1 -0
- package/dist/resources/release.d.ts +2 -0
- package/dist/resources/release.d.ts.map +1 -0
- package/dist/resources/release.js +33 -0
- package/dist/resources/release.js.map +1 -0
- package/dist/resources/rolloutGroup.d.ts +2 -0
- package/dist/resources/rolloutGroup.d.ts.map +1 -0
- package/dist/resources/rolloutGroup.js +35 -0
- package/dist/resources/rolloutGroup.js.map +1 -0
- package/dist/resources/runbook.d.ts +2 -0
- package/dist/resources/runbook.d.ts.map +1 -0
- package/dist/resources/runbook.js +34 -0
- package/dist/resources/runbook.js.map +1 -0
- package/dist/resources/task.d.ts +2 -0
- package/dist/resources/task.d.ts.map +1 -0
- package/dist/resources/task.js +68 -0
- package/dist/resources/task.js.map +1 -0
- package/dist/tools/createRelease.d.ts +3 -0
- package/dist/tools/createRelease.d.ts.map +1 -0
- package/dist/tools/createRelease.js +151 -0
- package/dist/tools/createRelease.js.map +1 -0
- package/dist/tools/deployRelease.d.ts +3 -0
- package/dist/tools/deployRelease.d.ts.map +1 -0
- package/dist/tools/deployRelease.js +227 -0
- package/dist/tools/deployRelease.js.map +1 -0
- package/dist/tools/execute.d.ts +3 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +261 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/findAccounts.d.ts +3 -0
- package/dist/tools/findAccounts.d.ts.map +1 -0
- package/dist/tools/findAccounts.js +90 -0
- package/dist/tools/findAccounts.js.map +1 -0
- package/dist/tools/findCertificates.d.ts +3 -0
- package/dist/tools/findCertificates.d.ts.map +1 -0
- package/dist/tools/findCertificates.js +98 -0
- package/dist/tools/findCertificates.js.map +1 -0
- package/dist/tools/findDeploymentTargets.d.ts +3 -0
- package/dist/tools/findDeploymentTargets.d.ts.map +1 -0
- package/dist/tools/findDeploymentTargets.js +161 -0
- package/dist/tools/findDeploymentTargets.js.map +1 -0
- package/dist/tools/findFeatureToggles.d.ts +37 -0
- package/dist/tools/findFeatureToggles.d.ts.map +1 -0
- package/dist/tools/findFeatureToggles.js +139 -0
- package/dist/tools/findFeatureToggles.js.map +1 -0
- package/dist/tools/findInterruptions.d.ts +79 -0
- package/dist/tools/findInterruptions.d.ts.map +1 -0
- package/dist/tools/findInterruptions.js +273 -0
- package/dist/tools/findInterruptions.js.map +1 -0
- package/dist/tools/findReleases.d.ts +3 -0
- package/dist/tools/findReleases.d.ts.map +1 -0
- package/dist/tools/findReleases.js +138 -0
- package/dist/tools/findReleases.js.map +1 -0
- package/dist/tools/findRunbooks.d.ts +3 -0
- package/dist/tools/findRunbooks.d.ts.map +1 -0
- package/dist/tools/findRunbooks.js +139 -0
- package/dist/tools/findRunbooks.js.map +1 -0
- package/dist/tools/findTenants.d.ts +19 -0
- package/dist/tools/findTenants.d.ts.map +1 -0
- package/dist/tools/findTenants.js +133 -0
- package/dist/tools/findTenants.js.map +1 -0
- package/dist/tools/getBranches.d.ts.map +1 -1
- package/dist/tools/getBranches.js +51 -33
- package/dist/tools/getBranches.js.map +1 -1
- package/dist/tools/getCurrentUser.d.ts.map +1 -1
- package/dist/tools/getCurrentUser.js +34 -25
- package/dist/tools/getCurrentUser.js.map +1 -1
- package/dist/tools/getDeploymentFromUrl.d.ts +57 -0
- package/dist/tools/getDeploymentFromUrl.d.ts.map +1 -0
- package/dist/tools/getDeploymentFromUrl.js +162 -0
- package/dist/tools/getDeploymentFromUrl.js.map +1 -0
- package/dist/tools/getDeploymentProcess.d.ts.map +1 -1
- package/dist/tools/getDeploymentProcess.js +57 -19
- package/dist/tools/getDeploymentProcess.js.map +1 -1
- package/dist/tools/getKubernetesLiveStatus.d.ts.map +1 -1
- package/dist/tools/getKubernetesLiveStatus.js +70 -48
- package/dist/tools/getKubernetesLiveStatus.js.map +1 -1
- package/dist/tools/getMissingTenantVariables.d.ts.map +1 -1
- package/dist/tools/getMissingTenantVariables.js +58 -26
- package/dist/tools/getMissingTenantVariables.js.map +1 -1
- package/dist/tools/getTaskFromUrl.d.ts +18 -0
- package/dist/tools/getTaskFromUrl.d.ts.map +1 -0
- package/dist/tools/getTaskFromUrl.js +90 -0
- package/dist/tools/getTaskFromUrl.js.map +1 -0
- package/dist/tools/getTenantVariables.d.ts.map +1 -1
- package/dist/tools/getTenantVariables.js +58 -38
- package/dist/tools/getTenantVariables.js.map +1 -1
- package/dist/tools/getVariables.d.ts.map +1 -1
- package/dist/tools/getVariables.js +12 -9
- package/dist/tools/getVariables.js.map +1 -1
- package/dist/tools/grepLlmsTxt.d.ts +13 -0
- package/dist/tools/grepLlmsTxt.d.ts.map +1 -0
- package/dist/tools/grepLlmsTxt.js +105 -0
- package/dist/tools/grepLlmsTxt.js.map +1 -0
- package/dist/tools/grepTaskLog.d.ts +30 -0
- package/dist/tools/grepTaskLog.d.ts.map +1 -0
- package/dist/tools/grepTaskLog.js +116 -0
- package/dist/tools/grepTaskLog.js.map +1 -0
- package/dist/tools/index.d.ts +22 -18
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +33 -21
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/listDeployments.d.ts.map +1 -1
- package/dist/tools/listDeployments.js +77 -37
- package/dist/tools/listDeployments.js.map +1 -1
- package/dist/tools/listEnvironments.d.ts.map +1 -1
- package/dist/tools/listEnvironments.js +63 -37
- package/dist/tools/listEnvironments.js.map +1 -1
- package/dist/tools/listProjects.d.ts.map +1 -1
- package/dist/tools/listProjects.js +64 -38
- package/dist/tools/listProjects.js.map +1 -1
- package/dist/tools/listSpaces.d.ts.map +1 -1
- package/dist/tools/listSpaces.js +56 -30
- package/dist/tools/listSpaces.js.map +1 -1
- package/dist/tools/readResource.d.ts +3 -0
- package/dist/tools/readResource.d.ts.map +1 -0
- package/dist/tools/readResource.js +50 -0
- package/dist/tools/readResource.js.map +1 -0
- package/dist/tools/runRunbook.d.ts +3 -0
- package/dist/tools/runRunbook.d.ts.map +1 -0
- package/dist/tools/runRunbook.js +174 -0
- package/dist/tools/runRunbook.js.map +1 -0
- package/dist/tools/updateFeatureToggle.d.ts +94 -0
- package/dist/tools/updateFeatureToggle.d.ts.map +1 -0
- package/dist/tools/updateFeatureToggle.js +308 -0
- package/dist/tools/updateFeatureToggle.js.map +1 -0
- package/dist/types/featureToggleTypes.d.ts +47 -0
- package/dist/types/featureToggleTypes.d.ts.map +1 -0
- package/dist/types/featureToggleTypes.js +10 -0
- package/dist/types/featureToggleTypes.js.map +1 -0
- package/dist/types/resourceConfig.d.ts +17 -0
- package/dist/types/resourceConfig.d.ts.map +1 -0
- package/dist/types/resourceConfig.js +6 -0
- package/dist/types/resourceConfig.js.map +1 -0
- package/dist/types/toolAnnotations.d.ts +8 -0
- package/dist/types/toolAnnotations.d.ts.map +1 -0
- package/dist/types/toolAnnotations.js +28 -0
- package/dist/types/toolAnnotations.js.map +1 -0
- package/dist/types/toolConfig.d.ts +7 -1
- package/dist/types/toolConfig.d.ts.map +1 -1
- package/dist/types/toolConfig.js +4 -1
- package/dist/types/toolConfig.js.map +1 -1
- package/dist/utils/parseConfig.d.ts +1 -1
- package/dist/utils/parseConfig.d.ts.map +1 -1
- package/dist/utils/parseConfig.js +3 -2
- package/dist/utils/parseConfig.js.map +1 -1
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +3 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +9 -3
- package/dist/tools/getAccount.d.ts +0 -3
- package/dist/tools/getAccount.d.ts.map +0 -1
- package/dist/tools/getAccount.js +0 -40
- package/dist/tools/getAccount.js.map +0 -1
- package/dist/tools/getCertificate.d.ts +0 -3
- package/dist/tools/getCertificate.d.ts.map +0 -1
- package/dist/tools/getCertificate.js +0 -40
- package/dist/tools/getCertificate.js.map +0 -1
- package/dist/tools/getDeploymentTarget.d.ts +0 -3
- package/dist/tools/getDeploymentTarget.d.ts.map +0 -1
- package/dist/tools/getDeploymentTarget.js +0 -66
- package/dist/tools/getDeploymentTarget.js.map +0 -1
- package/dist/tools/getReleaseById.d.ts +0 -3
- package/dist/tools/getReleaseById.d.ts.map +0 -1
- package/dist/tools/getReleaseById.js +0 -45
- package/dist/tools/getReleaseById.js.map +0 -1
- package/dist/tools/getTaskById.d.ts +0 -9
- package/dist/tools/getTaskById.d.ts.map +0 -1
- package/dist/tools/getTaskById.js +0 -44
- package/dist/tools/getTaskById.js.map +0 -1
- package/dist/tools/getTaskDetails.d.ts +0 -9
- package/dist/tools/getTaskDetails.d.ts.map +0 -1
- package/dist/tools/getTaskDetails.js +0 -44
- package/dist/tools/getTaskDetails.js.map +0 -1
- package/dist/tools/getTaskRaw.d.ts +0 -9
- package/dist/tools/getTaskRaw.d.ts.map +0 -1
- package/dist/tools/getTaskRaw.js +0 -43
- package/dist/tools/getTaskRaw.js.map +0 -1
- package/dist/tools/getTenantById.d.ts +0 -3
- package/dist/tools/getTenantById.d.ts.map +0 -1
- package/dist/tools/getTenantById.js +0 -50
- package/dist/tools/getTenantById.js.map +0 -1
- package/dist/tools/listAccounts.d.ts +0 -3
- package/dist/tools/listAccounts.d.ts.map +0 -1
- package/dist/tools/listAccounts.js +0 -54
- package/dist/tools/listAccounts.js.map +0 -1
- package/dist/tools/listCertificates.d.ts +0 -3
- package/dist/tools/listCertificates.d.ts.map +0 -1
- package/dist/tools/listCertificates.js +0 -62
- package/dist/tools/listCertificates.js.map +0 -1
- package/dist/tools/listDeploymentTargets.d.ts +0 -3
- package/dist/tools/listDeploymentTargets.d.ts.map +0 -1
- package/dist/tools/listDeploymentTargets.js +0 -98
- package/dist/tools/listDeploymentTargets.js.map +0 -1
- package/dist/tools/listReleases.d.ts +0 -3
- package/dist/tools/listReleases.d.ts.map +0 -1
- package/dist/tools/listReleases.js +0 -54
- package/dist/tools/listReleases.js.map +0 -1
- package/dist/tools/listReleasesForProject.d.ts +0 -3
- package/dist/tools/listReleasesForProject.d.ts.map +0 -1
- package/dist/tools/listReleasesForProject.js +0 -60
- package/dist/tools/listReleasesForProject.js.map +0 -1
- package/dist/tools/listTenants.d.ts +0 -3
- package/dist/tools/listTenants.d.ts.map +0 -1
- package/dist/tools/listTenants.js +0 -69
- package/dist/tools/listTenants.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { registerTools } from "./tools/index.js";
|
|
5
|
+
import { registerResources } from "./resources/index.js";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import dotenv from "dotenv";
|
|
7
8
|
import { createToolsetConfig } from "./utils/parseConfig.js";
|
|
8
|
-
import { DEFAULT_TOOLSETS, printToolVersionAnalysis } from "./types/toolConfig.js";
|
|
9
|
+
import { DEFAULT_TOOLSETS, printToolVersionAnalysis, } from "./types/toolConfig.js";
|
|
9
10
|
import { getClientConfigurationFromEnvironment } from "./helpers/getClientConfigurationFromEnvironment.js";
|
|
10
11
|
import { setClientInfo } from "./utils/clientInfo.js";
|
|
11
12
|
import { logger } from "./utils/logger.js";
|
|
12
13
|
import packageJson from "../package.json" with { type: "json" };
|
|
13
14
|
import { fileURLToPath } from "url";
|
|
14
|
-
import { dirname, join
|
|
15
|
+
import { dirname, join } from "path";
|
|
15
16
|
export const SEMVER_VERSION = packageJson.version;
|
|
16
17
|
// Set entry directory for logger (ESM equivalent of __dirname)
|
|
17
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -24,28 +25,81 @@ program
|
|
|
24
25
|
.description("Octopus Deploy MCP Server")
|
|
25
26
|
.version(SEMVER_VERSION)
|
|
26
27
|
.option("-s, --server-url <url>", "Octopus server URL")
|
|
27
|
-
.option("-k, --api-key <key>", "Octopus API key")
|
|
28
28
|
.option("--toolsets <toolsets>", `Comma-separated list of toolsets to enable, or "all" (default: all). Available toolsets: ${DEFAULT_TOOLSETS.join(", ")}`)
|
|
29
|
-
.option("--read-only", "Enable read-only mode (default: enabled)"
|
|
29
|
+
.option("--read-only", "Enable read-only mode: disable all write tools and block POST/PUT/PATCH/DELETE through the execute tool (default: write tools enabled)")
|
|
30
|
+
.option("--allow-deletes", "Permit DELETE-method requests through the execute tool. Has no effect when --read-only is set. Default false.")
|
|
30
31
|
.option("--log-level <level>", "Minimum log level (info, error)", "info")
|
|
31
|
-
.option("--log-file <path>",
|
|
32
|
+
.option("--log-file <path>", "Log file path or filename. If not specified, logs are written to console only.")
|
|
32
33
|
.option("-q, --quiet", "Disable file logging, only log errors to console", false)
|
|
33
34
|
.option("--list-tools-by-version", "List all registered tools by their supported Octopus Server version and exit")
|
|
34
35
|
.parse();
|
|
35
36
|
const options = program.opts();
|
|
37
|
+
// Resolve the Octopus server URL up front so the MCP `instructions` string
|
|
38
|
+
// can advertise which instance the client is connected to. Mirrors the
|
|
39
|
+
// precedence used by getClientConfigurationFromEnvironment (CLI flag wins
|
|
40
|
+
// over OCTOPUS_SERVER_URL env var).
|
|
41
|
+
if (options.serverUrl) {
|
|
42
|
+
process.env.CLI_SERVER_URL = options.serverUrl;
|
|
43
|
+
}
|
|
44
|
+
const configuredServerUrl = process.env.CLI_SERVER_URL ||
|
|
45
|
+
process.env.OCTOPUS_SERVER_URL ||
|
|
46
|
+
"(not configured — set OCTOPUS_SERVER_URL or pass --server-url)";
|
|
47
|
+
const SERVER_INSTRUCTIONS = `
|
|
48
|
+
The official Octopus Deploy MCP server, currently connected to: ${configuredServerUrl}
|
|
49
|
+
|
|
50
|
+
Tools are grouped into toolsets (core, releases, deployments, tasks, tenants, kubernetes, machines, certificates, accounts, interruptions, featureToggles) and you can filter them via --toolsets. Writes are on by default; pass --read-only to gate them off.
|
|
51
|
+
|
|
52
|
+
Resource URIs and how to dereference them:
|
|
53
|
+
- Many tools return slim summaries plus an 'octopus://...' URI in fields like 'resourceUri' or 'taskResourceUri' instead of inlining heavy payloads (release notes, packaged versions, structured task activity trees, etc.). To fetch the full body, dereference the URI.
|
|
54
|
+
- Resource-aware clients (Claude Code, MCP Inspector): call the standard 'resources/read' primitive with the URI.
|
|
55
|
+
- Clients without native resources/read (Claude.ai web, several IDE integrations): call the 'read_resource' tool with { uri }. It returns the same body as resources/read. Always available, regardless of toolset filter.
|
|
56
|
+
- The 'read_resource' tool is the universal bridge from any URI returned by any tool — if you see an 'octopus://' string in a response and don't know what to do with it, call read_resource with it.
|
|
57
|
+
|
|
58
|
+
Currently exposed resource families:
|
|
59
|
+
- releases: 'octopus://spaces/{spaceName}/releases/{releaseId}'
|
|
60
|
+
- tasks: 'octopus://spaces/{spaceName}/tasks/{taskId}' (metadata) and '/details' (structured ActivityLogs tree)
|
|
61
|
+
- interruptions: 'octopus://spaces/{spaceName}/interruptions/{interruptionId}' (full Form definition with control types, Markdown instructions, button options like Abort/Proceed, and any submitted Form.Values). The find_interruptions tool returns slim summaries that point at this URI; dereference it to drill into a specific interruption.
|
|
62
|
+
- feature toggles: 'octopus://spaces/{spaceName}/projects/{projectId}/featuretoggles/{slug}' (full toggle body — per-environment configuration including tenant lists, segments, minimum versions). The find_feature_toggles slim summaries omit those fields and point at this URI.
|
|
63
|
+
- rollout groups: 'octopus://spaces/{spaceName}/projects/{projectId}/rolloutgroups/{rolloutGroupId}' (read-only — this server doesn't expose rollout group writes; use the Octopus UI for those).
|
|
64
|
+
- catalog: 'octopus://api/llms.txt' is the markdown catalog of every Octopus REST endpoint (~300+ KB). 'octopus://api/capabilities' is the runtime introspection blob (server version, enabled toolsets, available tools, feature flags).
|
|
65
|
+
|
|
66
|
+
There is intentionally NO 'octopus://.../tasks/{id}/log' resource. Activity logs can be multi-megabyte; an addressable resource would tempt you to fetch the entire body when you almost always want only the matching lines. To search a task log, call the 'grep_task_log' tool — its parameters mirror GNU grep (pattern, caseInsensitive, invertMatch, fixedString, beforeContext, afterContext, maxCount) and it returns matching lines with totalMatches count and optional context windows. For step hierarchy / categories / timing, fetch the /details resource instead.
|
|
67
|
+
|
|
68
|
+
The same pattern applies to the API catalog: do NOT read 'octopus://api/llms.txt' directly because the body is large. Use the 'grep_llms_txt' tool — same GNU-grep parameter shape — to find the endpoints, methods, and request/response shapes you need.
|
|
69
|
+
|
|
70
|
+
The 'execute' tool reaches Octopus REST endpoints not covered by curated tools. **Method gating is hard-coded server-side**, three tiers:
|
|
71
|
+
- GET → read tier: always allowed (subject to toolset allowlist + sensitive denylist).
|
|
72
|
+
- POST / PUT / PATCH → write tier: blocked when --read-only is set; requires user confirmation via elicitation otherwise.
|
|
73
|
+
- DELETE → delete tier: requires --allow-deletes (and is blocked when --read-only is set) AND a stronger confirmation.
|
|
74
|
+
|
|
75
|
+
The HTTP method enum IS the read/write/delete classifier — the runtime classifies based on the actual method, never on a flag the agent sets. Use grep_llms_txt to discover the right path + method before calling execute.
|
|
76
|
+
|
|
77
|
+
More resource families will be added over time.
|
|
78
|
+
`.trim();
|
|
36
79
|
const server = new McpServer({
|
|
37
80
|
name: "Octopus Deploy",
|
|
38
81
|
description: "Official Octopus Deploy MCP server.",
|
|
39
82
|
version: SEMVER_VERSION,
|
|
83
|
+
}, {
|
|
84
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
40
85
|
});
|
|
41
|
-
const toolsetConfig = createToolsetConfig(options.toolsets, options.readOnly);
|
|
86
|
+
const toolsetConfig = createToolsetConfig(options.toolsets, options.readOnly, options.allowDeletes);
|
|
87
|
+
// `--allow-deletes` only takes effect when writes are enabled. Surface this
|
|
88
|
+
// on stderr at startup so an operator who set both --read-only and
|
|
89
|
+
// --allow-deletes doesn't silently end up with DELETE requests blocked.
|
|
90
|
+
if (toolsetConfig.allowDeletes && toolsetConfig.readOnlyMode) {
|
|
91
|
+
process.stderr.write("WARNING: --allow-deletes was provided, but --read-only is also set. " +
|
|
92
|
+
"DELETE requests through the execute tool remain blocked. Remove " +
|
|
93
|
+
"--read-only to enable DELETE.\n");
|
|
94
|
+
}
|
|
42
95
|
registerTools(server, toolsetConfig);
|
|
96
|
+
registerResources(server, toolsetConfig);
|
|
43
97
|
if (options.listToolsByVersion) {
|
|
44
98
|
printToolVersionAnalysis();
|
|
45
99
|
process.exit(0);
|
|
46
100
|
}
|
|
47
101
|
if (options.logFile) {
|
|
48
|
-
if (dirname(options.logFile) ===
|
|
102
|
+
if (dirname(options.logFile) === ".") {
|
|
49
103
|
logger.setLogFilePath(join(__dirname, options.logFile));
|
|
50
104
|
}
|
|
51
105
|
else {
|
|
@@ -54,14 +108,7 @@ if (options.logFile) {
|
|
|
54
108
|
}
|
|
55
109
|
logger.setLogLevel(logger.parseLogLevel(options.logLevel));
|
|
56
110
|
logger.setQuietMode(options.quiet);
|
|
57
|
-
|
|
58
|
-
process.env.CLI_SERVER_URL = options.serverUrl;
|
|
59
|
-
}
|
|
60
|
-
if (options.apiKey) {
|
|
61
|
-
process.env.CLI_API_KEY = options.apiKey;
|
|
62
|
-
}
|
|
63
|
-
// Test configuration
|
|
64
|
-
getClientConfigurationFromEnvironment();
|
|
111
|
+
// CLI_SERVER_URL is set earlier so the MCP instructions string can reference it.
|
|
65
112
|
// Set up initialization callback to capture client info
|
|
66
113
|
server.server.oninitialized = () => {
|
|
67
114
|
const clientInfo = server.server.getClientVersion();
|
|
@@ -76,6 +123,8 @@ server.server.oninitialized = () => {
|
|
|
76
123
|
logger.info(`Starting Octopus Deploy MCP server (version: ${SEMVER_VERSION})`);
|
|
77
124
|
// Start server
|
|
78
125
|
async function runServer() {
|
|
126
|
+
// Test configuration
|
|
127
|
+
getClientConfigurationFromEnvironment();
|
|
79
128
|
const transport = new StdioServerTransport();
|
|
80
129
|
await server.connect(transport);
|
|
81
130
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Toolset } from "../../types/toolConfig.js";
|
|
2
|
+
import { type MethodTier } from "../../helpers/methodTier.js";
|
|
3
|
+
interface CapabilityToolEntry {
|
|
4
|
+
name: string;
|
|
5
|
+
toolset: Toolset;
|
|
6
|
+
readOnly: boolean;
|
|
7
|
+
minimumOctopusVersion?: string;
|
|
8
|
+
/**
|
|
9
|
+
* True for tools whose actual read/write/delete behaviour depends on
|
|
10
|
+
* arguments rather than a static tool-level flag. Currently set only on
|
|
11
|
+
* `execute`, where the HTTP method is the runtime classifier.
|
|
12
|
+
*/
|
|
13
|
+
methodGated?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Effective method tiers reachable through this tool in the *current*
|
|
16
|
+
* session. For `execute` this reflects --read-only and --allow-deletes;
|
|
17
|
+
* for static tools it is undefined (the `readOnly` flag is sufficient).
|
|
18
|
+
*/
|
|
19
|
+
tiersAvailable?: MethodTier[];
|
|
20
|
+
}
|
|
21
|
+
interface Capabilities {
|
|
22
|
+
server: {
|
|
23
|
+
version: string;
|
|
24
|
+
installationId: string;
|
|
25
|
+
};
|
|
26
|
+
session: {
|
|
27
|
+
enabledToolsets: Toolset[];
|
|
28
|
+
readOnlyMode: boolean;
|
|
29
|
+
allowDeletes: boolean;
|
|
30
|
+
};
|
|
31
|
+
tools: CapabilityToolEntry[];
|
|
32
|
+
featureFlags?: unknown;
|
|
33
|
+
}
|
|
34
|
+
export declare function buildCapabilities(): Promise<Capabilities>;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../src/resources/catalog/capabilities.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,OAAO,EACb,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED,UAAU,YAAY;IACpB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,EAAE;QACP,eAAe,EAAE,OAAO,EAAE,CAAC;QAC3B,YAAY,EAAE,OAAO,CAAC;QACtB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAUD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,YAAY,CAAC,CAgE/D"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Client } from "@octopusdeploy/api-client";
|
|
2
|
+
import { registerResourceDescriptor } from "../../types/resourceConfig.js";
|
|
3
|
+
import { getClientConfigurationFromEnvironment } from "../../helpers/getClientConfigurationFromEnvironment.js";
|
|
4
|
+
import { TOOL_REGISTRY, DEFAULT_TOOLSETS, } from "../../types/toolConfig.js";
|
|
5
|
+
import { getActiveToolsetConfig } from "../../helpers/activeToolsetConfig.js";
|
|
6
|
+
import {} from "../../helpers/methodTier.js";
|
|
7
|
+
function resolveEnabledToolsets() {
|
|
8
|
+
const config = getActiveToolsetConfig();
|
|
9
|
+
if (config.enabledToolsets === "all" || config.enabledToolsets == null) {
|
|
10
|
+
return DEFAULT_TOOLSETS;
|
|
11
|
+
}
|
|
12
|
+
return config.enabledToolsets;
|
|
13
|
+
}
|
|
14
|
+
export async function buildCapabilities() {
|
|
15
|
+
const client = await Client.create(getClientConfigurationFromEnvironment());
|
|
16
|
+
const serverInfo = await client.getServerInformation();
|
|
17
|
+
const activeConfig = getActiveToolsetConfig();
|
|
18
|
+
const enabledToolsets = resolveEnabledToolsets();
|
|
19
|
+
const readOnlyMode = activeConfig.readOnlyMode ?? false;
|
|
20
|
+
const allowDeletes = activeConfig.allowDeletes ?? false;
|
|
21
|
+
const enabledSet = new Set(enabledToolsets);
|
|
22
|
+
enabledSet.add("core");
|
|
23
|
+
const tools = [];
|
|
24
|
+
for (const [name, registration] of TOOL_REGISTRY) {
|
|
25
|
+
if (!enabledSet.has(registration.config.toolset))
|
|
26
|
+
continue;
|
|
27
|
+
if (readOnlyMode && !registration.config.readOnly)
|
|
28
|
+
continue;
|
|
29
|
+
const entry = {
|
|
30
|
+
name,
|
|
31
|
+
toolset: registration.config.toolset,
|
|
32
|
+
readOnly: registration.config.readOnly,
|
|
33
|
+
minimumOctopusVersion: registration.minimumOctopusVersion,
|
|
34
|
+
};
|
|
35
|
+
// The execute tool registers as readOnly:true (so it survives the
|
|
36
|
+
// registration filter in read-only mode for its GET branch) but its
|
|
37
|
+
// actual behaviour is method-gated. Surface that explicitly so callers
|
|
38
|
+
// don't conclude execute is fully read-only.
|
|
39
|
+
if (name === "execute") {
|
|
40
|
+
entry.methodGated = true;
|
|
41
|
+
const tiers = ["read"];
|
|
42
|
+
if (!readOnlyMode)
|
|
43
|
+
tiers.push("write");
|
|
44
|
+
if (!readOnlyMode && allowDeletes)
|
|
45
|
+
tiers.push("delete");
|
|
46
|
+
entry.tiersAvailable = tiers;
|
|
47
|
+
}
|
|
48
|
+
tools.push(entry);
|
|
49
|
+
}
|
|
50
|
+
tools.sort((a, b) => a.name.localeCompare(b.name));
|
|
51
|
+
let featureFlags;
|
|
52
|
+
try {
|
|
53
|
+
featureFlags = await client.get("~/api/serverstatus/extensions");
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// The serverstatus/extensions endpoint isn't universally available across
|
|
57
|
+
// older Octopus versions. Omit feature flags rather than failing the whole
|
|
58
|
+
// capabilities read — server version is the high-value field.
|
|
59
|
+
featureFlags = undefined;
|
|
60
|
+
}
|
|
61
|
+
const capabilities = {
|
|
62
|
+
server: {
|
|
63
|
+
version: serverInfo.version,
|
|
64
|
+
installationId: serverInfo.installationId,
|
|
65
|
+
},
|
|
66
|
+
session: {
|
|
67
|
+
enabledToolsets: Array.from(enabledSet).sort(),
|
|
68
|
+
readOnlyMode,
|
|
69
|
+
allowDeletes,
|
|
70
|
+
},
|
|
71
|
+
tools,
|
|
72
|
+
};
|
|
73
|
+
if (featureFlags !== undefined) {
|
|
74
|
+
capabilities.featureFlags = featureFlags;
|
|
75
|
+
}
|
|
76
|
+
return capabilities;
|
|
77
|
+
}
|
|
78
|
+
registerResourceDescriptor({
|
|
79
|
+
name: "catalog-capabilities",
|
|
80
|
+
uriTemplate: "octopus://api/capabilities",
|
|
81
|
+
toolset: "core",
|
|
82
|
+
title: "Octopus MCP capabilities",
|
|
83
|
+
description: "Server version, enabled toolsets, available tools, and Octopus feature flags for this MCP session. Use this to discover what's reachable before calling other tools.",
|
|
84
|
+
mimeType: "application/json",
|
|
85
|
+
read: async () => ({
|
|
86
|
+
mimeType: "application/json",
|
|
87
|
+
text: JSON.stringify(await buildCapabilities()),
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../src/resources/catalog/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,qCAAqC,EAAE,MAAM,wDAAwD,CAAC;AAC/G,OAAO,EACL,aAAa,EACb,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAmB,MAAM,6BAA6B,CAAC;AAmC9D,SAAS,sBAAsB;IAC7B,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;IACxC,IAAI,MAAM,CAAC,eAAe,KAAK,KAAK,IAAI,MAAM,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;QACvE,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC,eAAe,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,qCAAqC,EAAE,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,oBAAoB,EAAE,CAAC;IAEvD,MAAM,YAAY,GAAG,sBAAsB,EAAE,CAAC;IAC9C,MAAM,eAAe,GAAG,sBAAsB,EAAE,CAAC;IACjD,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,IAAI,KAAK,CAAC;IACxD,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,IAAI,KAAK,CAAC;IAExD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAU,eAAe,CAAC,CAAC;IACrD,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,KAAK,GAA0B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,aAAa,EAAE,CAAC;QACjD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,SAAS;QAC3D,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ;YAAE,SAAS;QAC5D,MAAM,KAAK,GAAwB;YACjC,IAAI;YACJ,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,OAAO;YACpC,QAAQ,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ;YACtC,qBAAqB,EAAE,YAAY,CAAC,qBAAqB;SAC1D,CAAC;QACF,kEAAkE;QAClE,oEAAoE;QACpE,uEAAuE;QACvE,6CAA6C;QAC7C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;YACzB,MAAM,KAAK,GAAiB,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,CAAC,YAAY;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,CAAC,YAAY,IAAI,YAAY;gBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxD,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEnD,IAAI,YAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,MAAM,CAAC,GAAG,CAAU,+BAA+B,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,2EAA2E;QAC3E,8DAA8D;QAC9D,YAAY,GAAG,SAAS,CAAC;IAC3B,CAAC;IAED,MAAM,YAAY,GAAiB;QACjC,MAAM,EAAE;YACN,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,cAAc,EAAE,UAAU,CAAC,cAAc;SAC1C;QACD,OAAO,EAAE;YACP,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAe;YAC3D,YAAY;YACZ,YAAY;SACb;QACD,KAAK;KACN,CAAC;IACF,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC;IAC3C,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,0BAA0B,CAAC;IACzB,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,4BAA4B;IACzC,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,sKAAsK;IACxK,QAAQ,EAAE,kBAAkB;IAC5B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QACjB,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,iBAAiB,EAAE,CAAC;KAChD,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch llms.txt for the configured Octopus server, with a 5-minute TTL cache.
|
|
3
|
+
* Exposed so grep_llms_txt can share the same cache.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fetchLlmsTxt(): Promise<string>;
|
|
6
|
+
/** Test seam: clear the cache between tests. */
|
|
7
|
+
export declare function clearLlmsTxtCache(): void;
|
|
8
|
+
//# sourceMappingURL=llmsTxt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmsTxt.d.ts","sourceRoot":"","sources":["../../../src/resources/catalog/llmsTxt.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAcpD;AAED,gDAAgD;AAChD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Client } from "@octopusdeploy/api-client";
|
|
2
|
+
import { registerResourceDescriptor } from "../../types/resourceConfig.js";
|
|
3
|
+
import { getClientConfigurationFromEnvironment } from "../../helpers/getClientConfigurationFromEnvironment.js";
|
|
4
|
+
const LLMS_TXT_PATH = "~/api/experimental/llms.txt";
|
|
5
|
+
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
6
|
+
// Module-scoped cache keyed on the configured Octopus server URL. llms.txt
|
|
7
|
+
// only changes when Octopus itself ships a new version; refetching on every
|
|
8
|
+
// resource read or every grep call would burn ~360 KB of bandwidth and add
|
|
9
|
+
// latency to every catalog query.
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Fetch llms.txt for the configured Octopus server, with a 5-minute TTL cache.
|
|
13
|
+
* Exposed so grep_llms_txt can share the same cache.
|
|
14
|
+
*/
|
|
15
|
+
export async function fetchLlmsTxt() {
|
|
16
|
+
const configuration = getClientConfigurationFromEnvironment();
|
|
17
|
+
const cacheKey = configuration.instanceURL ?? "(unknown)";
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const hit = cache.get(cacheKey);
|
|
20
|
+
if (hit && now - hit.fetchedAt < CACHE_TTL_MS) {
|
|
21
|
+
return hit.body;
|
|
22
|
+
}
|
|
23
|
+
const client = await Client.create(configuration);
|
|
24
|
+
const body = await client.getRaw(LLMS_TXT_PATH);
|
|
25
|
+
cache.set(cacheKey, { body, fetchedAt: now });
|
|
26
|
+
return body;
|
|
27
|
+
}
|
|
28
|
+
/** Test seam: clear the cache between tests. */
|
|
29
|
+
export function clearLlmsTxtCache() {
|
|
30
|
+
cache.clear();
|
|
31
|
+
}
|
|
32
|
+
registerResourceDescriptor({
|
|
33
|
+
name: "catalog-llms-txt",
|
|
34
|
+
uriTemplate: "octopus://api/llms.txt",
|
|
35
|
+
toolset: "core",
|
|
36
|
+
title: "Octopus API catalog (llms.txt)",
|
|
37
|
+
description: "Markdown catalog of every Octopus REST endpoint, including HTTP method, path, query params, and request/response types. Large (~300+ KB) — prefer the grep_llms_txt tool to search it instead of reading the whole body. Requires Octopus Server 2026.2.3916 or later (the /api/experimental/llms.txt endpoint shipped in that release).",
|
|
38
|
+
mimeType: "text/markdown",
|
|
39
|
+
read: async () => ({
|
|
40
|
+
mimeType: "text/markdown",
|
|
41
|
+
text: await fetchLlmsTxt(),
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=llmsTxt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmsTxt.js","sourceRoot":"","sources":["../../../src/resources/catalog/llmsTxt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,qCAAqC,EAAE,MAAM,wDAAwD,CAAC;AAE/G,MAAM,aAAa,GAAG,6BAA6B,CAAC;AACpD,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAOnC,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,kCAAkC;AAClC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;AAE5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,aAAa,GAAG,qCAAqC,EAAE,CAAC;IAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,IAAI,WAAW,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC;QAC9C,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAChD,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,iBAAiB;IAC/B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,0BAA0B,CAAC;IACzB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,wBAAwB;IACrC,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,gCAAgC;IACvC,WAAW,EACT,0UAA0U;IAC5U,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QACjB,QAAQ,EAAE,eAAe;QACzB,IAAI,EAAE,MAAM,YAAY,EAAE;KAC3B,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry-driven dispatch for octopus:// resource URIs.
|
|
3
|
+
*
|
|
4
|
+
* Both the Resource Template registrations (src/resources/index.ts) and the
|
|
5
|
+
* `read_resource` Tool backstop (src/tools/readResource.ts) flow through the
|
|
6
|
+
* same descriptor registry, so resource-aware clients (which call resources/read)
|
|
7
|
+
* and resource-less clients (which call the Tool wrapper) hit identical logic.
|
|
8
|
+
*
|
|
9
|
+
* Toolset filtering is enforced at dispatch time. Native MCP clients only
|
|
10
|
+
* see resources whose toolset is enabled because registerResources skips
|
|
11
|
+
* disabled descriptors at registration. The `read_resource` backstop, by
|
|
12
|
+
* contrast, is registered under `core` and is always available — so without
|
|
13
|
+
* filtering here a caller could guess a URI for a descriptor whose toolset
|
|
14
|
+
* is disabled and still fetch the body. The filter below closes that gap.
|
|
15
|
+
*/
|
|
16
|
+
import { type ResourcePayload } from "../types/resourceConfig.js";
|
|
17
|
+
/**
|
|
18
|
+
* Pick the first value for each variable and URL-decode it.
|
|
19
|
+
*
|
|
20
|
+
* The SDK's UriTemplate.match captures regex groups as raw strings (no decoding),
|
|
21
|
+
* so an input URI like `octopus://spaces/AI%20Foundations/releases/Releases-1`
|
|
22
|
+
* yields `spaceName = "AI%20Foundations"` here. Decoding makes the variables
|
|
23
|
+
* usable directly against the Octopus API, which expects the literal `AI Foundations`.
|
|
24
|
+
*
|
|
25
|
+
* Falls back to the raw value if a string contains an invalid percent-escape so
|
|
26
|
+
* a malformed input surfaces as a clearer downstream error rather than a URIError.
|
|
27
|
+
*/
|
|
28
|
+
export declare function flatten(variables: Record<string, string | string[]>): Record<string, string>;
|
|
29
|
+
export declare function dispatchOctopusUri(uri: string): Promise<ResourcePayload | null>;
|
|
30
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/resources/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAmBpC;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAC3C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAmBD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAejC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry-driven dispatch for octopus:// resource URIs.
|
|
3
|
+
*
|
|
4
|
+
* Both the Resource Template registrations (src/resources/index.ts) and the
|
|
5
|
+
* `read_resource` Tool backstop (src/tools/readResource.ts) flow through the
|
|
6
|
+
* same descriptor registry, so resource-aware clients (which call resources/read)
|
|
7
|
+
* and resource-less clients (which call the Tool wrapper) hit identical logic.
|
|
8
|
+
*
|
|
9
|
+
* Toolset filtering is enforced at dispatch time. Native MCP clients only
|
|
10
|
+
* see resources whose toolset is enabled because registerResources skips
|
|
11
|
+
* disabled descriptors at registration. The `read_resource` backstop, by
|
|
12
|
+
* contrast, is registered under `core` and is always available — so without
|
|
13
|
+
* filtering here a caller could guess a URI for a descriptor whose toolset
|
|
14
|
+
* is disabled and still fetch the body. The filter below closes that gap.
|
|
15
|
+
*/
|
|
16
|
+
import { UriTemplate } from "@modelcontextprotocol/sdk/shared/uriTemplate.js";
|
|
17
|
+
import { RESOURCE_REGISTRY, } from "../types/resourceConfig.js";
|
|
18
|
+
import { DEFAULT_TOOLSETS, } from "../types/toolConfig.js";
|
|
19
|
+
import { getActiveToolsetConfig } from "../helpers/activeToolsetConfig.js";
|
|
20
|
+
const COMPILED = new WeakMap();
|
|
21
|
+
function compiled(descriptor) {
|
|
22
|
+
let template = COMPILED.get(descriptor);
|
|
23
|
+
if (!template) {
|
|
24
|
+
template = new UriTemplate(descriptor.uriTemplate);
|
|
25
|
+
COMPILED.set(descriptor, template);
|
|
26
|
+
}
|
|
27
|
+
return template;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Pick the first value for each variable and URL-decode it.
|
|
31
|
+
*
|
|
32
|
+
* The SDK's UriTemplate.match captures regex groups as raw strings (no decoding),
|
|
33
|
+
* so an input URI like `octopus://spaces/AI%20Foundations/releases/Releases-1`
|
|
34
|
+
* yields `spaceName = "AI%20Foundations"` here. Decoding makes the variables
|
|
35
|
+
* usable directly against the Octopus API, which expects the literal `AI Foundations`.
|
|
36
|
+
*
|
|
37
|
+
* Falls back to the raw value if a string contains an invalid percent-escape so
|
|
38
|
+
* a malformed input surfaces as a clearer downstream error rather than a URIError.
|
|
39
|
+
*/
|
|
40
|
+
export function flatten(variables) {
|
|
41
|
+
const out = {};
|
|
42
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
43
|
+
const first = Array.isArray(value) ? (value[0] ?? "") : value;
|
|
44
|
+
out[key] = safeDecode(first);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function safeDecode(value) {
|
|
49
|
+
try {
|
|
50
|
+
return decodeURIComponent(value);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function isToolsetEnabled(toolset, config) {
|
|
57
|
+
if (toolset === "core")
|
|
58
|
+
return true;
|
|
59
|
+
const enabled = config.enabledToolsets === "all"
|
|
60
|
+
? DEFAULT_TOOLSETS
|
|
61
|
+
: config.enabledToolsets || DEFAULT_TOOLSETS;
|
|
62
|
+
return enabled.includes(toolset);
|
|
63
|
+
}
|
|
64
|
+
export async function dispatchOctopusUri(uri) {
|
|
65
|
+
if (!uri.startsWith("octopus://"))
|
|
66
|
+
return null;
|
|
67
|
+
const config = getActiveToolsetConfig();
|
|
68
|
+
for (const descriptor of RESOURCE_REGISTRY) {
|
|
69
|
+
const variables = compiled(descriptor).match(uri);
|
|
70
|
+
if (!variables)
|
|
71
|
+
continue;
|
|
72
|
+
// Even though the URI matches, the descriptor's toolset may be disabled
|
|
73
|
+
// for this session. Skip and keep looking — but no other descriptor
|
|
74
|
+
// should claim the same template, so this effectively returns null.
|
|
75
|
+
if (!isToolsetEnabled(descriptor.toolset, config))
|
|
76
|
+
continue;
|
|
77
|
+
return descriptor.read(flatten(variables));
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/resources/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,OAAO,EACL,iBAAiB,GAGlB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,GAGjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAmC,CAAC;AAEhE,SAAS,QAAQ,CAAC,UAA8B;IAC9C,IAAI,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QACnD,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CACrB,SAA4C;IAE5C,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAgB,EAAE,MAAqB;IAC/D,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,OAAO,GACX,MAAM,CAAC,eAAe,KAAK,KAAK;QAC9B,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,MAAM,CAAC,eAAe,IAAI,gBAAgB,CAAC;IACjD,OAAO,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAW;IAEX,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/C,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;IACxC,KAAK,MAAM,UAAU,IAAI,iBAAiB,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,wEAAwE;QACxE,oEAAoE;QACpE,oEAAoE;QACpE,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;YAAE,SAAS;QAC5D,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureToggle.d.ts","sourceRoot":"","sources":["../../src/resources/featureToggle.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Client, resolveSpaceId } from "@octopusdeploy/api-client";
|
|
2
|
+
import { registerResourceDescriptor } from "../types/resourceConfig.js";
|
|
3
|
+
import { getClientConfigurationFromEnvironment } from "../helpers/getClientConfigurationFromEnvironment.js";
|
|
4
|
+
import { handleOctopusApiError } from "../helpers/errorHandling.js";
|
|
5
|
+
import { stripLinks } from "../helpers/stripLinks.js";
|
|
6
|
+
import {} from "../types/featureToggleTypes.js";
|
|
7
|
+
registerResourceDescriptor({
|
|
8
|
+
name: "featureToggle",
|
|
9
|
+
uriTemplate: "octopus://spaces/{spaceName}/projects/{projectId}/featuretoggles/{slug}",
|
|
10
|
+
toolset: "featureToggles",
|
|
11
|
+
title: "Octopus feature toggle",
|
|
12
|
+
description: "Full customer feature toggle body for a given slug in a project. Includes per-environment configuration (tenants, segments, minimum versions) that the find_feature_toggles slim summary omits.",
|
|
13
|
+
mimeType: "application/json",
|
|
14
|
+
read: async ({ spaceName, projectId, slug }) => {
|
|
15
|
+
try {
|
|
16
|
+
const client = await Client.create(getClientConfigurationFromEnvironment());
|
|
17
|
+
const spaceId = await resolveSpaceId(client, spaceName);
|
|
18
|
+
const toggle = await client.get("~/api/{spaceId}/projects/{projectId}/featuretoggles/{slug}", { spaceId, projectId, slug });
|
|
19
|
+
return {
|
|
20
|
+
mimeType: "application/json",
|
|
21
|
+
text: JSON.stringify(stripLinks(toggle)),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
handleOctopusApiError(error, {
|
|
26
|
+
entityType: "feature toggle",
|
|
27
|
+
entityId: slug,
|
|
28
|
+
spaceName,
|
|
29
|
+
helpText: "Use find_feature_toggles to list valid slugs. If 404 persists across all toggles, the customer feature toggles capability may be disabled on the Octopus instance.",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=featureToggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureToggle.js","sourceRoot":"","sources":["../../src/resources/featureToggle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,qCAAqC,EAAE,MAAM,qDAAqD,CAAC;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAA8B,MAAM,gCAAgC,CAAC;AAE5E,0BAA0B,CAAC;IACzB,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,yEAAyE;IAC3E,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EACT,iMAAiM;IACnM,QAAQ,EAAE,kBAAkB;IAC5B,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAChC,qCAAqC,EAAE,CACxC,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAC7B,4DAA4D,EAC5D,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAC7B,CAAC;YAEF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aACzC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,qBAAqB,CAAC,KAAK,EAAE;gBAC3B,UAAU,EAAE,gBAAgB;gBAC5B,QAAQ,EAAE,IAAI;gBACd,SAAS;gBACT,QAAQ,EACN,oKAAoK;aACvK,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type ToolsetConfig } from "../types/toolConfig.js";
|
|
3
|
+
import "./release.js";
|
|
4
|
+
import "./runbook.js";
|
|
5
|
+
import "./task.js";
|
|
6
|
+
import "./interruption.js";
|
|
7
|
+
import "./featureToggle.js";
|
|
8
|
+
import "./rolloutGroup.js";
|
|
9
|
+
import "./catalog/llmsTxt.js";
|
|
10
|
+
import "./catalog/capabilities.js";
|
|
11
|
+
export declare function registerResources(server: McpServer, config?: ToolsetConfig): void;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,cAAc,CAAC;AACtB,OAAO,cAAc,CAAC;AACtB,OAAO,WAAW,CAAC;AACnB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,2BAA2B,CAAC;AAWnC,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,GAAE,aAAkB,GAAG,IAAI,CA2BrF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { DEFAULT_TOOLSETS, } from "../types/toolConfig.js";
|
|
3
|
+
import { RESOURCE_REGISTRY } from "../types/resourceConfig.js";
|
|
4
|
+
import { flatten } from "./dispatch.js";
|
|
5
|
+
import { setActiveToolsetConfig } from "../helpers/activeToolsetConfig.js";
|
|
6
|
+
// Side-effect imports populate RESOURCE_REGISTRY.
|
|
7
|
+
import "./release.js";
|
|
8
|
+
import "./runbook.js";
|
|
9
|
+
import "./task.js";
|
|
10
|
+
import "./interruption.js";
|
|
11
|
+
import "./featureToggle.js";
|
|
12
|
+
import "./rolloutGroup.js";
|
|
13
|
+
import "./catalog/llmsTxt.js";
|
|
14
|
+
import "./catalog/capabilities.js";
|
|
15
|
+
function isToolsetEnabled(toolset, config) {
|
|
16
|
+
const enabled = config.enabledToolsets === "all"
|
|
17
|
+
? DEFAULT_TOOLSETS
|
|
18
|
+
: config.enabledToolsets || DEFAULT_TOOLSETS;
|
|
19
|
+
return toolset === "core" || enabled.includes(toolset);
|
|
20
|
+
}
|
|
21
|
+
export function registerResources(server, config = {}) {
|
|
22
|
+
setActiveToolsetConfig(config);
|
|
23
|
+
for (const descriptor of RESOURCE_REGISTRY) {
|
|
24
|
+
if (!isToolsetEnabled(descriptor.toolset, config))
|
|
25
|
+
continue;
|
|
26
|
+
server.registerResource(descriptor.name, new ResourceTemplate(descriptor.uriTemplate, { list: undefined }), {
|
|
27
|
+
title: descriptor.title,
|
|
28
|
+
description: descriptor.description,
|
|
29
|
+
mimeType: descriptor.mimeType,
|
|
30
|
+
}, async (uri, variables) => {
|
|
31
|
+
const payload = await descriptor.read(flatten(variables));
|
|
32
|
+
return {
|
|
33
|
+
contents: [
|
|
34
|
+
{
|
|
35
|
+
uri: uri.href,
|
|
36
|
+
mimeType: payload.mimeType,
|
|
37
|
+
text: payload.text,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAGL,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,kDAAkD;AAClD,OAAO,cAAc,CAAC;AACtB,OAAO,cAAc,CAAC;AACtB,OAAO,WAAW,CAAC;AACnB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,2BAA2B,CAAC;AAEnC,SAAS,gBAAgB,CAAC,OAAgB,EAAE,MAAqB;IAC/D,MAAM,OAAO,GACX,MAAM,CAAC,eAAe,KAAK,KAAK;QAC9B,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,MAAM,CAAC,eAAe,IAAI,gBAAgB,CAAC;IAEjD,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,SAAwB,EAAE;IAC7E,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,MAAM,UAAU,IAAI,iBAAiB,EAAE,CAAC;QAC3C,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;YAAE,SAAS;QAE5D,MAAM,CAAC,gBAAgB,CACrB,UAAU,CAAC,IAAI,EACf,IAAI,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EACjE;YACE,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,WAAW,EAAE,UAAU,CAAC,WAAW;YACnC,QAAQ,EAAE,UAAU,CAAC,QAAQ;SAC9B,EACD,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;YACvB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YAC1D,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;qBACnB;iBACF;aACF,CAAC;QACJ,CAAC,CACF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interruption.d.ts","sourceRoot":"","sources":["../../src/resources/interruption.ts"],"names":[],"mappings":""}
|