Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,26 @@ foreach (var run in runs?.Runs ?? [])
}
```

## Marketplace MCP connections — tool catalog

An MCP connection (a Marketplace connection whose listing uses the MCP
transport) stores its server's tool catalog when it is validated.
`Code.GetMarketplaceIntegrationToolsAsync` reads it
(`GET /{version}/code/marketplace/integrations/{IntegrationViewId}/tools`):
each tool has `Name`, `Title`, `Description`, `InputSchema` (JSON Schema as
text), `ReadOnlyHint` and `DestructiveHint`; the response also carries
`ListedAt`, `CatalogHash` and `Truncated`. A connection that was never
validated answers `CM-ERRORS-MARKETPLACE-020`. A function on a tool is saved
with `SaveMarketplaceFunction` (`Function.FunctionKey` = the tool name).

```csharp
var catalog = await hub.Code.GetMarketplaceIntegrationToolsAsync(
new GetMarketplaceIntegrationTools { IntegrationViewId = "int_…" });

foreach (var tool in catalog?.Tools ?? [])
Console.WriteLine($"{tool.Name} {(tool.ReadOnlyHint == true ? "read-only" : "writes")}");
```

## Coverage Notes

Generated coverage tracks the API and Hub DTO contract files. Some flows are not generated automatically:
Expand Down
41 changes: 41 additions & 0 deletions src/Norbix.Sdk.Types/Generated/Hub.dtos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4128,6 +4128,28 @@ public partial class MarketplaceListingProjection
public virtual string? VideoUrl { get; set; }
}

[DataContract]
public partial class MarketplaceMcpToolDto
{
[DataMember]
public virtual string Name { get; set; }

[DataMember]
public virtual string? Title { get; set; }

[DataMember]
public virtual string? Description { get; set; }

[DataMember]
public virtual string InputSchema { get; set; }

[DataMember]
public virtual bool? ReadOnlyHint { get; set; }

[DataMember]
public virtual bool? DestructiveHint { get; set; }
}

public enum MarketplaceParameterLocation
{
Body,
Expand Down Expand Up @@ -11598,6 +11620,25 @@ public partial class GetMarketplaceIntegrationsResponse
public virtual PaginatedResponse<MarketplaceIntegrationListProjection>? List { get; set; }
}

[NorbixRoute("/{version}/code/marketplace/integrations/{IntegrationViewId}/tools", "GET")]
public partial class GetMarketplaceIntegrationTools
: CodeMashRequestBase, INorbixRequest<GetMarketplaceIntegrationToolsResponse>
{
///<summary>
///Integration view id, from get_marketplace_integrations.
///</summary>
public virtual string IntegrationViewId { get; set; }
}

public partial class GetMarketplaceIntegrationToolsResponse
: ResponseBase
{
public virtual IReadOnlyList<MarketplaceMcpToolDto> Tools { get; set; }
public virtual DateTimeOffset? ListedAt { get; set; }
public virtual string? CatalogHash { get; set; }
public virtual bool Truncated { get; set; }
}

[NorbixRoute("/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets", "PUT")]
[DataContract]
public partial class ReplaceMarketplaceIntegrationSecretsRequest
Expand Down
57 changes: 57 additions & 0 deletions tests/Norbix.Hub.Tests/MarketplaceMcpToolsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Norbix.Sdk.Tests.Helpers;
using Norbix.Sdk.Types.Hub;

using NUnit.Framework;

using VerifyNUnit;

namespace Norbix.Hub.Tests;

/// <summary>
/// GET /{version}/code/marketplace/integrations/{IntegrationViewId}/tools returns
/// the stored tool catalog of an MCP connection. The coverage snapshot sends a
/// placeholder id; this case pins a real connection id in the path, no query
/// value for it, no body, and the catalog read back from the generated response.
/// Nothing leaves the process.
/// </summary>
[TestFixture]
public sealed class MarketplaceMcpToolsTests
{
private static NorbixTestFixture NewFixture() =>
NorbixTestFixture.Create(o =>
{
o.AccountId = "test-account";
o.BearerToken = "test-bearer";
});

[Test]
public async Task Tools_put_the_connection_id_in_the_path_with_no_body()
{
using var fixture = NewFixture();
fixture.RespondNext(new
{
tools = new[]
{
new
{
name = "create_issue",
title = "Create issue",
description = "Open a new issue in a repository",
inputSchema = "{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"}},\"required\":[\"title\"]}",
readOnlyHint = false,
destructiveHint = false,
},
},
listedAt = "2026-10-13T08:00:00Z",
catalogHash = "4ce4259bec02f283",
truncated = false,
});

var response = await fixture.Client.Code.GetMarketplaceIntegrationToolsAsync(
new GetMarketplaceIntegrationTools { IntegrationViewId = "int_7Hq2mcpServer" });

await Verifier.Verify(
new { Sent = fixture.LastRequest, response!.Tools, response.CatalogHash, response.Truncated },
VerifyConfig.VerifySettings);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
Target: Hub,
Group: code,
Count: 38,
Count: 39,
Endpoints: [
{
Target: Hub,
Expand Down Expand Up @@ -1060,6 +1060,41 @@
}
}
},
{
Target: Hub,
Group: code,
MethodName: GetMarketplaceIntegrationToolsAsync,
RequestType: GetMarketplaceIntegrationTools,
HttpMethod: GET,
Path: /{version}/code/marketplace/integrations/{IntegrationViewId}/tools,
PathParams: [
IntegrationViewId
],
IsAccountScoped: false,
IsUnauthenticated: false,
Sent: {
Method: GET,
Path: /v2/code/marketplace/integrations/{guid}/tools,
Query: ?env=test-env,
Headers: {
Authorization: Bearer test-bearer,
norbix-account-id: test-account,
norbix-project-id: test-project
}
},
ResponseType: GetMarketplaceIntegrationToolsResponse,
Response: {
Tools: [
{}
],
ListedAt: DateTimeOffset_1,
CatalogHash: test-catalogHash,
Truncated: true,
ResponseStatus: {
IsSuccess: true
}
}
},
{
Target: Hub,
Group: code,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
Sent: {
Method: GET,
Path: /v2/code/marketplace/integrations/int_7Hq2mcpServer/tools,
Headers: {
Authorization: Bearer test-bearer,
norbix-account-id: test-account,
norbix-project-id: test-project
}
},
Tools: [
{
Name: create_issue,
Title: Create issue,
Description: Open a new issue in a repository,
InputSchema: {"type":"object","properties":{"title":{"type":"string"}},"required":["title"]},
ReadOnlyHint: false,
DestructiveHint: false
}
],
CatalogHash: 4ce4259bec02f283,
Truncated: false
}
Loading