@cloudinary/asset-management-mcp 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/README.md +46 -2
  2. package/bin/mcp-server.js +6852 -5586
  3. package/bin/mcp-server.js.map +30 -25
  4. package/esm/funcs/foldersAssignFolderRoles.d.ts +19 -0
  5. package/esm/funcs/foldersAssignFolderRoles.d.ts.map +1 -0
  6. package/esm/funcs/foldersAssignFolderRoles.js +101 -0
  7. package/esm/funcs/foldersAssignFolderRoles.js.map +1 -0
  8. package/esm/funcs/foldersGetFolderRoles.d.ts +15 -0
  9. package/esm/funcs/foldersGetFolderRoles.d.ts.map +1 -0
  10. package/esm/funcs/foldersGetFolderRoles.js +99 -0
  11. package/esm/funcs/foldersGetFolderRoles.js.map +1 -0
  12. package/esm/funcs/peopleGetPerson.d.ts +16 -0
  13. package/esm/funcs/peopleGetPerson.d.ts.map +1 -0
  14. package/esm/funcs/peopleGetPerson.js +95 -0
  15. package/esm/funcs/peopleGetPerson.js.map +1 -0
  16. package/esm/funcs/peopleListPeople.d.ts +19 -0
  17. package/esm/funcs/peopleListPeople.d.ts.map +1 -0
  18. package/esm/funcs/peopleListPeople.js +107 -0
  19. package/esm/funcs/peopleListPeople.js.map +1 -0
  20. package/esm/funcs/peopleUpdatePerson.d.ts +18 -0
  21. package/esm/funcs/peopleUpdatePerson.d.ts.map +1 -0
  22. package/esm/funcs/peopleUpdatePerson.js +98 -0
  23. package/esm/funcs/peopleUpdatePerson.js.map +1 -0
  24. package/esm/funcs/videoAnalyticsGetVideoViews.d.ts +2 -2
  25. package/esm/funcs/videoAnalyticsGetVideoViews.d.ts.map +1 -1
  26. package/esm/funcs/videoAnalyticsGetVideoViews.js.map +1 -1
  27. package/esm/landing-page.js +1 -1
  28. package/esm/lib/config.d.ts +4 -4
  29. package/esm/lib/config.js +4 -4
  30. package/esm/lib/security.d.ts.map +1 -1
  31. package/esm/lib/security.js.map +1 -1
  32. package/esm/mcp-server/cli/serve/command.d.ts +2 -0
  33. package/esm/mcp-server/cli/serve/command.d.ts.map +1 -0
  34. package/esm/mcp-server/cli/serve/command.js +140 -0
  35. package/esm/mcp-server/cli/serve/command.js.map +1 -0
  36. package/esm/mcp-server/cli/serve/impl.d.ts +12 -0
  37. package/esm/mcp-server/cli/serve/impl.d.ts.map +1 -0
  38. package/esm/mcp-server/cli/serve/impl.js +85 -0
  39. package/esm/mcp-server/cli/serve/impl.js.map +1 -0
  40. package/esm/mcp-server/mcp-server.d.ts.map +1 -1
  41. package/esm/mcp-server/mcp-server.js +3 -1
  42. package/esm/mcp-server/mcp-server.js.map +1 -1
  43. package/esm/mcp-server/server.js +1 -1
  44. package/esm/mcp-server/tools.d.ts +4 -0
  45. package/esm/mcp-server/tools.d.ts.map +1 -1
  46. package/esm/mcp-server/tools.js +40 -0
  47. package/esm/mcp-server/tools.js.map +1 -1
  48. package/esm/models/assignfolderrolesop.d.ts +16 -0
  49. package/esm/models/assignfolderrolesop.d.ts.map +1 -0
  50. package/esm/models/assignfolderrolesop.js +20 -0
  51. package/esm/models/assignfolderrolesop.js.map +1 -0
  52. package/esm/models/assignfolderrolesrequest.d.ts +33 -0
  53. package/esm/models/assignfolderrolesrequest.d.ts.map +1 -0
  54. package/esm/models/assignfolderrolesrequest.js +26 -0
  55. package/esm/models/assignfolderrolesrequest.js.map +1 -0
  56. package/esm/models/destroyassetop.d.ts +5 -3
  57. package/esm/models/destroyassetop.d.ts.map +1 -1
  58. package/esm/models/destroyassetop.js +5 -3
  59. package/esm/models/destroyassetop.js.map +1 -1
  60. package/esm/models/explicitassetop.d.ts +1 -67
  61. package/esm/models/explicitassetop.d.ts.map +1 -1
  62. package/esm/models/explicitassetop.js +1 -44
  63. package/esm/models/explicitassetop.js.map +1 -1
  64. package/esm/models/folderrole.d.ts +9 -0
  65. package/esm/models/folderrole.d.ts.map +1 -0
  66. package/esm/models/folderrole.js +11 -0
  67. package/esm/models/folderrole.js.map +1 -0
  68. package/esm/models/folderroleassignment.d.ts +11 -0
  69. package/esm/models/folderroleassignment.d.ts.map +1 -0
  70. package/esm/models/folderroleassignment.js +14 -0
  71. package/esm/models/folderroleassignment.js.map +1 -0
  72. package/esm/models/folderrolesresponse.d.ts +9 -0
  73. package/esm/models/folderrolesresponse.d.ts.map +1 -0
  74. package/esm/models/folderrolesresponse.js +12 -0
  75. package/esm/models/folderrolesresponse.js.map +1 -0
  76. package/esm/models/getfolderrolesop.d.ts +15 -0
  77. package/esm/models/getfolderrolesop.d.ts.map +1 -0
  78. package/esm/models/getfolderrolesop.js +18 -0
  79. package/esm/models/getfolderrolesop.js.map +1 -0
  80. package/esm/models/getpersonop.d.ts +21 -0
  81. package/esm/models/getpersonop.d.ts.map +1 -0
  82. package/esm/models/getpersonop.js +21 -0
  83. package/esm/models/getpersonop.js.map +1 -0
  84. package/esm/models/getvideoviewsop.d.ts +4 -4
  85. package/esm/models/getvideoviewsop.d.ts.map +1 -1
  86. package/esm/models/getvideoviewsop.js +3 -3
  87. package/esm/models/getvideoviewsop.js.map +1 -1
  88. package/esm/models/info.d.ts +25 -12
  89. package/esm/models/info.d.ts.map +1 -1
  90. package/esm/models/info.js +26 -8
  91. package/esm/models/info.js.map +1 -1
  92. package/esm/models/listpeopleop.d.ts +69 -0
  93. package/esm/models/listpeopleop.d.ts.map +1 -0
  94. package/esm/models/listpeopleop.js +60 -0
  95. package/esm/models/listpeopleop.js.map +1 -0
  96. package/esm/models/listresourcesbymoderationkindandstatusop.d.ts +1 -1
  97. package/esm/models/parametersdirection.d.ts +18 -0
  98. package/esm/models/parametersdirection.d.ts.map +1 -0
  99. package/esm/models/parametersdirection.js +16 -0
  100. package/esm/models/parametersdirection.js.map +1 -0
  101. package/esm/models/permittedrole.d.ts +8 -0
  102. package/esm/models/permittedrole.d.ts.map +1 -0
  103. package/esm/models/permittedrole.js +10 -0
  104. package/esm/models/permittedrole.js.map +1 -0
  105. package/esm/models/persondetails.d.ts +16 -0
  106. package/esm/models/persondetails.d.ts.map +1 -0
  107. package/esm/models/persondetails.js +15 -0
  108. package/esm/models/persondetails.js.map +1 -0
  109. package/esm/models/personstatus.d.ts +18 -0
  110. package/esm/models/personstatus.d.ts.map +1 -0
  111. package/esm/models/personstatus.js +16 -0
  112. package/esm/models/personstatus.js.map +1 -0
  113. package/esm/models/principaltype.d.ts +20 -0
  114. package/esm/models/principaltype.d.ts.map +1 -0
  115. package/esm/models/principaltype.js +18 -0
  116. package/esm/models/principaltype.js.map +1 -0
  117. package/esm/models/resourceupdaterequest.d.ts +4 -68
  118. package/esm/models/resourceupdaterequest.d.ts.map +1 -1
  119. package/esm/models/resourceupdaterequest.js +4 -53
  120. package/esm/models/resourceupdaterequest.js.map +1 -1
  121. package/esm/models/searchparameters.d.ts +1 -1
  122. package/esm/models/searchresponse.d.ts +4 -0
  123. package/esm/models/searchresponse.d.ts.map +1 -1
  124. package/esm/models/searchresponse.js +4 -0
  125. package/esm/models/searchresponse.js.map +1 -1
  126. package/esm/models/successresponse.d.ts +6 -0
  127. package/esm/models/successresponse.d.ts.map +1 -0
  128. package/esm/models/successresponse.js +8 -0
  129. package/esm/models/successresponse.js.map +1 -0
  130. package/esm/models/textop.d.ts +15 -15
  131. package/esm/models/textop.d.ts.map +1 -1
  132. package/esm/models/textop.js +15 -15
  133. package/esm/models/textop.js.map +1 -1
  134. package/esm/models/thumbnail.d.ts +15 -0
  135. package/esm/models/thumbnail.d.ts.map +1 -0
  136. package/esm/models/thumbnail.js +14 -0
  137. package/esm/models/thumbnail.js.map +1 -0
  138. package/esm/models/updatepersonop.d.ts +30 -0
  139. package/esm/models/updatepersonop.d.ts.map +1 -0
  140. package/esm/models/updatepersonop.js +31 -0
  141. package/esm/models/updatepersonop.js.map +1 -0
  142. package/esm/models/uploadrequest.d.ts +4 -136
  143. package/esm/models/uploadrequest.d.ts.map +1 -1
  144. package/esm/models/uploadrequest.js +4 -96
  145. package/esm/models/uploadrequest.js.map +1 -1
  146. package/package.json +1 -1
  147. package/src/funcs/foldersAssignFolderRoles.ts +173 -0
  148. package/src/funcs/foldersGetFolderRoles.ts +170 -0
  149. package/src/funcs/peopleGetPerson.ts +161 -0
  150. package/src/funcs/peopleListPeople.ts +195 -0
  151. package/src/funcs/peopleUpdatePerson.ts +168 -0
  152. package/src/funcs/videoAnalyticsGetVideoViews.ts +3 -3
  153. package/src/landing-page.ts +1 -1
  154. package/src/lib/config.ts +4 -4
  155. package/src/lib/security.ts +4 -1
  156. package/src/mcp-server/cli/serve/command.ts +147 -0
  157. package/src/mcp-server/cli/serve/impl.ts +114 -0
  158. package/src/mcp-server/mcp-server.ts +3 -1
  159. package/src/mcp-server/server.ts +1 -1
  160. package/src/mcp-server/tools.ts +89 -0
  161. package/src/models/assignfolderrolesop.ts +46 -0
  162. package/src/models/assignfolderrolesrequest.ts +52 -0
  163. package/src/models/destroyassetop.ts +7 -5
  164. package/src/models/explicitassetop.ts +2 -74
  165. package/src/models/folderrole.ts +19 -0
  166. package/src/models/folderroleassignment.ts +22 -0
  167. package/src/models/folderrolesresponse.ts +21 -0
  168. package/src/models/getfolderrolesop.ts +43 -0
  169. package/src/models/getpersonop.ts +43 -0
  170. package/src/models/getvideoviewsop.ts +5 -5
  171. package/src/models/info.ts +53 -17
  172. package/src/models/listpeopleop.ts +114 -0
  173. package/src/models/parametersdirection.ts +23 -0
  174. package/src/models/permittedrole.ts +13 -0
  175. package/src/models/persondetails.ts +28 -0
  176. package/src/models/personstatus.ts +23 -0
  177. package/src/models/principaltype.ts +25 -0
  178. package/src/models/resourceupdaterequest.ts +8 -87
  179. package/src/models/searchresponse.ts +4 -0
  180. package/src/models/successresponse.ts +11 -0
  181. package/src/models/textop.ts +30 -30
  182. package/src/models/thumbnail.ts +28 -0
  183. package/src/models/updatepersonop.ts +66 -0
  184. package/src/models/uploadrequest.ts +8 -162
  185. package/_speakeasy/.github/action-inputs-config.json +0 -53
  186. package/_speakeasy/.github/action-security-config.json +0 -88
  187. package/manifest.json +0 -169
  188. package/tsconfig.json +0 -35
