Skip to content

Commit eada429

Browse files
## Mcp-typescript SDK Changes: (#7)
* `CloudinaryAssetMgmt.assets.listVideos()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.updateResourceByAssetId()`: * `request.ResourceUpdateRequest` **Changed** (Breaking ⚠️) * `response` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.search.visualSearchAssets()`: `response.resources[].status` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.search.searchAssets()`: `response.resources[].status` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.moderations.listResourcesByModerationKindAndStatus()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.upload.upload()`: `request.upload_request` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.upload.uploadNoResourceType()`: `request` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.upload.uploadChunk()`: `request.upload_request` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.upload.destroyAsset()`: `response.result.enum(not found)` **Added** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listRawFiles()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.explicitAsset()`: * `request.RequestBody.moderation` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listImages()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.getResourceByAssetId()`: `response` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.updateResourceByPublicId()`: * `request.ResourceUpdateRequest` **Changed** (Breaking ⚠️) * `response` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.restoreResourcesByAssetIDs()`: `response.Map<restore_response>.union(info)` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listResourcesByAssetIDs()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listResourcesByContext()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listResourcesByModerationKindAndStatus()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.listResourcesByAssetFolder()`: `response.resources[]` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.assets.getResourceByPublicId()`: `response` **Changed** (Breaking ⚠️) * `CloudinaryAssetMgmt.folders.getFolderRoles()`: **Added** * `CloudinaryAssetMgmt.folders.assignFolderRoles()`: **Added** * `CloudinaryAssetMgmt.upload.text()`: `response` **Changed** * `CloudinaryAssetMgmt.people.updatePerson()`: **Added** * `CloudinaryAssetMgmt.people.getPerson()`: **Added** * `CloudinaryAssetMgmt.people.listPeople()`: **Added** Co-authored-by: speakeasybot <bot@speakeasyapi.dev>
1 parent 2f6719a commit eada429

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2261
-462
lines changed

.npmignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
!/**/*.ts
44
!/**/*.js
55
!/**/*.mjs
6-
!/**/*.json
6+
!/package.json
7+
!/jsr.json
8+
!/dist/**/*.json
9+
!/esm/**/*.json
710
!/**/*.map
811

912
/eslint.config.mjs

.speakeasy/gen.lock

Lines changed: 263 additions & 55 deletions
Large diffs are not rendered by default.

.speakeasy/gen.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ generation:
1414
securityFeb2025: true
1515
sharedErrorComponentsApr2025: true
1616
sharedNestedComponentsJan2026: false
17+
nameOverrideFeb2026: false
1718
auth:
1819
oAuth2ClientCredentialsEnabled: true
1920
oAuth2PasswordEnabled: true
@@ -30,7 +31,7 @@ generation:
3031
generateNewTests: true
3132
skipResponseBodyAssertions: false
3233
mcp-typescript:
33-
version: 0.7.0
34+
version: 0.8.0
3435
additionalDependencies:
3536
dependencies: {}
3637
devDependencies: {}

