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
24 changes: 24 additions & 0 deletions docs/hub/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Accessed as `norbix.hub.code` on the [`Norbix`](../../README.md#authentication)
| [`invokeMarketplaceFunction`](#invokemarketplacefunction) | `POST` | `/{version}/code/marketplace/functions/{FunctionViewId}/invoke` | `project` |
| [`getMarketplaceListing`](#getmarketplacelisting) | `GET` | `/{version}/code/marketplace/listings/{ListingViewId}` | `project` |
| [`testMarketplaceIntegration`](#testmarketplaceintegration) | `POST` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/test` | `project` |
| [`getMarketplaceIntegrationTools`](#getmarketplaceintegrationtools) | `GET` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/tools` | `project` |
| [`replaceMarketplaceIntegrationSecrets`](#replacemarketplaceintegrationsecrets) | `PUT` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets` | `project` |
| [`revealMarketplaceIntegrationSecrets`](#revealmarketplaceintegrationsecrets) | `POST` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets/reveal` | `project` |
| [`setMarketplaceIntegrationTokenMappings`](#setmarketplaceintegrationtokenmappings) | `PUT` | `/{version}/code/marketplace/integrations/{IntegrationViewId}/token-mappings` | `project` |
Expand Down Expand Up @@ -686,6 +687,29 @@ const result = await norbix.hub.code.testMarketplaceIntegration({

[↑ Top](#endpoints)

### getMarketplaceIntegrationTools

`GET` `/{version}/code/marketplace/integrations/{IntegrationViewId}/tools`

Fetch a single item by ID.

**Request DTO**: `CodeMashHub2.GetMarketplaceIntegrationTools`
**Response**: `CodeMashHub2.GetMarketplaceIntegrationToolsResponse`

```ts
import { Norbix } from '@norbix.ai/ts';

const norbix = new Norbix();

const result = await norbix.hub.code.getMarketplaceIntegrationTools({
IntegrationViewId: 'IntegrationViewId-here',
// Other fields: see CodeMash type for the full request shape.
});
// → typed as CodeMashHub2.GetMarketplaceIntegrationToolsResponse
```

[↑ Top](#endpoints)

### replaceMarketplaceIntegrationSecrets

`PUT` `/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets`
Expand Down
19 changes: 19 additions & 0 deletions src/hub/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,25 @@ export class CodeModule {
});
};

/**
* GET /{version}/code/marketplace/integrations/{IntegrationViewId}/tools
* Request DTO: GetMarketplaceIntegrationTools
*/
getMarketplaceIntegrationTools = (
request: Partial<CodeMashHub2.GetMarketplaceIntegrationTools> = {} as Partial<CodeMashHub2.GetMarketplaceIntegrationTools>,
options: RequestOverrideOptions = {},
): Promise<CodeMashHub2.GetMarketplaceIntegrationToolsResponse> => {
return this.transport.send<CodeMashHub2.GetMarketplaceIntegrationToolsResponse>({
target: 'hub',
path: '/{version}/code/marketplace/integrations/{IntegrationViewId}/tools',
method: 'GET',
request,
pathParams: ['IntegrationViewId'],
scope: 'project',
...options,
});
};

/**
* PUT /{version}/code/marketplace/integrations/{IntegrationViewId}/secrets
* Request DTO: ReplaceMarketplaceIntegrationSecretsRequest
Expand Down
4 changes: 4 additions & 0 deletions src/types/hub2.contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,10 @@
"requiresAuth": true,
"returnsBytes": false
},
"GetMarketplaceIntegrationTools": {
"requiresAuth": true,
"returnsBytes": false
},
"GetMarketplaceIntegrations": {
"requiresAuth": true,
"returnsBytes": false
Expand Down
63 changes: 62 additions & 1 deletion src/types/hub2.dtos.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
/* Options:
Date: 2026-10-13 06:06:10
Date: 2026-10-13 09:00:52
Version: 10.20
Tip: To override a DTO option, remove "//" prefix before updating
BaseUrl: http://localhost:5001
Expand Down Expand Up @@ -9430,6 +9430,31 @@ export module CodeMashHub2 {
}
}

// @DataContract
export class MarketplaceMcpToolDto {
// @DataMember
public name: string;

// @DataMember
public title?: string;

// @DataMember
public description?: string;

// @DataMember
public inputSchema: string;

// @DataMember
public readOnlyHint?: boolean;

// @DataMember
public destructiveHint?: boolean;

public constructor(init?: Partial<MarketplaceMcpToolDto>) {
(Object as any).assign(this, init);
}
}

// @DataContract
export class MarketplaceFunctionProjection implements IHasViewId {
// @DataMember
Expand Down Expand Up @@ -12721,6 +12746,18 @@ export module CodeMashHub2 {
}
}

export class GetMarketplaceIntegrationToolsResponse extends ResponseBase {
public tools: IReadOnlyList<MarketplaceMcpToolDto>;
public listedAt?: string;
public catalogHash?: string;
public truncated: boolean;

public constructor(init?: Partial<GetMarketplaceIntegrationToolsResponse>) {
super(init);
(Object as any).assign(this, init);
}
}

export class EmptyMarketplaceSecretsResponse extends ResponseBase {
public constructor(init?: Partial<EmptyMarketplaceSecretsResponse>) {
super(init);
Expand Down Expand Up @@ -23615,6 +23652,30 @@ export module CodeMashHub2 {
}
}

// @Route("/{version}/code/marketplace/integrations/{IntegrationViewId}/tools", "GET")
export class GetMarketplaceIntegrationTools
extends CodeMashRequestBase
implements IReturn<GetMarketplaceIntegrationToolsResponse>
{
/** @description Integration view id, from get_marketplace_integrations. */
// @ApiMember(Description="Integration view id, from get_marketplace_integrations.", IsRequired=true)
public integrationViewId: string;

public constructor(init?: Partial<GetMarketplaceIntegrationTools>) {
super(init);
(Object as any).assign(this, init);
}
public getTypeName() {
return 'GetMarketplaceIntegrationTools';
}
public getMethod() {
return 'GET';
}
public createResponse() {
return new GetMarketplaceIntegrationToolsResponse();
}
}

// @Route("/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets", "PUT")
// @DataContract
export class ReplaceMarketplaceIntegrationSecretsRequest
Expand Down
26 changes: 26 additions & 0 deletions tests/hub/code.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe('hub.code', () => {
expect(typeof ns['invokeMarketplaceFunction']).toBe('function');
expect(typeof ns['getMarketplaceListing']).toBe('function');
expect(typeof ns['testMarketplaceIntegration']).toBe('function');
expect(typeof ns['getMarketplaceIntegrationTools']).toBe('function');
expect(typeof ns['replaceMarketplaceIntegrationSecrets']).toBe('function');
expect(typeof ns['revealMarketplaceIntegrationSecrets']).toBe('function');
expect(typeof ns['setMarketplaceIntegrationTokenMappings']).toBe('function');
Expand Down Expand Up @@ -737,6 +738,31 @@ describe('hub.code', () => {
expect(mock.lastCall?.headers.get('norbix-project-id')).toBe('test-project');
});

it('getMarketplaceIntegrationTools: GET /{version}/code/marketplace/integrations/{IntegrationViewId}/tools', async () => {
const stub = stubRequestForPath(
'/{version}/code/marketplace/integrations/{IntegrationViewId}/tools',
);
const expected = expectedUrl({
baseUrl: 'https://hub.norbix.io',
path: '/{version}/code/marketplace/integrations/{IntegrationViewId}/tools',
version: 'v2',
stub,
});
const { norbix, mock } = makeClient({});
const fn = (
norbix.hub as unknown as Record<
string,
Record<string, (a?: unknown, o?: unknown) => Promise<unknown>>
>
)['code']!['getMarketplaceIntegrationTools']!;
await fn(stub);
expect(mock.lastCall).toBeDefined();
expect(mock.lastCall?.method).toBe('GET');
expect(mock.lastCall?.url.startsWith(expected)).toBe(true);
expect(mock.lastCall?.headers.get('Authorization')).toBe('Bearer test-token');
expect(mock.lastCall?.headers.get('norbix-project-id')).toBe('test-project');
});

it('replaceMarketplaceIntegrationSecrets: PUT /{version}/code/marketplace/integrations/{IntegrationViewId}/secrets', async () => {
const stub = stubRequestForPath(
'/{version}/code/marketplace/integrations/{IntegrationViewId}/secrets',
Expand Down
50 changes: 50 additions & 0 deletions tests/hub/marketplace-mcp-tools.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, expect, it } from 'vitest';

import type { CodeMashHub2 } from '../../src/types/hub2.dtos.js';
import { createMockFetch, makeClient } from '../_helpers.js';

/**
* GET /{version}/code/marketplace/integrations/{IntegrationViewId}/tools — the
* stored tool catalog of an MCP connection for the request's env.
*
* The generated test in code.test.ts sends a stub request; this case pins that
* the connection id goes into the path (never the query or a body) and that the
* catalog comes back as the gateway sent it.
*/
describe('hub.code.getMarketplaceIntegrationTools', () => {
it('puts the connection id in the path on a GET with no body and returns the catalog', async () => {
const tool = {
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,
} as CodeMashHub2.MarketplaceMcpToolDto;
const mock = createMockFetch({
body: {
tools: [tool],
listedAt: '2026-10-13T08:00:00Z',
catalogHash: '4ce4259bec02f283',
truncated: false,
},
});
const { norbix } = makeClient({ fetch: mock.fetch });

const response = await norbix.hub.code.getMarketplaceIntegrationTools({
integrationViewId: 'int_7Hq2mcpServer',
});

const call = mock.lastCall!;
const url = new URL(call.url);
expect(call.method).toBe('GET');
expect(url.pathname).toBe('/v2/code/marketplace/integrations/int_7Hq2mcpServer/tools');
expect(url.searchParams.has('integrationViewId')).toBe(false);
expect(call.body).toBeUndefined();
expect(call.headers.get('norbix-project-id')).toBe('test-project');
expect(response.tools).toEqual([tool]);
expect(response.catalogHash).toBe('4ce4259bec02f283');
expect(response.truncated).toBe(false);
});
});
Loading