@@ -21,7 +21,7 @@ import { SDKValidationError } from "../models/errors/sdkvalidationerror.js";
21
21
  import {
22
22
  GetVideoViewsRequest,
23
23
  GetVideoViewsRequest$zodSchema,
24
- SortBy,
24
+ GetVideoViewsSortBy,
25
25
  } from "../models/getvideoviewsop.js";
26
26
  import { APICall, APIPromise } from "../types/async.js";
27
27
  import { Result } from "../types/fp.js";
@@ -37,7 +37,7 @@ export function videoAnalyticsGetVideoViews(
37
37
  client$: CloudinaryAssetMgmtCore,
38
38
  expression?: string | undefined,
39
39
  max_results?: number | undefined,
40
- sort_by?: SortBy | undefined,
40
+ sort_by?: GetVideoViewsSortBy | undefined,
41
41
  next_cursor?: string | undefined,
42
42
  options?: RequestOptions,
43
43
  ): APIPromise<
@@ -66,7 +66,7 @@ async function $do(
66
66
  client$: CloudinaryAssetMgmtCore,
67
67
  expression?: string | undefined,
68
68
  max_results?: number | undefined,
69
- sort_by?: SortBy | undefined,
69
+ sort_by?: GetVideoViewsSortBy | undefined,
70
70
  next_cursor?: string | undefined,
71
71
  options?: RequestOptions,
72
72
  ): Promise<