.speakeasy/workflow.lock

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
speakeasyVersion: 1.718.0
1+
speakeasyVersion: 1.755.0
22
sources:
33
CloudinaryAssetMgmt-MCP-OAS:
44
sourceNamespace: cloudinary-asset-mgmt-mcp-oas
5-
sourceRevisionDigest: sha256:54488bad4e45592eff31da0005697492192900c66cce2a8cd6cf4ec767a7c921
6-
sourceBlobDigest: sha256:f4caad987450dc6391aacfcad94c27c951ff8a84fb03db609c8a1b470d0a9e0c
5+
sourceRevisionDigest: sha256:98b76aa350b6b9401a8ed927940ad205d5c04c72b470d67c40befe1558ea6fb2
6+
sourceBlobDigest: sha256:8f3672ab7f5ca9c1539d8daab3280e6f3e6019936d01c4c2956ce628082c4314
77
tags:
88
- latest
9-
- speakeasy-sdk-regen-1771242575
10-
- 0.3.5
9+
- 0.4.0
1110
targets:
1211
cloudinary-asset-mgmt-mcp:
1312
source: CloudinaryAssetMgmt-MCP-OAS
1413
sourceNamespace: cloudinary-asset-mgmt-mcp-oas
15-
sourceRevisionDigest: sha256:54488bad4e45592eff31da0005697492192900c66cce2a8cd6cf4ec767a7c921
16-
sourceBlobDigest: sha256:f4caad987450dc6391aacfcad94c27c951ff8a84fb03db609c8a1b470d0a9e0c
14+
sourceRevisionDigest: sha256:98b76aa350b6b9401a8ed927940ad205d5c04c72b470d67c40befe1558ea6fb2
15+
sourceBlobDigest: sha256:8f3672ab7f5ca9c1539d8daab3280e6f3e6019936d01c4c2956ce628082c4314
1716
workflow:
1817
workflowVersion: 1.0.0
1918
speakeasyVersion: latest

