Skip to main content
Glama
OctopusDeploy

Octopus Deploy MCP Server

Official

Read an Octopus resource by URI

read_resource
Read-onlyIdempotent

Fetch the full body of any 'octopus://' URI returned by other tools to access resource or task details.

Instructions

Universal fetch for any 'octopus://' URI returned by any other tool. Use this whenever you see fields like 'resourceUri' or 'taskResourceUri' in a response and need the full body.

How to use:

  • Pass the URI string verbatim. Examples: 'octopus://spaces/Default/releases/Releases-42', 'octopus://spaces/Default/tasks/ServerTasks-7', 'octopus://spaces/Default/tasks/ServerTasks-7/details'.

  • The response 'mimeType' tells you how to interpret 'text': 'application/json' → parse as JSON.

This tool is the backstop for clients that do not natively implement the MCP 'resources/read' primitive. Clients that DO support resources/read (Claude Code, MCP Inspector) can call it directly and skip this tool. Either path returns byte-identical bodies.

Tools that return resource URIs include: find_releases, get_deployment_from_url, get_task_from_url, and others. When in doubt, call read_resource on any 'octopus://' string you encounter.

Note: there is intentionally no octopus://...tasks/{id}/log resource. Call the grep_task_log tool to search task logs without inhaling the full body.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
uriYesAny 'octopus://...' URI returned by another tool (e.g. in the resourceUri or taskResourceUri field).

Implementation Reference

  • The actual handler and registration of the 'read_resource' tool. It accepts an 'octopus://' URI string, calls dispatchOctopusUri to resolve and fetch the resource, and returns the payload with uri, mimeType, and text.
      server.registerTool(
        "read_resource",
        {
          title: "Read an Octopus resource by URI",
          description: `Universal fetch for any 'octopus://' URI returned by any other tool. Use this whenever you see fields like 'resourceUri' or 'taskResourceUri' in a response and need the full body.
    
    How to use:
    - Pass the URI string verbatim. Examples: 'octopus://spaces/Default/releases/Releases-42', 'octopus://spaces/Default/tasks/ServerTasks-7', 'octopus://spaces/Default/tasks/ServerTasks-7/details'.
    - The response 'mimeType' tells you how to interpret 'text': 'application/json' → parse as JSON.
    
    This tool is the backstop for clients that do not natively implement the MCP 'resources/read' primitive. Clients that DO support resources/read (Claude Code, MCP Inspector) can call it directly and skip this tool. Either path returns byte-identical bodies.
    
    Tools that return resource URIs include: find_releases, get_deployment_from_url, get_task_from_url, and others. When in doubt, call read_resource on any 'octopus://' string you encounter.
    
    Note: there is intentionally no octopus://...tasks/{id}/log resource. Call the grep_task_log tool to search task logs without inhaling the full body.`,
          inputSchema: {
            uri: z
              .string()
              .describe(
                "Any 'octopus://...' URI returned by another tool (e.g. in the resourceUri or taskResourceUri field).",
              ),
          },
          annotations: READ_ONLY_TOOL_ANNOTATIONS,
        },
        async ({ uri }) => {
          const payload = await dispatchOctopusUri(uri);
    
          if (payload === null) {
            throw new Error(`Unrecognised resource URI '${uri}'.`);
          }
    
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify({
                  uri,
                  mimeType: payload.mimeType,
                  text: payload.text,
                }),
              },
            ],
          };
        },
      );
  • Input schema for the read_resource tool: a single required string parameter 'uri' described as an octopus:// URI.
    inputSchema: {
      uri: z
        .string()
        .describe(
          "Any 'octopus://...' URI returned by another tool (e.g. in the resourceUri or taskResourceUri field).",
        ),
    },
    annotations: READ_ONLY_TOOL_ANNOTATIONS,
  • Registration of read_resource in the tool registry. It belongs to the 'core' toolset and is read-only, ensuring it's always available regardless of toolset filtering.
    registerToolDefinition({
      toolName: "read_resource",
      config: { toolset: "core", readOnly: true },
      registerFn: registerReadResourceTool,
    });
  • Generic tool registration loop that registers all enabled tools (including read_resource) by iterating the TOOL_REGISTRY map.
    export function registerTools(server: McpServer, config: ToolsetConfig = {}) {
      // Iterate through all registered tools and register those that are enabled
      for (const [, toolRegistration] of TOOL_REGISTRY) {
        if (isToolEnabled(toolRegistration, config)) {
          toolRegistration.registerFn(server);
        }
      }
    }
  • The dispatch engine that resolves an octopus:// URI against the resource descriptor registry, respecting toolset filtering, and returns a ResourcePayload (mimeType + text) or null if not found.
    export async function dispatchOctopusUri(
      uri: string,
    ): Promise<ResourcePayload | null> {
      if (!uri.startsWith("octopus://")) return null;
    
      const config = getActiveToolsetConfig();
      for (const descriptor of RESOURCE_REGISTRY) {
        const variables = compiled(descriptor).match(uri);
        if (!variables) continue;
        // Even though the URI matches, the descriptor's toolset may be disabled
        // for this session. Skip and keep looking — but no other descriptor
        // should claim the same template, so this effectively returns null.
        if (!isToolsetEnabled(descriptor.toolset, config)) continue;
        return descriptor.read(flatten(variables));
      }
    
      return null;
    }
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=true, destructiveHint=false, idempotentHint=true. The description adds that this tool is a backstop for clients without resources/read, that both paths return byte-identical bodies, and discloses the non-existence of a task log resource. No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a lead sentence summarizing purpose, then a 'How to use' section with examples, notes on when to skip, and a caveat about missing resource. Every sentence adds value without being verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one param, no output schema, but annotations present), the description covers everything needed: purpose, usage, behavior, and a specific caveat. It also references sibling tools that produce URIs, ensuring the agent can use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a single parameter 'uri' described as 'Any octopus://... URI returned by another tool.' The description adds significant value: pass it verbatim, examples (e.g., octopus://spaces/Default/releases/Releases-42), and connection to resourceUri fields. This elevates beyond the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Universal fetch for any octopus:// URI returned by any other tool.' It specifies the verb (read), resource (Octopus resource by URI), and distinguishes from siblings by being the universal fetch tool. The context of resource URIs from other tools is explained.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance: 'Use this whenever you see fields like resourceUri or taskResourceUri in a response and need the full body.' It tells how to pass the URI verbatim with examples, how to interpret the response mimeType, and when to skip this tool (clients that support resources/read). It also notes that there is no resource for task logs, directing to grep_task_log.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/OctopusDeploy/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server