@@ -932,7 +932,7 @@ http_headers = { "api-key" = "YOUR_API_KEY", "api-secret" = "YOUR_API_SECRET", "
932
932
  <h1>Instructions</h1>
933
933
  <p>One-click installation for Claude Desktop users</p>
934
934
  <div class="instruction-item">
935
- <a href="https://github.com/cloudinary/asset-management-mcp/releases/download/v0.7.0/mcp-server.mcpb" download="mcp-server.mcpb" class="action-button header-action" style="display: inline-flex; margin-bottom: 16px;">
935
+ <a href="https://github.com/cloudinary/asset-management-mcp/releases/download/v0.8.0/mcp-server.mcpb" download="mcp-server.mcpb" class="action-button header-action" style="display: inline-flex; margin-bottom: 16px;">
936
936
  📥 Download MCP Bundle
937
937
  </a>
938
938
  </div>
package/src/lib/config.ts CHANGED
@@ -111,9 +111,9 @@ export function serverURLFromOptions(options: SDKOptions): URL | null {
111
111
 
112
112
  export const SDK_METADATA = {
113
113
  language: "typescript",
114
- openapiDocVersion: "0.3.5",
115
- sdkVersion: "0.7.0",
116
- genVersion: "2.824.1",
114
+ openapiDocVersion: "0.4.0",
115
+ sdkVersion: "0.8.0",
116
+ genVersion: "2.865.2",
117
117
  userAgent:
118
- "speakeasy-sdk/mcp-typescript 0.7.0 2.824.1 0.3.5 @cloudinary/asset-management-mcp",
118
+ "speakeasy-sdk/mcp-typescript 0.8.0 2.865.2 0.4.0 @cloudinary/asset-management-mcp",
119
119
  } as const;
@@ -84,7 +84,10 @@ type SecurityInputOAuth2 = {
84
84
  type SecurityInputOAuth2ClientCredentials = {
85
85
  type: "oauth2:client_credentials";
86
86
  value:
87
- | { clientID?: string | undefined; clientSecret?: string | undefined }
87
+ | {
88
+ clientID?: string | undefined;
89
+ clientSecret?: string | undefined;
90
+ }
88
91
  | null
89
92
  | string
90
93
  | undefined;
@@ -0,0 +1,147 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import { buildCommand } from "@stricli/core";
6
+ import { numberParser } from "@stricli/core";
7
+ import * as z from "zod";
8
+ import { ServerRegion } from "../../../lib/config.js";
9
+ import { consoleLoggerLevels } from "../../console-logger.js";
10
+ import { mcpScopes } from "../../scopes.js";
11
+
12
+ export const serveCommand = buildCommand({
13
+ loader: async () => {
14
+ const { main } = await import("./impl.js");
15
+ return main;
16
+ },
17
+ parameters: {
18
+ flags: {
19
+ port: {
20
+ kind: "parsed",
21
+ brief: "The port to listen on for Streamable HTTP connections",
22
+ default: "2718",
23
+ parse: (val: string) =>
24
+ z.coerce.number().int().gte(0).lt(65536).parse(val),
25
+ },
26
+ "disable-static-auth": {
27
+ kind: "boolean",
28
+ brief:
29
+ "Disable static authentication, allowing credentials to be passed via request headers only",
30
+ default: false,
31
+ },
32
+ tool: {
33
+ kind: "parsed",
34
+ brief: "Specify tools to mount on the server",
35
+ optional: true,
36
+ variadic: true,
37
+ parse: (value) => {
38
+ return z.string().parse(value);
39
+ },
40
+ },
41
+ mode: {
42
+ kind: "enum",
43
+ brief:
44
+ "Server mode (dynamic: expose list_tools, describe_tool, and execute_tool instead of individual tools)",
45
+ values: ["dynamic"],
46
+ optional: true,
47
+ },
48
+ scope: {
49
+ kind: "enum",
50
+ brief: "Mount tools/resources that match given scope (repeatable flag)",
51
+ values: mcpScopes,
52
+ variadic: true,
53
+ optional: true,
54
+ },
55
+ "api-key": {
56
+ kind: "parsed",
57
+ brief: "Sets the api_key auth field for the API",
58
+ optional: true,
59
+ parse: (value) => {
60
+ return z.string().parse(value);
61
+ },
62
+ },
63
+ "api-secret": {
64
+ kind: "parsed",
65
+ brief: "Sets the api_secret auth field for the API",
66
+ optional: true,
67
+ parse: (value) => {
68
+ return z.string().parse(value);
69
+ },
70
+ },
71
+ oauth2: {
72
+ kind: "parsed",
73
+ brief: "Sets the oauth2 auth field for the API",
74
+ optional: true,
75
+ parse: (value) => {
76
+ return z.string().parse(value);
77
+ },
78
+ },
79
+ "cloud-name": {
80
+ kind: "parsed",
81
+ brief:
82
+ "Allows setting the cloud_name parameter for all supported operations",
83
+ optional: true,
84
+ parse: (value) => {
85
+ return z.string().parse(value);
86
+ },
87
+ },
88
+ "server-url": {
89
+ kind: "parsed",
90
+ brief: "Overrides the default server URL used by the SDK",
91
+ optional: true,
92
+ parse: (value) => new URL(value).toString(),
93
+ },
94
+ "server-index": {
95
+ kind: "parsed",
96
+ brief: "Selects a predefined server used by the SDK",
97
+ optional: true,
98
+ parse: numberParser,
99
+ },
100
+ region: {
101
+ kind: "enum",
102
+ brief: "Sets the region variable for url substitution",
103
+ optional: true,
104
+ values: Object.values(ServerRegion) as Array<ServerRegion>,
105
+ },
106
+ "api-host": {
107
+ kind: "parsed",
108
+ brief: "Sets the host variable for url substitution",
109
+ optional: true,
110
+ parse: (value) => value,
111
+ },
112
+ "log-level": {
113
+ kind: "enum",
114
+ brief: "The log level to use for the server",
115
+ default: "info",
116
+ values: consoleLoggerLevels,
117
+ },
118
+ env: {
119
+ kind: "parsed",
120
+ brief: "Environment variables made available to the server",
121
+ optional: true,
122
+ variadic: true,
123
+ parse: (val: string) => {
124
+ const sepIdx = val.indexOf("=");
125
+ if (sepIdx === -1) {
126
+ throw new Error("Invalid environment variable format");
127
+ }
128
+
129
+ const key = val.slice(0, sepIdx);
130
+ const value = val.slice(sepIdx + 1);
131
+
132
+ return [
133
+ z.string().nonempty({
134
+ message: "Environment variable key must be a non-empty string",
135
+ }).parse(key),
136
+ z.string().nonempty({
137
+ message: "Environment variable value must be a non-empty string",
138
+ }).parse(value),
139
+ ] satisfies [string, string];
140
+ },
141
+ },
142
+ },
143
+ },
144
+ docs: {
145
+ brief: "Run the MCP server with Streamable HTTP transport",
146
+ },
147
+ });
@@ -0,0 +1,114 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
6
+ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
7
+ import express from "express";
8
+ import { LocalContext } from "../../cli.js";
9
+ import {
10
+ ConsoleLoggerLevel,
11
+ createConsoleLogger,
12
+ } from "../../console-logger.js";
13
+ import { MCPServerFlags } from "../../flags.js";
14
+ import { createMCPServer } from "../../server.js";
15
+ import { buildSDK } from "../../tools.js";
16
+
17
+ import { landingPageExpress } from "../../../landing-page.js";
18
+
19
+ interface ServeCommandFlags extends MCPServerFlags {
20
+ readonly port: number;
21
+ readonly "disable-static-auth": boolean;
22
+ readonly "log-level": ConsoleLoggerLevel;
23
+ readonly env?: [string, string][];
24
+ }
25
+
26
+ export async function main(this: LocalContext, flags: ServeCommandFlags) {
27
+ flags.env?.forEach(([key, value]) => {
28
+ process.env[key] = value;
29
+ });
30
+
31
+ await startStreamableHTTP(flags);
32
+ }
33
+
34
+ async function startStreamableHTTP(cliFlags: ServeCommandFlags) {
35
+ const logger = createConsoleLogger(cliFlags["log-level"]);
36
+ const app = express();
37
+
38
+ // Enable CORS for cross-origin requests
39
+ app.use((req, res, next) => {
40
+ res.header("Access-Control-Allow-Origin", "*");
41
+ res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
42
+ res.header("Access-Control-Allow-Headers", "Content-Type, *");
43
+ if (req.method === "OPTIONS") {
44
+ res.sendStatus(204);
45
+ return;
46
+ }
47
+ next();
48
+ });
49
+
50
+ app.use(express.json());
51
+
52
+ app.post("/mcp", async (req, res) => {
53
+ const headers = new Headers();
54
+ for (const [key, value] of Object.entries(req.headers)) {
55
+ if (Array.isArray(value)) {
56
+ for (const v of value) headers.append(key, v);
57
+ } else if (value !== undefined) {
58
+ headers.set(key, value);
59
+ }
60
+ }
61
+
62
+ const transport = new StreamableHTTPServerTransport({});
63
+
64
+ const { server: mcpServer } = createMCPServer({
65
+ logger,
66
+ allowedTools: cliFlags.tool,
67
+ dynamic: cliFlags.mode === "dynamic",
68
+ scopes: cliFlags.scope,
69
+ serverURL: cliFlags["server-url"],
70
+ getSDK: () =>
71
+ buildSDK(headers, cliFlags, cliFlags["disable-static-auth"], logger),
72
+ cloud_name: cliFlags["cloud-name"],
73
+ serverIdx: cliFlags["server-index"],
74
+ region: cliFlags.region,
75
+ host: cliFlags["api-host"],
76
+ });
77
+
78
+ mcpServer.server.onerror = (error) => {
79
+ logger.error("MCP protocol error", {
80
+ error: error instanceof Error ? error.message : String(error),
81
+ stack: error instanceof Error ? error.stack : undefined,
82
+ });
83
+ };
84
+
85
+ await mcpServer.connect(transport as Transport);
86
+ await transport.handleRequest(req, res, req.body);
87
+ });
88
+
89
+ app.get("/", landingPageExpress);
90
+
91
+ const httpServer = app.listen(cliFlags.port, "0.0.0.0", () => {
92
+ const ha = httpServer.address();
93
+ const host = typeof ha === "string" ? ha : `${ha?.address}:${ha?.port}`;
94
+ logger.info("MCP Streamable HTTP server started", { host });
95
+ });
96
+
97
+ const shutdown = () => {
98
+ logger.info("Shutting down HTTP server");
99
+
100
+ const timer = setTimeout(() => {
101
+ logger.info("Forcing shutdown");
102
+ process.exit(1);
103
+ }, 5000);
104
+
105
+ httpServer.close(() => {
106
+ clearTimeout(timer);
107
+ logger.info("Graceful shutdown complete");
108
+ process.exit(0);
109
+ });
110
+ };
111
+
112
+ process.on("SIGTERM", shutdown);
113
+ process.on("SIGINT", shutdown);
114
+ }
@@ -5,11 +5,13 @@
5
5
  import { buildApplication, buildRouteMap, run } from "@stricli/core";
6
6
  import process from "node:process";
7
7
  import { buildContext } from "./cli.js";
8
+ import { serveCommand } from "./cli/serve/command.js";
8
9
  import { startCommand } from "./cli/start/command.js";
9
10
 
10
11
  const routes = buildRouteMap({
11
12
  routes: {
12
13
  start: startCommand,
14
+ serve: serveCommand,
13
15
  },
14
16
  docs: {
15
17
  brief: "MCP server CLI",
@@ -19,7 +21,7 @@ const routes = buildRouteMap({
19
21
  export const app = buildApplication(routes, {
20
22
  name: "mcp",
21
23
  versionInfo: {
22
- currentVersion: "0.7.0",
24
+ currentVersion: "0.8.0",
23
25
  },
24
26
  });
25
27
 
@@ -52,7 +52,7 @@ export function createMCPServer(deps: {
52
52
  }) {
53
53
  const server = new McpServer({
54
54
  name: "CloudinaryAssetMgmt",
55
- version: "0.7.0",
55
+ version: "0.8.0",
56
56
  });
57
57
 
58
58
  const getClient = deps.getSDK || (() =>
@@ -15,7 +15,9 @@ import {
15
15
  } from "@modelcontextprotocol/sdk/types.js";
16
16
  import * as z from "zod";
17
17
  import { CloudinaryAssetMgmtCore } from "../core.js";
18
+ import { ServerRegion$zodSchema } from "../lib/config.js";
18
19
  import { ConsoleLogger } from "./console-logger.js";
20
+ import { MCPServerFlags } from "./flags.js";
19
21
  import { MCPScope, mcpScopes } from "./scopes.js";
20
22
  import { valueToBase64 } from "./shared.js";
21
23
 
@@ -376,3 +378,90 @@ export function registerDynamicTools(
376
378
  logger.debug("Registered dynamic meta-tool", { name: "list_scopes" });
377
379
  }
378
380
  }
381
+ function resolveHeader<T>(
382
+ headers: Headers,
383
+ headerName: string,
384
+ schema: z.ZodType<T>,
385
+ cliFlagValue: T | undefined,
386
+ disableStaticAuth: boolean,
387
+ ): T | undefined {
388
+ const val = headers.get(headerName);
389
+ if (val != null) {
390
+ return schema.parse(val);
391
+ }
392
+ return disableStaticAuth ? undefined : schema.parse(cliFlagValue);
393
+ }
394
+
395
+ export function buildSDK(
396
+ headers: Headers,
397
+ cliFlags: MCPServerFlags,
398
+ disableStaticAuth: boolean,
399
+ logger: { level: string },
400
+ ) {
401
+ const flags = {
402
+ ...cliFlags,
403
+ "api-key": resolveHeader(
404
+ headers,
405
+ "api-key",
406
+ z.string(),
407
+ cliFlags["api-key"],
408
+ disableStaticAuth,
409
+ ),
410
+ "api-secret": resolveHeader(
411
+ headers,
412
+ "api-secret",
413
+ z.string(),
414
+ cliFlags["api-secret"],
415
+ disableStaticAuth,
416
+ ),
417
+ "oauth2": resolveHeader(
418
+ headers,
419
+ "oauth2",
420
+ z.string(),
421
+ cliFlags["oauth2"],
422
+ disableStaticAuth,
423
+ ),
424
+ };
425
+
426
+ return new CloudinaryAssetMgmtCore({
427
+ security: {
428
+ cloudinaryAuth: flags["api-key"] != null && flags["api-secret"] != null
429
+ ? {
430
+ api_key: flags["api-key"] ?? "",
431
+ api_secret: flags["api-secret"] ?? "",
432
+ }
433
+ : void 0,
434
+ oauth2: flags.oauth2 ?? "",
435
+ },
436
+ serverURL: cliFlags["server-url"],
437
+ cloud_name: resolveHeader(
438
+ headers,
439
+ "cloud-name",
440
+ z.string(),
441
+ cliFlags["cloud-name"],
442
+ disableStaticAuth,
443
+ ),
444
+ serverIdx: cliFlags["server-index"],
445
+ region: resolveHeader(
446
+ headers,
447
+ "region",
448
+ ServerRegion$zodSchema,
449
+ cliFlags.region,
450
+ disableStaticAuth,
451
+ ),
452
+ host: resolveHeader(
453
+ headers,
454
+ "api-host",
455
+ z.string(),
456
+ cliFlags["api-host"],
457
+ disableStaticAuth,
458
+ ),
459
+ debugLogger: logger.level === "debug"
460
+ ? {
461
+ log: (...args) => console.log(...args),
462
+ group: (...args) => console.group(...args),
463
+ groupEnd: (...args) => console.groupEnd(...args),
464
+ }
465
+ : undefined,
466
+ });
467
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import * as z from "zod";
6
+ import { ApiError, ApiError$zodSchema } from "./apierror.js";
7
+ import {
8
+ AssignFolderRolesRequest,
9
+ AssignFolderRolesRequest$zodSchema,
10
+ } from "./assignfolderrolesrequest.js";
11
+ import {
12
+ SuccessResponse,
13
+ SuccessResponse$zodSchema,
14
+ } from "./successresponse.js";
15
+
16
+ export type AssignFolderRolesGlobals = { cloud_name?: string | undefined };
17
+
18
+ export const AssignFolderRolesGlobals$zodSchema: z.ZodType<
19
+ AssignFolderRolesGlobals
20
+ > = z.object({
21
+ cloud_name: z.string().describe("The cloud name of your product environment.")
22
+ .optional(),
23
+ });
24
+
25
+ export type AssignFolderRolesRequestRequest = {
26
+ folder_id: string;
27
+ assign_folder_roles_request: AssignFolderRolesRequest;
28
+ };
29
+
30
+ export const AssignFolderRolesRequestRequest$zodSchema: z.ZodType<
31
+ AssignFolderRolesRequestRequest
32
+ > = z.object({
33
+ assign_folder_roles_request: AssignFolderRolesRequest$zodSchema,
34
+ folder_id: z.string().describe(
35
+ "The immutable identifier of the folder, returned by the Get root folders and Get subfolders endpoints.",
36
+ ),
37
+ });
38
+
39
+ export type AssignFolderRolesResponse = SuccessResponse | ApiError;
40
+
41
+ export const AssignFolderRolesResponse$zodSchema: z.ZodType<
42
+ AssignFolderRolesResponse
43
+ > = z.union([
44
+ SuccessResponse$zodSchema,
45
+ ApiError$zodSchema,
46
+ ]);
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import * as z from "zod";
6
+ import { ClosedEnum } from "../types/enums.js";
7
+ import { PrincipalType, PrincipalType$zodSchema } from "./principaltype.js";
8
+
9
+ /**
10
+ * The user, group, or API key whose role assignments are being modified.
11
+ */
12
+ export type Principal = { type: PrincipalType; id: string };
13
+
14
+ export const Principal$zodSchema: z.ZodType<Principal> = z.object({
15
+ id: z.string(),
16
+ type: PrincipalType$zodSchema,
17
+ }).describe(
18
+ "The user, group, or API key whose role assignments are being modified.",
19
+ );
20
+
21
+ /**
22
+ * The operation to perform on the principal’s role assignments. `add` grants the specified roles; `remove` revokes them.
23
+ */
24
+ export const Operation = {
25
+ Add: "add",
26
+ Remove: "remove",
27
+ } as const;
28
+ /**
29
+ * The operation to perform on the principal’s role assignments. `add` grants the specified roles; `remove` revokes them.
30
+ */
31
+ export type Operation = ClosedEnum<typeof Operation>;
32
+
33
+ export const Operation$zodSchema = z.enum([
34
+ "add",
35
+ "remove",
36
+ ]).describe(
37
+ "The operation to perform on the principal’s role assignments. `add` grants the specified roles; `remove` revokes them.",
38
+ );
39
+
40
+ export type AssignFolderRolesRequest = {
41
+ principal: Principal;
42
+ operation: Operation;
43
+ roles: Array<string>;
44
+ };
45
+
46
+ export const AssignFolderRolesRequest$zodSchema: z.ZodType<
47
+ AssignFolderRolesRequest
48
+ > = z.object({
49
+ operation: Operation$zodSchema,
50
+ principal: z.lazy(() => Principal$zodSchema),
51
+ roles: z.array(z.string()),
52
+ });
@@ -32,22 +32,24 @@ export const DestroyAssetRequest$zodSchema: z.ZodType<DestroyAssetRequest> = z
32
32
  });
33
33
 
34
34
  /**
35
- * Indicates successful deletion
35
+ * Result of the deletion operation
36
36
  */
37
37
  export const DestroyAssetResult = {
38
38
  Ok: "ok",
39
+ NotFound: "not found",
39
40
  } as const;
40
41
  /**
41
- * Indicates successful deletion
42
+ * Result of the deletion operation
42
43
  */
43
44
  export type DestroyAssetResult = ClosedEnum<typeof DestroyAssetResult>;
44
45
 
45
46
  export const DestroyAssetResult$zodSchema = z.enum([
46
47
  "ok",
47
- ]).describe("Indicates successful deletion");
48
+ "not found",
49
+ ]).describe("Result of the deletion operation");
48
50
 
49
51
  /**
50
- * Asset/resource destroyed successfully
52
+ * Asset/resource destroyed successfully or not found
51
53
  */
52
54
  export type DestroyAssetResponseBody = {
53
55
  result?: DestroyAssetResult | undefined;
@@ -57,7 +59,7 @@ export const DestroyAssetResponseBody$zodSchema: z.ZodType<
57
59
  DestroyAssetResponseBody
58
60
  > = z.object({
59
61
  result: DestroyAssetResult$zodSchema.optional(),
60
- }).describe("Asset/resource destroyed successfully");
62
+ }).describe("Asset/resource destroyed successfully or not found");
61
63
 
62
64
  export type DestroyAssetResponse = ApiError | DestroyAssetResponseBody;
63
65