README.md

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* [Development](#development)
1919
* [Building from Source](#building-from-source)
2020
* [Contributions](#contributions)
21+
* [Progressive Discovery](#progressive-discovery)
2122

2223
<!-- End Table of Contents [toc] -->
2324

@@ -27,9 +28,9 @@
2728
<details>
2829
<summary>Claude Desktop</summary>
2930

30-
Install the MCP server as a Desktop Extension using the pre-built [`mcp-server.mcpb`](https://github.com/cloudinary/asset-management-mcp/releases/download/v0.7.0/mcp-server.mcpb) file:
31+
Install the MCP server as a Desktop Extension using the pre-built [`mcp-server.mcpb`](https://github.com/cloudinary/asset-management-mcp/releases/download/v0.8.0/mcp-server.mcpb) file:
3132

32-
Simply drag and drop the [`mcp-server.mcpb`](https://github.com/cloudinary/asset-management-mcp/releases/download/v0.7.0/mcp-server.mcpb) file onto Claude Desktop to install the extension.
33+
Simply drag and drop the [`mcp-server.mcpb`](https://github.com/cloudinary/asset-management-mcp/releases/download/v0.8.0/mcp-server.mcpb) file onto Claude Desktop to install the extension.
3334

3435
The MCP bundle package includes the MCP server and all necessary configuration. Once installed, the server will be available without additional setup.
3536

@@ -379,4 +380,47 @@ We look forward to hearing your feedback. Feel free to open a PR or issue with a
379380

380381
### MCP Server Created by [Speakeasy](https://www.speakeasy.com/?utm_source=asset-management-mcp&utm_campaign=mcp-typescript)
381382

383+
<!-- Start Progressive Discovery [dynamic-mode] -->
384+
## Progressive Discovery
385+
386+
MCP servers with many tools can bloat LLM context windows, leading to increased token usage and tool confusion. Dynamic mode solves this by exposing only a small set of meta-tools that let agents progressively discover and invoke tools on demand.
387+
388+
To enable dynamic mode, pass the `--mode dynamic` flag when starting your server:
389+
390+
```jsonc
391+
{
392+
"mcpServers": {
393+
"CloudinaryAssetMgmt": {
394+
"command": "npx",
395+
"args": ["@cloudinary/asset-management-mcp", "start", "--mode", "dynamic"],
396+
// ... other server arguments
397+
}
398+
}
399+
}
400+
```
401+
402+
In dynamic mode, the server registers only the following meta-tools instead of every individual tool:
403+
404+
- **`list_tools`**: Lists all available tools with their names and descriptions.
405+
- **`describe_tool`**: Returns the input schema for one or more tools by name.
406+
- **`execute_tool`**: Executes a tool by name with the provided input parameters.
407+
- **`list_scopes`**: Lists the scopes available on the server.
408+
409+
This approach significantly reduces the number of tokens sent to the LLM on each request, which is especially useful for servers with a large number of tools.
410+
411+
You can combine dynamic mode with scope and tool filters:
412+
413+
```jsonc
414+
{
415+
"mcpServers": {
416+
"CloudinaryAssetMgmt": {
417+
"command": "npx",
418+
"args": ["@cloudinary/asset-management-mcp", "start", "--mode", "dynamic", "--scope", "admin"],
419+
// ... other server arguments
420+
}
421+
}
422+
}
423+
```
424+
<!-- End Progressive Discovery [dynamic-mode] -->
425+
382426
<!-- Placeholder for Future Speakeasy SDK Sections -->

RELEASES.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@ Based on:
3030
- OpenAPI Doc
3131
- Speakeasy CLI 1.718.0 (2.824.1) https://github.com/speakeasy-api/speakeasy
3232
### Generated
33-
- [mcp-typescript v0.7.0] .
33+
- [mcp-typescript v0.7.0] .
34+
35+
## 2026-03-16 00:05:40
36+
### Changes
37+
Based on:
38+
- OpenAPI Doc
39+
- Speakeasy CLI 1.755.0 (2.865.2) https://github.com/speakeasy-api/speakeasy
40+
### Generated
41+
- [mcp-typescript v0.8.0] .

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"type": "string"
7272
}
7373
},
74-
"version": "0.7.0",
74+
"version": "0.8.0",
7575
"tools": [
7676
{
7777
"name": "upload-asset",

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cloudinary/asset-management-mcp",
3-
"version": "0.7.0",
3+
"version": "0.8.0",
44
"author": "Cloudinary",
55
"type": "module",
66
"sideEffects": false,
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3+
*/
4+
5+
import { CloudinaryAssetMgmtCore } from "../core.js";
6+
import { encodeJSON, encodeSimple } from "../lib/encodings.js";
7+
import { compactMap } from "../lib/primitives.js";
8+
import { safeParse } from "../lib/schemas.js";
9+
import { RequestOptions } from "../lib/sdks.js";
10+
import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
11+
import { pathToFunc } from "../lib/url.js";
12+
import {
13+
AssignFolderRolesRequestRequest,
14+
AssignFolderRolesRequestRequest$zodSchema,
15+
} from "../models/assignfolderrolesop.js";
16+
import { AssignFolderRolesRequest } from "../models/assignfolderrolesrequest.js";
17+
import { APIError } from "../models/errors/apierror.js";
18+
import {
19+
ConnectionError,
20+
InvalidRequestError,
21+
RequestAbortedError,
22+
RequestTimeoutError,
23+
UnexpectedClientError,
24+
} from "../models/errors/httpclienterrors.js";
25+
import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
26+
import { APICall, APIPromise } from "../types/async.js";
27+
import { Result } from "../types/fp.js";
28+
29+
/**
30+
* Assign folder roles
31+
*
32+
* @remarks
33+
* Assigns or removes folder roles for a principal (user, group, or API key).
34+
* Supports all system folder roles (see [System roles reference](https://cloudinary.com/documentation/permissions_system_roles_policies#folder_roles)).
35+
* Enterprise customers can also assign custom roles by ID.
36+
* Note: Assigning roles to users or groups via this endpoint requires their user or group IDs, which are available through the Provisioning API (Enterprise only). Free customers can use this endpoint to assign roles only to API keys, but can assign folder roles to users and groups through the UI.
37+
*/
38+
export function foldersAssignFolderRoles(
39+
client$: CloudinaryAssetMgmtCore,
40+
folder_id: string,
41+
assign_folder_roles_request: AssignFolderRolesRequest,
42+
options?: RequestOptions,
43+
): APIPromise<
44+
Result<
45+
Response,
46+
| APIError
47+
| SDKValidationError
48+
| UnexpectedClientError
49+
| InvalidRequestError
50+
| RequestAbortedError
51+
| RequestTimeoutError
52+
| ConnectionError
53+
>
54+
> {
55+
return new APIPromise($do(
56+
client$,
57+
folder_id,
58+
assign_folder_roles_request,
59+
options,
60+
));
61+
}
62+
63+
async function $do(
64+
client$: CloudinaryAssetMgmtCore,
65+
folder_id: string,
66+
assign_folder_roles_request: AssignFolderRolesRequest,
67+
options?: RequestOptions,
68+
): Promise<
69+
[
70+
Result<
71+
Response,
72+
| APIError
73+
| SDKValidationError
74+
| UnexpectedClientError
75+
| InvalidRequestError
76+
| RequestAbortedError
77+
| RequestTimeoutError
78+
| ConnectionError
79+
>,
80+
APICall,
81+
]
82+
> {
83+
const input$: AssignFolderRolesRequestRequest = {
84+
folder_id: folder_id,
85+
assign_folder_roles_request: assign_folder_roles_request,
86+
};
87+
88+
const parsed$ = safeParse(
89+
input$,
90+
(value$) => AssignFolderRolesRequestRequest$zodSchema.parse(value$),
91+
"Input validation failed",
92+
);
93+
if (!parsed$.ok) {
94+
return [parsed$, { status: "invalid" }];
95+
}
96+
const payload$ = parsed$.value;
97+
const body$ = encodeJSON("body", payload$.assign_folder_roles_request, {
98+
explode: true,
99+
});
100+
101+
const pathParams$ = {
102+
cloud_name: encodeSimple("cloud_name", client$._options.cloud_name, {
103+
explode: false,
104+
charEncoding: "percent",
105+
}),
106+
folder_id: encodeSimple("folder_id", payload$.folder_id, {
107+
explode: false,
108+
charEncoding: "percent",
109+
}),
110+
};
111+
const path$ = pathToFunc(
112+
"/v1_1/{cloud_name}/folder_operations/invite/{folder_id}",
113+
)(
114+
pathParams$,
115+
);
116+
117+
const headers$ = new Headers(compactMap({
118+
"Content-Type": "application/json",
119+
Accept: "application/json",
120+
}));
121+
const securityInput = await extractSecurity(client$._options.security);
122+
const requestSecurity = resolveGlobalSecurity(securityInput);
123+
124+
const context = {
125+
options: client$._options,
126+
baseURL: options?.serverURL ?? client$._baseURL ?? "",
127+
operationID: "assignFolderRoles",
128+
oAuth2Scopes: null,
129+
resolvedSecurity: requestSecurity,
130+
securitySource: client$._options.security,
131+
retryConfig: options?.retries
132+
|| client$._options.retryConfig
133+
|| { strategy: "none" },
134+
retryCodes: options?.retryCodes || [
135+
"429",
136+
"500",
137+
"502",
138+
"503",
139+
"504",
140+
],
141+
};
142+
143+
const requestRes = client$._createRequest(context, {
144+
security: requestSecurity,
145+
method: "POST",
146+
baseURL: options?.serverURL,
147+
path: path$,
148+
headers: headers$,
149+
body: body$,
150+
userAgent: client$._options.userAgent,
151+
timeoutMs: options?.timeoutMs || client$._options.timeoutMs
152+
|| -1,
153+
}, options);
154+
if (!requestRes.ok) {
155+
return [requestRes, { status: "invalid" }];
156+
}
157+
const req$ = requestRes.value;
158+
159+
const doResult = await client$._do(req$, {
160+
context,
161+
errorCodes: [],
162+
retryConfig: context.retryConfig,
163+
retryCodes: context.retryCodes,
164+
});
165+
if (!doResult.ok) {
166+
return [doResult, { status: "request-error", request: req$ }];
167+
}
168+
return [doResult, {
169+
status: "complete",
170+
"request": req$,
171+
response: doResult.value,
172+
}];
173+
}

0 commit comments

Comments
 (0)