Skip to content

Commit 3d2d444

Browse files
fix: Add missing pagination parameters to various tools (#45)
1 parent 4ed95a8 commit 3d2d444

7 files changed

Lines changed: 113 additions & 78 deletions

File tree

src/tools/listDeployments.ts

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,68 @@ export function registerListDeploymentsTool(server: McpServer) {
1010
`List deployments in a space
1111
1212
This tool lists deployments in a given space. The space name is required. When requesting latest deployment consider which deployment state the user is interested in (successful or all). Optional filters include: projects (array of project IDs), environments (array of environment IDs), tenants (array of tenant IDs), channels (array of channel IDs), taskState (one of: Canceled, Cancelling, Executing, Failed, Queued, Success, TimedOut), and take (number of results to return).`,
13-
{
14-
spaceName: z.string(),
13+
{
14+
spaceName: z.string(),
1515
projects: z.array(z.string()).optional(),
1616
environments: z.array(z.string()).optional(),
1717
tenants: z.array(z.string()).optional(),
1818
channels: z.array(z.string()).optional(),
1919
taskState: z.enum(["Canceled", "Cancelling", "Executing", "Failed", "Queued", "Success", "TimedOut"]).optional(),
20+
skip: z.number().optional(),
2021
take: z.number().optional()
2122
},
2223
{
2324
title: "List deployments in an Octopus Deploy space",
2425
readOnlyHint: true,
2526
},
26-
async ({ spaceName, projects, environments, tenants, channels, taskState, take }) => {
27+
async ({ spaceName, projects, environments, tenants, channels, taskState, skip, take }) => {
2728
const configuration = getClientConfigurationFromEnvironment();
2829
const client = await Client.create(configuration);
2930
const deploymentRepository = new DeploymentRepository(client, spaceName);
3031

31-
const deploymentsResponse = await deploymentRepository.list({
32+
const deploymentsResponse = await deploymentRepository.list({
3233
projects,
3334
environments,
3435
tenants,
3536
channels,
3637
taskState: taskState ? TaskState[taskState as keyof typeof TaskState] : undefined,
38+
skip,
3739
take
3840
});
39-
40-
const deployments = deploymentsResponse.Items.map((deployment: Deployment) => ({
41-
spaceId: deployment.SpaceId,
42-
id: deployment.Id,
43-
name: deployment.Name,
44-
releaseId: deployment.ReleaseId,
45-
environmentId: deployment.EnvironmentId,
46-
tenantId: deployment.TenantId,
47-
projectId: deployment.ProjectId,
48-
channelId: deployment.ChannelId,
49-
created: deployment.Created,
50-
taskId: deployment.TaskId,
51-
deploymentProcessId: deployment.DeploymentProcessId,
52-
comments: deployment.Comments,
53-
formValues: deployment.FormValues,
54-
queueTime: deployment.QueueTime,
55-
queueTimeExpiry: deployment.QueueTimeExpiry,
56-
useGuidedFailure: deployment.UseGuidedFailure,
57-
specificMachineIds: deployment.SpecificMachineIds,
58-
excludedMachineIds: deployment.ExcludedMachineIds,
59-
skipActions: deployment.SkipActions,
60-
forcePackageDownload: deployment.ForcePackageDownload,
61-
forcePackageRedeployment: deployment.ForcePackageRedeployment,
62-
}));
6341

6442
return {
6543
content: [
6644
{
6745
type: "text",
68-
text: JSON.stringify(deployments),
46+
text: JSON.stringify({
47+
totalResults: deploymentsResponse.TotalResults,
48+
itemsPerPage: deploymentsResponse.ItemsPerPage,
49+
numberOfPages: deploymentsResponse.NumberOfPages,
50+
lastPageNumber: deploymentsResponse.LastPageNumber,
51+
items: deploymentsResponse.Items.map((deployment: Deployment) => ({
52+
spaceId: deployment.SpaceId,
53+
id: deployment.Id,
54+
name: deployment.Name,
55+
releaseId: deployment.ReleaseId,
56+
environmentId: deployment.EnvironmentId,
57+
tenantId: deployment.TenantId,
58+
projectId: deployment.ProjectId,
59+
channelId: deployment.ChannelId,
60+
created: deployment.Created,
61+
taskId: deployment.TaskId,
62+
deploymentProcessId: deployment.DeploymentProcessId,
63+
comments: deployment.Comments,
64+
formValues: deployment.FormValues,
65+
queueTime: deployment.QueueTime,
66+
queueTimeExpiry: deployment.QueueTimeExpiry,
67+
useGuidedFailure: deployment.UseGuidedFailure,
68+
specificMachineIds: deployment.SpecificMachineIds,
69+
excludedMachineIds: deployment.ExcludedMachineIds,
70+
skipActions: deployment.SkipActions,
71+
forcePackageDownload: deployment.ForcePackageDownload,
72+
forcePackageRedeployment: deployment.ForcePackageRedeployment,
73+
}))
74+
}),
6975
},
7076
],
7177
};

src/tools/listEnvironments.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,43 @@ export function registerListEnvironmentsTool(server: McpServer) {
1010
`List environments in a space
1111
1212
This tool lists all environments in a given space. The space name is required. Use this tool as early as possible to understand which environments are configured. Optionally filter by partial name match using partialName parameter.`,
13-
{ spaceName: z.string(), partialName: z.string().optional() },
13+
{
14+
spaceName: z.string(),
15+
partialName: z.string().optional(),
16+
skip: z.number().optional(),
17+
take: z.number().optional()
18+
},
1419
{
1520
title: "List all environments in an Octopus Deploy space",
1621
readOnlyHint: true,
1722
},
18-
async ({ spaceName, partialName }) => {
23+
async ({ spaceName, partialName, skip, take }) => {
1924
const configuration = getClientConfigurationFromEnvironment();
2025
const client = await Client.create(configuration);
2126
const environmentRepository = new EnvironmentRepository(client, spaceName);
2227

23-
const environmentsResponse = await environmentRepository.list({ partialName });
24-
const environments = environmentsResponse.Items.map((environment: DeploymentEnvironment) => ({
25-
spaceId: environment.SpaceId,
26-
id: environment.Id,
27-
name: environment.Name,
28-
description: environment.Description,
29-
sortOrder: environment.SortOrder,
30-
useGuidedFailure: environment.UseGuidedFailure,
31-
allowDynamicInfrastructure: environment.AllowDynamicInfrastructure,
32-
extensionSettings: environment.ExtensionSettings,
33-
}));
28+
const environmentsResponse = await environmentRepository.list({ partialName, skip, take });
3429

3530
return {
3631
content: [
3732
{
3833
type: "text",
39-
text: JSON.stringify(environments),
34+
text: JSON.stringify({
35+
totalResults: environmentsResponse.TotalResults,
36+
itemsPerPage: environmentsResponse.ItemsPerPage,
37+
numberOfPages: environmentsResponse.NumberOfPages,
38+
lastPageNumber: environmentsResponse.LastPageNumber,
39+
items: environmentsResponse.Items.map((environment: DeploymentEnvironment) => ({
40+
spaceId: environment.SpaceId,
41+
id: environment.Id,
42+
name: environment.Name,
43+
description: environment.Description,
44+
sortOrder: environment.SortOrder,
45+
useGuidedFailure: environment.UseGuidedFailure,
46+
allowDynamicInfrastructure: environment.AllowDynamicInfrastructure,
47+
extensionSettings: environment.ExtensionSettings,
48+
}))
49+
}),
4050
},
4151
],
4252
};

src/tools/listProjects.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,47 @@ export function registerListProjectsTool(server: McpServer) {
99
server.tool(
1010
"list_projects",
1111
`This tool lists all projects in a given space. ${projectsDescription} The space name is required, if you can't find the space name, ask the user directly for the name of the space. Optionally filter by partial name match using partialName parameter.`,
12-
{ spaceName: z.string(), partialName: z.string().optional() },
12+
{
13+
spaceName: z.string(),
14+
partialName: z.string().optional(),
15+
skip: z.number().optional(),
16+
take: z.number().optional()
17+
},
1318
{
1419
title: "List all projects in an Octopus Deploy space",
1520
readOnlyHint: true,
1621
},
17-
async ({ spaceName, partialName }) => {
22+
async ({ spaceName, partialName, skip, take }) => {
1823
const configuration = getClientConfigurationFromEnvironment();
1924
const client = await Client.create(configuration);
2025
const projectRepository = new ProjectRepository(client, spaceName);
2126

22-
const projectsResponse = await projectRepository.list({ partialName });
23-
const projects = projectsResponse.Items.map((project: Project) => ({
24-
spaceId: project.SpaceId,
25-
id: project.Id,
26-
name: project.Name,
27-
description: project.Description,
28-
slug: project.Slug,
29-
deploymentProcessId: project.DeploymentProcessId,
30-
lifecycleId: project.LifecycleId,
31-
isDisabled: project.IsDisabled,
32-
repositoryUrl:
33-
project.PersistenceSettings.Type === "VersionControlled"
34-
? project.PersistenceSettings.Url
35-
: null,
36-
}));
27+
const projectsResponse = await projectRepository.list({ partialName, skip, take });
3728

3829
return {
3930
content: [
4031
{
4132
type: "text",
42-
text: JSON.stringify(projects),
33+
text: JSON.stringify({
34+
totalResults: projectsResponse.TotalResults,
35+
itemsPerPage: projectsResponse.ItemsPerPage,
36+
numberOfPages: projectsResponse.NumberOfPages,
37+
lastPageNumber: projectsResponse.LastPageNumber,
38+
items: projectsResponse.Items.map((project: Project) => ({
39+
spaceId: project.SpaceId,
40+
id: project.Id,
41+
name: project.Name,
42+
description: project.Description,
43+
slug: project.Slug,
44+
deploymentProcessId: project.DeploymentProcessId,
45+
lifecycleId: project.LifecycleId,
46+
isDisabled: project.IsDisabled,
47+
repositoryUrl:
48+
project.PersistenceSettings.Type === "VersionControlled"
49+
? project.PersistenceSettings.Url
50+
: null,
51+
})),
52+
}),
4353
},
4454
],
4555
};

src/tools/listReleases.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export function registerListReleasesTool(server: McpServer) {
1212
This tool lists all releases in a given space. The space name is required. Optionally provide skip and take parameters for pagination.`,
1313
{
1414
spaceName: z.string().describe("The space name"),
15-
skip: z.number().optional().describe("Number of items to skip for pagination"),
16-
take: z.number().optional().describe("Number of items to take for pagination")
15+
skip: z.number().optional(),
16+
take: z.number().optional()
1717
},
1818
{
1919
title: "List all releases in an Octopus Deploy space",

src/tools/listReleasesForProject.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export function registerListReleasesForProjectTool(server: McpServer) {
1313
{
1414
spaceName: z.string(),
1515
projectId: z.string(),
16-
skip: z.number().optional().describe("Number of items to skip for pagination"),
17-
take: z.number().optional().describe("Number of items to take for pagination"),
16+
skip: z.number().optional(),
17+
take: z.number().optional(),
1818
searchByVersion: z.string().optional().describe("Search releases by version string")
1919
},
2020
{

src/tools/listSpaces.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,39 @@ export function registerListSpacesTool(server: McpServer) {
99
server.tool(
1010
"list_spaces",
1111
`List all spaces in the Octopus Deploy instance. ${spacesDescription} Always use this tool first to check that the requested space exists.`,
12-
{ partialName: z.string().optional() },
12+
{
13+
partialName: z.string().optional(),
14+
skip: z.number().optional(),
15+
take: z.number().optional()
16+
},
1317
{
1418
title: "List all spaces in an Octopus Deploy instance",
1519
readOnlyHint: true,
1620
},
17-
async ({ partialName }) => {
21+
async ({ partialName, skip, take }) => {
1822
const configuration = getClientConfigurationFromEnvironment();
1923
const client = await Client.create(configuration);
2024
const spaceRepository = new SpaceRepository(client);
2125

22-
const spacesResponse = await spaceRepository.list({ partialName });
23-
const spaces = spacesResponse.Items.map((space) => ({
24-
id: space.Id,
25-
name: space.Name,
26-
description: space.Description,
27-
isDefault: space.IsDefault,
28-
taskQueueStopped: space.TaskQueueStopped,
29-
}));
26+
const spacesResponse = await spaceRepository.list({ partialName, skip, take });
3027

3128
return {
3229
content: [
3330
{
3431
type: "text",
35-
text: JSON.stringify(spaces),
32+
text: JSON.stringify({
33+
totalResults: spacesResponse.TotalResults,
34+
itemsPerPage: spacesResponse.ItemsPerPage,
35+
numberOfPages: spacesResponse.NumberOfPages,
36+
lastPageNumber: spacesResponse.LastPageNumber,
37+
items: spacesResponse.Items.map((space) => ({
38+
id: space.Id,
39+
name: space.Name,
40+
description: space.Description,
41+
isDefault: space.IsDefault,
42+
taskQueueStopped: space.TaskQueueStopped,
43+
}))
44+
}),
3645
},
3746
],
3847
};

src/tools/listTenants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export function registerListTenantsTool(server: McpServer) {
1313
This tool lists all tenants in a given space. The space name is required. Optionally provide skip and take parameters for pagination.`,
1414
{
1515
spaceName: z.string().describe("The space name"),
16-
skip: z.number().optional().describe("Number of items to skip for pagination"),
17-
take: z.number().optional().describe("Number of items to take for pagination"),
16+
skip: z.number().optional(),
17+
take: z.number().optional(),
1818
projectId: z.string().optional().describe("Filter by specific project ID"),
1919
tags: z.string().optional().describe("Filter by tenant tags (comma-separated list)"),
2020
ids: z.array(z.string()).optional().describe("Filter by specific tenant IDs"),

0 commit comments

Comments
 (0)